diff --git a/include/wx/colour.h b/include/wx/colour.h index 9caceccaef..aa50b349ec 100644 --- a/include/wx/colour.h +++ b/include/wx/colour.h @@ -65,7 +65,7 @@ DECLARE_VARIANT_OBJECT_EXPORTED(wxColour,WXDLLIMPEXP_CORE) not need the wxGDIObject machinery to handle colors, please add it to the list of ports which do not need it. */ -#if defined( __WXMAC__ ) || defined( __WXMSW__ ) || defined( __WXQT__ ) +#if defined( __WXMSW__ ) || defined( __WXQT__ ) #define wxCOLOUR_IS_GDIOBJECT 0 #else #define wxCOLOUR_IS_GDIOBJECT 1 diff --git a/include/wx/osx/core/colour.h b/include/wx/osx/core/colour.h index ff41bcb5dd..b862332173 100644 --- a/include/wx/osx/core/colour.h +++ b/include/wx/osx/core/colour.h @@ -29,60 +29,76 @@ public: // default copy ctor and dtor are ok // accessors - virtual bool IsOk() const { return m_cgColour != NULL; } + virtual ChannelType Red() const wxOVERRIDE; + virtual ChannelType Green() const wxOVERRIDE; + virtual ChannelType Blue() const wxOVERRIDE; + virtual ChannelType Alpha() const wxOVERRIDE; - virtual WXDLLIMPEXP_INLINE_CORE ChannelType Red() const { return m_red; } - virtual WXDLLIMPEXP_INLINE_CORE ChannelType Green() const { return m_green; } - virtual WXDLLIMPEXP_INLINE_CORE ChannelType Blue() const { return m_blue; } - virtual WXDLLIMPEXP_INLINE_CORE ChannelType Alpha() const { return m_alpha; } + wxColour& operator=(const wxColour& col); // comparison bool operator == (const wxColour& colour) const; - bool operator != (const wxColour& colour) const { return !(*this == colour); } - CGColorRef GetPixel() const { return m_cgColour; } + // CoreGraphics CGColor + // -------------------- - CGColorRef GetCGColor() const { return m_cgColour; } - CGColorRef CreateCGColor() const { return wxCFRetain( (CGColorRef)m_cgColour ); } + // This ctor does take ownership of the color. + wxColour( CGColorRef col ); + + // don't take ownership of the returned value + CGColorRef GetCGColor() const; + + // do take ownership of the returned value + CGColorRef CreateCGColor() const { return wxCFRetain(GetCGColor()); } #if wxOSX_USE_COCOA_OR_CARBON + // Quickdraw RGBColor + // ------------------ + wxColour(const RGBColor& col); void GetRGBColor( RGBColor *col ) const; #endif - // Mac-specific ctor and assignment operator from the native colour - // assumes ownership of CGColorRef - wxColour( CGColorRef col ); -#if wxOSX_USE_COCOA_OR_CARBON - wxColour(const RGBColor& col); - wxColour& operator=(const RGBColor& col); -#endif #if wxOSX_USE_COCOA + // NSColor Cocoa + // ------------- + // This ctor does not take ownership of the color. explicit wxColour(WX_NSColor color); WX_NSColor OSXGetNSColor() const; #endif - wxColour& operator=(CGColorRef col); - wxColour& operator=(const wxColour& col); - + protected : virtual void - InitRGBA(ChannelType r, ChannelType g, ChannelType b, ChannelType a); -#if wxOSX_USE_COCOA_OR_CARBON - void InitRGBColor( const RGBColor& col ); -#endif - void InitCGColorRef( CGColorRef col ); + InitRGBA(ChannelType r, ChannelType g, ChannelType b, ChannelType a) wxOVERRIDE; + + virtual wxGDIRefData *CreateGDIRefData() const wxOVERRIDE; + virtual wxGDIRefData *CloneGDIRefData(const wxGDIRefData *data) const wxOVERRIDE; private: - wxCFRef m_cgColour; - - ChannelType m_red; - ChannelType m_blue; - ChannelType m_green; - ChannelType m_alpha; wxDECLARE_DYNAMIC_CLASS(wxColour); }; +class wxColourRefData : public wxGDIRefData +{ +public: + wxColourRefData() {} + virtual ~wxColourRefData() {} + + virtual CGFloat Red() const = 0; + virtual CGFloat Green() const = 0; + virtual CGFloat Blue() const = 0; + virtual CGFloat Alpha() const = 0; + + virtual CGColorRef GetCGColor() const = 0; + + virtual wxColourRefData* Clone() const = 0; + +#if wxOSX_USE_COCOA + virtual WX_NSColor GetNSColor() const; +#endif +}; + #endif // _WX_COLOUR_H_ diff --git a/src/osx/cocoa/colour.mm b/src/osx/cocoa/colour.mm index e6a4d1750a..065c9547ae 100644 --- a/src/osx/cocoa/colour.mm +++ b/src/osx/cocoa/colour.mm @@ -13,78 +13,136 @@ #include "wx/osx/private.h" -// Helper function to avoid writing too many casts in wxColour ctor. -static inline wxColour::ChannelType NSColorChannelToWX(CGFloat c) +class wxNSColorRefData : public wxColourRefData { - return static_cast(c * 255 + 0.5); +public: + wxNSColorRefData(WX_NSColor color); + + wxNSColorRefData(const wxNSColorRefData& other); + + virtual ~wxNSColorRefData(); + + virtual CGFloat Red() const wxOVERRIDE; + virtual CGFloat Green() const wxOVERRIDE; + virtual CGFloat Blue() const wxOVERRIDE; + virtual CGFloat Alpha() const wxOVERRIDE; + + CGColorRef GetCGColor() const wxOVERRIDE; + + virtual wxColourRefData* Clone() const wxOVERRIDE { return new wxNSColorRefData(*this); } + + virtual WX_NSColor GetNSColor() const wxOVERRIDE; +private: + WX_NSColor m_nsColour; + + wxDECLARE_NO_ASSIGN_CLASS(wxNSColorRefData); +}; + +wxNSColorRefData::wxNSColorRefData(WX_NSColor color) +{ + m_nsColour = [color retain]; } -wxColour::wxColour(WX_NSColor col) +wxNSColorRefData::wxNSColorRefData(const wxNSColorRefData& other) +{ + m_nsColour = [other.m_nsColour retain]; +} + +wxNSColorRefData::~wxNSColorRefData() +{ + [m_nsColour release]; +} + +WX_NSColor wxNSColorRefData::GetNSColor() const +{ + return m_nsColour; +} + +CGFloat wxNSColorRefData::Red() const +{ + if ( NSColor* colRGBA = [m_nsColour colorUsingColorSpaceName:NSCalibratedRGBColorSpace] ) + return [colRGBA redComponent]; + + return 0.0; +} + +CGFloat wxNSColorRefData::Green() const +{ + if ( NSColor* colRGBA = [m_nsColour colorUsingColorSpaceName:NSCalibratedRGBColorSpace] ) + return [colRGBA greenComponent]; + + return 0.0; +} + +CGFloat wxNSColorRefData::Blue() const +{ + if ( NSColor* colRGBA = [m_nsColour colorUsingColorSpaceName:NSCalibratedRGBColorSpace] ) + return [colRGBA blueComponent]; + + return 0.0; +} + +CGFloat wxNSColorRefData::Alpha() const +{ + if ( NSColor* colRGBA = [m_nsColour colorUsingColorSpaceName:NSCalibratedRGBColorSpace] ) + return [colRGBA alphaComponent]; + + return 0.0; +} + +CGColorRef wxNSColorRefData::GetCGColor() const { #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 - if ( wxPlatformInfo::Get().CheckOSVersion(10, 8) ) - { - CGColorRef cgcolor = [col CGColor]; - CFRetain(cgcolor); - InitCGColorRef(cgcolor); - return ; - } + if (wxPlatformInfo::Get().CheckOSVersion(10, 8)) + return [m_nsColour CGColor]; #endif - - // Simplest case is when we can directly get the RGBA components: - if ( NSColor* colRGBA = [col colorUsingColorSpaceName:NSCalibratedRGBColorSpace] ) - { - InitRGBA - ( - NSColorChannelToWX([colRGBA redComponent]), - NSColorChannelToWX([colRGBA greenComponent]), - NSColorChannelToWX([colRGBA blueComponent]), - NSColorChannelToWX([colRGBA alphaComponent]) - ); - return; - } + CGColorRef cgcolor = NULL; + // Simplest case is when we can directly get the RGBA components: + if (NSColor* colRGBA = [m_nsColour colorUsingColorSpaceName:NSCalibratedRGBColorSpace]) + { + CGFloat components[4]; + [colRGBA getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]]; + + cgcolor = CGColorCreate(wxMacGetGenericRGBColorSpace(), components); + } // Some colours use patterns, we can handle them with the help of CGColorRef - if ( NSColor* colPat = [col colorUsingColorSpaceName:NSPatternColorSpace] ) + else if (NSColor* colPat = [m_nsColour colorUsingColorSpaceName:NSPatternColorSpace]) { NSImage* const nsimage = [colPat patternImage]; - if ( nsimage ) + if (nsimage) { NSSize size = [nsimage size]; NSRect r = NSMakeRect(0, 0, size.width, size.height); CGImageRef cgimage = [nsimage CGImageForProposedRect:&r context:nil hints:nil]; - if ( cgimage ) + if (cgimage) { // Callbacks for CGPatternCreate() struct PatternCreateCallbacks { - static void Draw(void *info, CGContextRef ctx) + static void Draw(void* info, CGContextRef ctx) { - CGImageRef image = (CGImageRef) info; - CGContextDrawImage - ( + CGImageRef image = (CGImageRef)info; + CGContextDrawImage( ctx, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), - image - ); + image); } - static void Release(void * WXUNUSED(info)) + static void Release(void* WXUNUSED(info)) { // Do not release the image here, we don't own it as it // comes from NSImage. } }; - const CGPatternCallbacks callbacks = - { + const CGPatternCallbacks callbacks = { /* version: */ 0, &PatternCreateCallbacks::Draw, &PatternCreateCallbacks::Release }; - CGPatternRef pattern = CGPatternCreate - ( + CGPatternRef pattern = CGPatternCreate( cgimage, CGRectMake(0, 0, size.width, size.height), CGAffineTransformMake(1, 0, 0, 1, 0, 0), @@ -96,24 +154,32 @@ wxColour::wxColour(WX_NSColor col) ); CGColorSpaceRef space = CGColorSpaceCreatePattern(NULL); CGFloat components[1] = { 1.0 }; - CGColorRef cgcolor = CGColorCreateWithPattern(space, pattern, components); + cgcolor = CGColorCreateWithPattern(space, pattern, components); CGColorSpaceRelease(space); CGPatternRelease(pattern); - - InitCGColorRef(cgcolor); - return; } } } - // Don't assert here, this will more likely than not result in a crash as - // colours are often created in drawing code which will be called again - // when the assert dialog is shown, resulting in a recursive assertion - // failure and, hence, a crash. - NSLog(@"Failed to convert NSColor \"%@\" to wxColour.", col); + if (cgcolor == NULL) + { + // Don't assert here, this will more likely than not result in a crash as + // colours are often created in drawing code which will be called again + // when the assert dialog is shown, resulting in a recursive assertion + // failure and, hence, a crash. + NSLog(@"Failed to convert NSColor \"%@\" to CGColorRef.", m_nsColour); + } + return cgcolor; } -WX_NSColor wxColour::OSXGetNSColor() const +WX_NSColor wxColourRefData::GetNSColor() const { - return [NSColor colorWithCalibratedRed:m_red / 255.0 green:m_green / 255.0 blue:m_blue / 255.0 alpha:m_alpha / 255.0]; + return [NSColor colorWithCalibratedRed:Red() green:Green() blue:Blue() alpha:Alpha() ]; } + +wxColour::wxColour(WX_NSColor col) +{ + m_refData = new wxNSColorRefData(col); +} + + diff --git a/src/osx/core/colour.cpp b/src/osx/core/colour.cpp index 05034106cb..39dac008b1 100644 --- a/src/osx/core/colour.cpp +++ b/src/osx/core/colour.cpp @@ -18,122 +18,221 @@ #include "wx/osx/private.h" +CGColorSpaceRef wxMacGetGenericRGBColorSpace(); + +class wxCGColorRefData : public wxColourRefData +{ +public: + wxCGColorRefData(CGFloat r, CGFloat g, CGFloat b, CGFloat a = 1.0); + + wxCGColorRefData(CGFloat components[4]); + + wxCGColorRefData(CGColorRef); + + wxCGColorRefData(const wxCGColorRefData& other); + + virtual bool IsOk() const wxOVERRIDE{ return m_cgColour != NULL; } + + virtual CGFloat Red() const wxOVERRIDE { return m_red; } + virtual CGFloat Green() const wxOVERRIDE { return m_green; } + virtual CGFloat Blue() const wxOVERRIDE { return m_blue; } + virtual CGFloat Alpha() const wxOVERRIDE { return m_alpha; } + + CGColorRef GetCGColor() const wxOVERRIDE { return m_cgColour; } + + virtual wxColourRefData* Clone() const wxOVERRIDE { return new wxCGColorRefData(*this); } + +private: + void Init(CGFloat components[4]); + + wxCFRef m_cgColour; + + CGFloat m_red; + CGFloat m_blue; + CGFloat m_green; + CGFloat m_alpha; + + wxDECLARE_NO_ASSIGN_CLASS(wxCGColorRefData); +}; + +wxCGColorRefData::wxCGColorRefData(CGFloat r, CGFloat g, CGFloat b, CGFloat a) +{ + CGFloat components[4]; + components[0] = r; + components[1] = b; + components[2] = g; + components[3] = a; + + Init(components); +} + +wxCGColorRefData::wxCGColorRefData(CGFloat components[4]) +{ + Init(components); +} + +wxCGColorRefData::wxCGColorRefData(const wxCGColorRefData& other) +{ + m_red = other.m_red; + m_blue = other.m_blue; + m_green = other.m_green; + m_alpha = other.m_alpha; + + m_cgColour = other.m_cgColour; +} + +void wxCGColorRefData::Init(CGFloat components[4]) +{ + m_red = components[0]; + m_blue = components[1]; + m_green = components[2]; + m_alpha = components[3]; + + m_cgColour = CGColorCreate(wxMacGetGenericRGBColorSpace(), components); +} + +wxCGColorRefData::wxCGColorRefData(CGColorRef col) +{ + wxASSERT_MSG(col != NULL, "Invalid CoreGraphics Color"); + m_cgColour.reset(col); + + wxCFRef rgbacol; + size_t noComp = CGColorGetNumberOfComponents(col); + const CGFloat* components = CGColorGetComponents(col); + + // set default alpha + m_alpha = 1.0; + bool isRGB = true; + + CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(col)); + if (model == kCGColorSpaceModelMonochrome) + { + wxASSERT_MSG(1 <= noComp && noComp <= 2, "Monochrome Color unexpected components"); + m_red = components[0]; + m_green = components[0]; + m_blue = components[0]; + if (noComp > 1) + m_alpha = components[1]; + isRGB = false; + } + else if (model != kCGColorSpaceModelRGB) + { +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_11 + if (wxPlatformInfo::Get().CheckOSVersion(10, 11)) + { + rgbacol = CGColorCreateCopyByMatchingToColorSpace(wxMacGetGenericRGBColorSpace(), kCGRenderingIntentDefault, col, NULL); + noComp = CGColorGetNumberOfComponents(rgbacol); + components = CGColorGetComponents(rgbacol); + } + else +#endif + { + isRGB = false; + } + } + + if (isRGB) + { + wxASSERT_MSG(3 <= noComp && noComp <= 4, "RGB Color unexpected components"); + m_red = components[0]; + m_green = components[1]; + m_blue = components[2]; + + if (noComp == 4) + m_alpha = components[3]; + } +} + +#define M_COLDATA static_cast(m_refData) + #if wxOSX_USE_COCOA_OR_CARBON wxColour::wxColour(const RGBColor& col) { - InitRGBColor(col); + CGFloat components[4] = { (CGFloat)(col.red / 65535.0), (CGFloat)(col.green / 65535.0), + (CGFloat)(col.blue / 65535.0), (CGFloat)1.0 }; + m_refData = new wxCGColorRefData(components); } #endif wxColour::wxColour(CGColorRef col) { - InitCGColorRef(col); + wxASSERT_MSG(col != NULL, "Invalid CoreGraphics Color"); + + m_refData = new wxCGColorRefData(col); +} + +wxColour::ChannelType wxColour::Red() const +{ + return wxRound(M_COLDATA->Red() * 255.0); +} + +wxColour::ChannelType wxColour::Green() const +{ + return wxRound(M_COLDATA->Red() * 255.0); +} + +wxColour::ChannelType wxColour::Blue() const +{ + return wxRound(M_COLDATA->Red() * 255.0); +} + +wxColour::ChannelType wxColour::Alpha() const +{ + return wxRound(M_COLDATA->Red() * 255.0); } #if wxOSX_USE_COCOA_OR_CARBON -void wxColour::GetRGBColor( RGBColor *col ) const +void wxColour::GetRGBColor(RGBColor* col) const { - col->red = (m_red << 8) + m_red; - col->blue = (m_blue << 8) + m_blue; - col->green = (m_green << 8) + m_green; -} - -wxColour& wxColour::operator=(const RGBColor& col) -{ - InitRGBColor(col); - return *this; + col->red = M_COLDATA->Red() * 65535.0; + col->blue = M_COLDATA->Blue() * 65535.0; + col->green = M_COLDATA->Green() * 65535.0; } #endif -wxColour& wxColour::operator=(CGColorRef col) +CGColorRef wxColour::GetCGColor() const { - InitCGColorRef(col); - return *this; + return M_COLDATA->GetCGColor(); +} + +#if wxOSX_USE_COCOA +WX_NSColor wxColour::OSXGetNSColor() const +{ + return M_COLDATA->GetNSColor(); +} +#endif + +void wxColour::InitRGBA(ChannelType r, ChannelType g, ChannelType b, ChannelType a) +{ + CGFloat components[4] = { (CGFloat)(r / 255.0), (CGFloat)(g / 255.0), (CGFloat)(b / 255.0), (CGFloat)(a / 255.0) }; + m_refData = new wxCGColorRefData(components); } wxColour& wxColour::operator=(const wxColour& col) { - m_red = col.m_red; - m_green = col.m_green; - m_blue = col.m_blue; - m_alpha = col.m_alpha; - m_cgColour = col.m_cgColour; + wxObject::operator=(col); + return *this; } -void wxColour::InitRGBA (ChannelType r, ChannelType g, ChannelType b, ChannelType a) +bool wxColour::operator==(const wxColour& other) const { - m_red = r; - m_green = g; - m_blue = b; - m_alpha = a ; - - CGColorRef col = 0 ; - CGFloat components[4] = { (CGFloat)(r / 255.0), (CGFloat) (g / 255.0), (CGFloat) (b / 255.0), (CGFloat) (a / 255.0) } ; - col = CGColorCreate( wxMacGetGenericRGBColorSpace() , components ) ; - - wxASSERT_MSG(col != NULL, "Invalid CoreGraphics Color"); - m_cgColour.reset( col ); + if (m_refData == other.m_refData) + return true; + + if (!m_refData || !other.m_refData) + return false; + + return CGColorEqualToColor(GetCGColor(), other.GetCGColor()); } -#if wxOSX_USE_COCOA_OR_CARBON -void wxColour::InitRGBColor( const RGBColor& col ) +wxGDIRefData* wxColour::CreateGDIRefData() const { - m_red = col.red >> 8; - m_blue = col.blue >> 8; - m_green = col.green >> 8; - m_alpha = wxALPHA_OPAQUE; - CGColorRef cfcol; - CGFloat components[4] = { (CGFloat)(col.red / 65535.0), (CGFloat)(col.green / 65535.0), - (CGFloat)(col.blue / 65535.0), (CGFloat) 1.0 } ; - cfcol = CGColorCreate( wxMacGetGenericRGBColorSpace() , components ) ; - - wxASSERT_MSG(cfcol != NULL, "Invalid CoreGraphics Color"); - m_cgColour.reset( cfcol ); -} -#endif - -void wxColour::InitCGColorRef( CGColorRef col ) -{ - wxASSERT_MSG(col != NULL, "Invalid CoreGraphics Color"); - m_cgColour.reset( col ); - size_t noComp = CGColorGetNumberOfComponents( col ); - - const CGFloat *components = NULL; - if ( noComp >= 1 && noComp <= 4 ) - { - // TODO verify whether we really are on a RGB color space - m_alpha = wxALPHA_OPAQUE; - components = CGColorGetComponents( col ); - } - - if ( noComp < 1 || !components ) - { - m_alpha = wxALPHA_OPAQUE; - m_red = m_green = m_blue = 0; - return; - } - - if ( noComp >= 3 ) - { - m_red = (int)(components[0]*255+0.5); - m_green = (int)(components[1]*255+0.5); - m_blue = (int)(components[2]*255+0.5); - if ( noComp == 4 ) - m_alpha = (int)(components[3]*255+0.5); - } - else - { - m_red = (int)(components[0]*255+0.5); - m_green = (int)(components[0]*255+0.5); - m_blue = (int)(components[0]*255+0.5); - } + // black + return new wxCGColorRefData(0.0, 0.0, 0.0); } -bool wxColour::operator == (const wxColour& colour) const +wxGDIRefData* wxColour::CloneGDIRefData(const wxGDIRefData* data) const { - return ( (IsOk() == colour.IsOk()) && (!IsOk() || - CGColorEqualToColor( m_cgColour, colour.m_cgColour ) ) ); + return static_cast(data)->Clone(); } - -