1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/osx/core/colour.cpp
3 // Purpose:     wxColour class
4 // Author:      Stefan Csomor
5 // Modified by:
6 // Created:     1998-01-01
7 // Copyright:   (c) Stefan Csomor
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 #include "wx/wxprec.h"
12 
13 #include "wx/colour.h"
14 
15 #ifndef WX_PRECOMP
16     #include "wx/gdicmn.h"
17 #endif
18 
19 #include "wx/osx/private.h"
20 #include "wx/osx/private/available.h"
21 
22 CGColorSpaceRef wxMacGetGenericRGBColorSpace();
23 
24 class wxCGColorRefData : public wxColourRefData
25 {
26 public:
27     wxCGColorRefData(CGFloat r, CGFloat g, CGFloat b, CGFloat a = 1.0);
28 
29     wxCGColorRefData(CGFloat components[4]);
30 
31     wxCGColorRefData(CGColorRef);
32 
33     wxCGColorRefData(const wxCGColorRefData& other);
34 
IsOk() const35     virtual bool IsOk() const  wxOVERRIDE{ return m_cgColour != NULL; }
36 
Red() const37     virtual CGFloat Red() const wxOVERRIDE { return m_red; }
Green() const38     virtual CGFloat Green() const wxOVERRIDE { return m_green; }
Blue() const39     virtual CGFloat Blue() const wxOVERRIDE { return m_blue; }
Alpha() const40     virtual CGFloat Alpha() const wxOVERRIDE { return m_alpha; }
41 
GetCGColor() const42     CGColorRef GetCGColor() const wxOVERRIDE { return m_cgColour; }
43 
Clone() const44     virtual wxColourRefData* Clone() const wxOVERRIDE { return new wxCGColorRefData(*this); }
45 
46 private:
47     void Init(CGFloat components[4]);
48 
49     wxCFRef<CGColorRef> m_cgColour;
50 
51     CGFloat m_red;
52     CGFloat m_blue;
53     CGFloat m_green;
54     CGFloat m_alpha;
55 
56     wxDECLARE_NO_ASSIGN_CLASS(wxCGColorRefData);
57 };
58 
wxCGColorRefData(CGFloat r,CGFloat g,CGFloat b,CGFloat a)59 wxCGColorRefData::wxCGColorRefData(CGFloat r, CGFloat g, CGFloat b, CGFloat a)
60 {
61     CGFloat components[4];
62     components[0] = r;
63     components[1] = g;
64     components[2] = b;
65     components[3] = a;
66 
67     Init(components);
68 }
69 
wxCGColorRefData(CGFloat components[4])70 wxCGColorRefData::wxCGColorRefData(CGFloat components[4])
71 {
72     Init(components);
73 }
74 
wxCGColorRefData(const wxCGColorRefData & other)75 wxCGColorRefData::wxCGColorRefData(const wxCGColorRefData& other)
76 {
77     m_red = other.m_red;
78     m_blue = other.m_blue;
79     m_green = other.m_green;
80     m_alpha = other.m_alpha;
81 
82     m_cgColour = other.m_cgColour;
83 }
84 
Init(CGFloat components[4])85 void wxCGColorRefData::Init(CGFloat components[4])
86 {
87     m_red = components[0];
88     m_green = components[1];
89     m_blue = components[2];
90     m_alpha = components[3];
91 
92     m_cgColour = CGColorCreate(wxMacGetGenericRGBColorSpace(), components);
93 }
94 
wxCGColorRefData(CGColorRef col)95 wxCGColorRefData::wxCGColorRefData(CGColorRef col)
96 {
97     wxASSERT_MSG(col != NULL, "Invalid CoreGraphics Color");
98     m_cgColour.reset(col);
99 
100     wxCFRef<CGColorRef> rgbacol;
101     size_t noComp = CGColorGetNumberOfComponents(col);
102     const CGFloat* components = CGColorGetComponents(col);
103 
104     // set default alpha
105     m_alpha = 1.0;
106     bool isRGB = true;
107 
108     CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(col));
109     if (model == kCGColorSpaceModelMonochrome)
110     {
111         wxASSERT_MSG(1 <= noComp && noComp <= 2, "Monochrome Color unexpected components");
112         m_red = components[0];
113         m_green = components[0];
114         m_blue = components[0];
115         if (noComp > 1)
116             m_alpha = components[1];
117         isRGB = false;
118     }
119     else if (model != kCGColorSpaceModelRGB)
120     {
121         if ( WX_IS_MACOS_OR_IOS_AVAILABLE(10, 11, 9, 0) )
122         {
123             rgbacol = CGColorCreateCopyByMatchingToColorSpace(wxMacGetGenericRGBColorSpace(), kCGRenderingIntentDefault, col, NULL);
124             noComp = CGColorGetNumberOfComponents(rgbacol);
125             components = CGColorGetComponents(rgbacol);
126         }
127         else
128         {
129             isRGB = false;
130         }
131     }
132 
133     if (isRGB)
134     {
135         wxASSERT_MSG(3 <= noComp && noComp <= 4, "RGB Color unexpected components");
136         m_red = components[0];
137         m_green = components[1];
138         m_blue = components[2];
139 
140         if (noComp == 4)
141             m_alpha = components[3];
142     }
143 }
144 
145 #define M_COLDATA static_cast<wxColourRefData*>(m_refData)
146 
147 #if wxOSX_USE_COCOA_OR_CARBON
wxColour(const RGBColor & col)148 wxColour::wxColour(const RGBColor& col)
149 {
150     CGFloat components[4] = { (CGFloat)(col.red / 65535.0), (CGFloat)(col.green / 65535.0),
151         (CGFloat)(col.blue / 65535.0), (CGFloat)1.0 };
152     m_refData = new wxCGColorRefData(components);
153 }
154 #endif
155 
wxColour(CGColorRef col)156 wxColour::wxColour(CGColorRef col)
157 {
158     wxASSERT_MSG(col != NULL, "Invalid CoreGraphics Color");
159 
160     m_refData = new wxCGColorRefData(col);
161 }
162 
Red() const163 wxColour::ChannelType wxColour::Red() const
164 {
165     wxCHECK_MSG( IsOk(), 0, "invalid colour" );
166 
167     return wxRound(M_COLDATA->Red() * 255.0);
168 }
169 
Green() const170 wxColour::ChannelType wxColour::Green() const
171 {
172     wxCHECK_MSG( IsOk(), 0, "invalid colour" );
173 
174     return wxRound(M_COLDATA->Green() * 255.0);
175 }
176 
Blue() const177 wxColour::ChannelType wxColour::Blue() const
178 {
179     wxCHECK_MSG( IsOk(), 0, "invalid colour" );
180 
181     return wxRound(M_COLDATA->Blue() * 255.0);
182 }
183 
Alpha() const184 wxColour::ChannelType wxColour::Alpha() const
185 {
186     wxCHECK_MSG( IsOk(), 0, "invalid colour" );
187 
188     return wxRound(M_COLDATA->Alpha() * 255.0);
189 }
190 
IsSolid() const191 bool wxColour::IsSolid() const
192 {
193     wxCHECK_MSG( IsOk(), false, "invalid colour" );
194 
195     return M_COLDATA->IsSolid();
196 }
197 
198 #if wxOSX_USE_COCOA_OR_CARBON
GetRGBColor(RGBColor * col) const199 void wxColour::GetRGBColor(RGBColor* col) const
200 {
201     wxCHECK_RET( IsOk(), "invalid colour" );
202 
203     col->red = M_COLDATA->Red() * 65535.0;
204     col->blue = M_COLDATA->Blue() * 65535.0;
205     col->green = M_COLDATA->Green() * 65535.0;
206 }
207 #endif
208 
GetCGColor() const209 CGColorRef wxColour::GetCGColor() const
210 {
211     wxCHECK_MSG( IsOk(), NULL, "invalid colour" );
212 
213     return M_COLDATA->GetCGColor();
214 }
215 
216 #if wxOSX_USE_COCOA
OSXGetNSColor() const217 WX_NSColor wxColour::OSXGetNSColor() const
218 {
219     wxCHECK_MSG( IsOk(), NULL, "invalid colour" );
220 
221     return M_COLDATA->GetNSColor();
222 }
223 
OSXGetNSPatternImage() const224 WX_NSImage wxColour::OSXGetNSPatternImage() const
225 {
226     wxCHECK_MSG( IsOk(), NULL, "invalid colour" );
227 
228     return M_COLDATA->GetNSPatternImage();
229 }
230 #endif
231 
InitRGBA(ChannelType r,ChannelType g,ChannelType b,ChannelType a)232 void wxColour::InitRGBA(ChannelType r, ChannelType g, ChannelType b, ChannelType a)
233 {
234     CGFloat components[4] = { (CGFloat)(r / 255.0), (CGFloat)(g / 255.0), (CGFloat)(b / 255.0), (CGFloat)(a / 255.0) };
235     m_refData = new wxCGColorRefData(components);
236 }
237 
operator ==(const wxColour & other) const238 bool wxColour::operator==(const wxColour& other) const
239 {
240     if (m_refData == other.m_refData)
241         return true;
242 
243     if (!m_refData || !other.m_refData)
244         return false;
245 
246     return CGColorEqualToColor(GetCGColor(), other.GetCGColor());
247 }
248 
CreateGDIRefData() const249 wxGDIRefData* wxColour::CreateGDIRefData() const
250 {
251     // black
252     return new wxCGColorRefData(0.0, 0.0, 0.0);
253 }
254 
CloneGDIRefData(const wxGDIRefData * data) const255 wxGDIRefData* wxColour::CloneGDIRefData(const wxGDIRefData* data) const
256 {
257     return static_cast<const wxColourRefData*>(data)->Clone();
258 }
259