From f0e52da8dc9b9418c4d48873029be777e2c03686 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 31 Mar 2011 09:28:41 +0000 Subject: [PATCH] Fix alpha handling in CSS syntax in wxColour in non-"C" locale. Use locale-independent functions to parse and generate the floating point alpha representation in CSS syntax for colours to make it work in locales which don't use period as decimal separator. Closes #13077. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@67356 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/common/colourcmn.cpp | 52 +++++++++++++++++++++++++++++++++------ tests/graphics/colour.cpp | 35 ++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 7 deletions(-) diff --git a/src/common/colourcmn.cpp b/src/common/colourcmn.cpp index d2e5bc16f0..965fbdcff0 100644 --- a/src/common/colourcmn.cpp +++ b/src/common/colourcmn.cpp @@ -101,10 +101,48 @@ bool wxColourBase::FromString(const wxString& str) alpha = wxALPHA_OPAQUE; if ( str.length() > 3 && (str[3] == wxT('a') || str[3] == wxT('A')) ) { - float a; - // TODO: use locale-independent function - if ( wxSscanf(str.wx_str() + 4, wxT("( %d , %d , %d , %f )"), - &red, &green, &blue, &a) != 4 ) + // We can't use sscanf() for the alpha value as sscanf() uses the + // current locale while the floating point numbers in CSS always + // use point as decimal separator, regardless of locale. So parse + // the tail of the string manually by putting it in a buffer and + // using wxString::ToCDouble() below. Notice that we can't use "%s" + // for this as it stops at white space and we need "%c" to avoid + // this and really get all the rest of the string into the buffer. + + const unsigned len = str.length(); // always big enough + wxCharBuffer alphaBuf(len); + char * const alphaPtr = alphaBuf.data(); + + for ( unsigned n = 0; n < len; n++ ) + alphaPtr[n] = '\0'; + + // Construct the format string which ensures that the last argument + // receives all the rest of the string. + wxString formatStr; + formatStr << wxS("( %d , %d , %d , %") << len << 'c'; + + // Notice that we use sscanf() here because if the string is not + // ASCII it can't represent a valid RGB colour specification anyhow + // and like this we can be sure that %c corresponds to "char *" + // while with wxSscanf() it depends on the type of the string + // passed as first argument: if it is a wide string, then %c + // expects "wchar_t *" matching parameter under MSW for example. + if ( sscanf(str.c_str() + 4, + formatStr, + &red, &green, &blue, alphaPtr) != 4 ) + return false; + + // Notice that we must explicitly specify the length to get rid of + // trailing NULs. + wxString alphaStr(alphaPtr, wxStrlen(alphaPtr)); + if ( alphaStr.empty() || alphaStr.Last() != ')' ) + return false; + + alphaStr.RemoveLast(); + alphaStr.Trim(); + + double a; + if ( !alphaStr.ToCDouble(&a) ) return false; alpha = wxRound(a * 255); @@ -181,9 +219,9 @@ wxString wxColourBase::GetAsString(long flags) const } else // use rgba() form { - // TODO: use locale-independent function - colName.Printf(wxT("rgba(%d, %d, %d, %.3f)"), - red, green, blue, Alpha() / 255.); + colName.Printf(wxT("rgba(%d, %d, %d, %s)"), + red, green, blue, + wxString::FromCDouble(Alpha() / 255., 3)); } } else if ( flags & wxC2S_HTML_SYNTAX ) diff --git a/tests/graphics/colour.cpp b/tests/graphics/colour.cpp index dfec5fea61..eab0eef037 100644 --- a/tests/graphics/colour.cpp +++ b/tests/graphics/colour.cpp @@ -20,6 +20,23 @@ #include "wx/colour.h" #include "asserthelper.h" +// ---------------------------------------------------------------------------- +// helpers +// ---------------------------------------------------------------------------- + +// Check the colour components, with and without alpha. +// +// NB: These are macros and not functions to have correct line numbers in case +// of failure. +#define ASSERT_EQUAL_RGB(c, r, g, b) \ + CPPUNIT_ASSERT_EQUAL( r, (int)c.Red() ); \ + CPPUNIT_ASSERT_EQUAL( g, (int)c.Green() ); \ + CPPUNIT_ASSERT_EQUAL( b, (int)c.Blue() ) + +#define ASSERT_EQUAL_RGBA(c, r, g, b, a) \ + ASSERT_EQUAL_RGB(c, r, g, b); \ + CPPUNIT_ASSERT_EQUAL( a, (int)c.Alpha() ) + // ---------------------------------------------------------------------------- // test class // ---------------------------------------------------------------------------- @@ -32,9 +49,11 @@ public: private: CPPUNIT_TEST_SUITE( ColourTestCase ); CPPUNIT_TEST( GetSetRGB ); + CPPUNIT_TEST( FromString ); CPPUNIT_TEST_SUITE_END(); void GetSetRGB(); + void FromString(); DECLARE_NO_COPY_CLASS(ColourTestCase) }; @@ -78,3 +97,19 @@ void ColourTestCase::GetSetRGB() #endif // __WXX11__ } +void ColourTestCase::FromString() +{ + ASSERT_EQUAL_RGB( wxColour("rgb(11, 22, 33)"), 11, 22, 33 ); + ASSERT_EQUAL_RGBA( wxColour("rgba(11, 22, 33, 0.5)"), 11, 22, 33, 128 ); + ASSERT_EQUAL_RGBA( wxColour("rgba( 11, 22, 33, 0.5 )"), 11, 22, 33, 128 ); + + ASSERT_EQUAL_RGB( wxColour("#aabbcc"), 0xaa, 0xbb, 0xcc ); + + ASSERT_EQUAL_RGB( wxColour("red"), 0xff, 0, 0 ); + + wxColour col; + CPPUNIT_ASSERT( !wxFromString("rgb(1, 2)", &col) ); + CPPUNIT_ASSERT( !wxFromString("rgba(1, 2, 3.456)", &col) ); + CPPUNIT_ASSERT( !wxFromString("rgba(1, 2, 3.456, foo)", &col) ); +} + -- 2.47.2