1 | /* |
2 | * Copyright (C) 2003-2016 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #pragma once |
27 | |
28 | #include "ColorSpace.h" |
29 | #include "ExtendedColor.h" |
30 | #include <algorithm> |
31 | #include <cmath> |
32 | #include <unicode/uchar.h> |
33 | #include <wtf/Forward.h> |
34 | #include <wtf/HashFunctions.h> |
35 | #include <wtf/Optional.h> |
36 | #include <wtf/text/LChar.h> |
37 | |
38 | #if USE(CG) |
39 | typedef struct CGColor* CGColorRef; |
40 | #endif |
41 | |
42 | #if PLATFORM(WIN) |
43 | struct _D3DCOLORVALUE; |
44 | typedef _D3DCOLORVALUE D3DCOLORVALUE; |
45 | typedef D3DCOLORVALUE D2D_COLOR_F; |
46 | typedef D2D_COLOR_F D2D1_COLOR_F; |
47 | struct D2D_VECTOR_4F; |
48 | typedef D2D_VECTOR_4F D2D1_VECTOR_4F; |
49 | #endif |
50 | |
51 | #if PLATFORM(GTK) |
52 | typedef struct _GdkColor GdkColor; |
53 | #ifndef GTK_API_VERSION_2 |
54 | typedef struct _GdkRGBA GdkRGBA; |
55 | #endif |
56 | #endif |
57 | |
58 | namespace WTF { |
59 | class TextStream; |
60 | } |
61 | |
62 | namespace WebCore { |
63 | |
64 | typedef unsigned RGBA32; // Deprecated: Type for an RGBA quadruplet. Use RGBA class instead. |
65 | |
66 | WEBCORE_EXPORT RGBA32 makeRGB(int r, int g, int b); |
67 | WEBCORE_EXPORT RGBA32 makeRGBA(int r, int g, int b, int a); |
68 | |
69 | RGBA32 makePremultipliedRGBA(int r, int g, int b, int a, bool ceiling = true); |
70 | RGBA32 makeUnPremultipliedRGBA(int r, int g, int b, int a); |
71 | |
72 | WEBCORE_EXPORT RGBA32 colorWithOverrideAlpha(RGBA32 color, float overrideAlpha); |
73 | RGBA32 colorWithOverrideAlpha(RGBA32 color, Optional<float> overrideAlpha); |
74 | |
75 | WEBCORE_EXPORT RGBA32 makeRGBA32FromFloats(float r, float g, float b, float a); |
76 | RGBA32 makeRGBAFromHSLA(double h, double s, double l, double a); |
77 | RGBA32 makeRGBAFromCMYKA(float c, float m, float y, float k, float a); |
78 | |
79 | inline int redChannel(RGBA32 color) { return (color >> 16) & 0xFF; } |
80 | inline int greenChannel(RGBA32 color) { return (color >> 8) & 0xFF; } |
81 | inline int blueChannel(RGBA32 color) { return color & 0xFF; } |
82 | inline int alphaChannel(RGBA32 color) { return (color >> 24) & 0xFF; } |
83 | |
84 | uint8_t roundAndClampColorChannel(int); |
85 | uint8_t roundAndClampColorChannel(float); |
86 | |
87 | class RGBA { |
88 | public: |
89 | RGBA(); // all channels zero, including alpha |
90 | RGBA(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha); |
91 | RGBA(uint8_t red, uint8_t green, uint8_t blue); // opaque, alpha of 1 |
92 | |
93 | uint8_t red() const; |
94 | uint8_t green() const; |
95 | uint8_t blue() const; |
96 | uint8_t alpha() const; |
97 | |
98 | bool hasAlpha() const; |
99 | |
100 | private: |
101 | friend class Color; |
102 | |
103 | unsigned m_integer { 0 }; |
104 | }; |
105 | |
106 | bool operator==(const RGBA&, const RGBA&); |
107 | bool operator!=(const RGBA&, const RGBA&); |
108 | |
109 | class Color { |
110 | WTF_MAKE_FAST_ALLOCATED; |
111 | public: |
112 | Color() { } |
113 | |
114 | // FIXME: Remove all these constructors and creation functions and replace the ones that are still needed with free functions. |
115 | |
116 | Color(RGBA32 color, bool valid = true) |
117 | { |
118 | if (valid) |
119 | setRGB(color); |
120 | } |
121 | |
122 | enum SemanticTag { Semantic }; |
123 | |
124 | Color(RGBA32 color, SemanticTag) |
125 | { |
126 | setRGB(color); |
127 | setIsSemantic(); |
128 | } |
129 | |
130 | Color(int r, int g, int b) |
131 | { |
132 | setRGB(r, g, b); |
133 | } |
134 | |
135 | Color(int r, int g, int b, int a) |
136 | { |
137 | setRGB(makeRGBA(r, g, b, a)); |
138 | } |
139 | |
140 | Color(float r, float g, float b, float a) |
141 | { |
142 | setRGB(makeRGBA32FromFloats(r, g, b, a)); |
143 | } |
144 | |
145 | // Creates a new color from the specific CMYK and alpha values. |
146 | Color(float c, float m, float y, float k, float a) |
147 | { |
148 | setRGB(makeRGBAFromCMYKA(c, m, y, k, a)); |
149 | } |
150 | |
151 | WEBCORE_EXPORT explicit Color(const String&); |
152 | explicit Color(const char*); |
153 | |
154 | explicit Color(WTF::HashTableDeletedValueType) |
155 | { |
156 | static_assert(deletedHashValue & invalidRGBAColor, "Color's deleted hash value must not look like an ExtendedColor" ); |
157 | static_assert(!(deletedHashValue & validRGBAColorBit), "Color's deleted hash value must not look like a valid RGBA32 Color" ); |
158 | static_assert(deletedHashValue & (1 << 4), "Color's deleted hash value must have some bits set that an RGBA32 Color wouldn't have" ); |
159 | m_colorData.rgbaAndFlags = deletedHashValue; |
160 | ASSERT(!isExtended()); |
161 | } |
162 | |
163 | bool isHashTableDeletedValue() const |
164 | { |
165 | return m_colorData.rgbaAndFlags == deletedHashValue; |
166 | } |
167 | |
168 | explicit Color(WTF::HashTableEmptyValueType) |
169 | { |
170 | static_assert(emptyHashValue & invalidRGBAColor, "Color's empty hash value must not look like an ExtendedColor" ); |
171 | static_assert(emptyHashValue & (1 << 4), "Color's deleted hash value must have some bits set that an RGBA32 Color wouldn't have" ); |
172 | m_colorData.rgbaAndFlags = emptyHashValue; |
173 | ASSERT(!isExtended()); |
174 | } |
175 | |
176 | // This creates an ExtendedColor. |
177 | // FIXME: If the colorSpace is sRGB and the values can all be |
178 | // converted exactly to integers, we should make a normal Color. |
179 | WEBCORE_EXPORT Color(float r, float g, float b, float a, ColorSpace colorSpace); |
180 | |
181 | Color(RGBA, ColorSpace); |
182 | WEBCORE_EXPORT Color(const Color&); |
183 | WEBCORE_EXPORT Color(Color&&); |
184 | |
185 | ~Color() |
186 | { |
187 | if (isExtended()) |
188 | m_colorData.extendedColor->deref(); |
189 | } |
190 | |
191 | static Color createUnchecked(int r, int g, int b) |
192 | { |
193 | RGBA32 color = 0xFF000000 | r << 16 | g << 8 | b; |
194 | return Color(color); |
195 | } |
196 | static Color createUnchecked(int r, int g, int b, int a) |
197 | { |
198 | RGBA32 color = a << 24 | r << 16 | g << 8 | b; |
199 | return Color(color); |
200 | } |
201 | |
202 | // Returns the color serialized according to HTML5 |
203 | // <https://html.spec.whatwg.org/multipage/scripting.html#fill-and-stroke-styles> (10 September 2015) |
204 | WEBCORE_EXPORT String serialized() const; |
205 | |
206 | WEBCORE_EXPORT String cssText() const; |
207 | |
208 | // Returns the color serialized as either #RRGGBB or #RRGGBBAA |
209 | String nameForRenderTreeAsText() const; |
210 | |
211 | bool isValid() const { return isExtended() || (m_colorData.rgbaAndFlags & validRGBAColorBit); } |
212 | |
213 | bool isOpaque() const { return isValid() && (isExtended() ? asExtended().alpha() == 1.0 : alpha() == 255); } |
214 | bool isVisible() const { return isValid() && (isExtended() ? asExtended().alpha() > 0.0 : alpha() > 0); } |
215 | |
216 | int red() const { return redChannel(rgb()); } |
217 | int green() const { return greenChannel(rgb()); } |
218 | int blue() const { return blueChannel(rgb()); } |
219 | int alpha() const { return alphaChannel(rgb()); } |
220 | |
221 | float alphaAsFloat() const { return isExtended() ? asExtended().alpha() : static_cast<float>(alphaChannel(rgb())) / 255; } |
222 | |
223 | RGBA32 rgb() const; |
224 | |
225 | // FIXME: Like operator==, this will give different values for ExtendedColors that |
226 | // should be identical, since the respective pointer will be different. |
227 | unsigned hash() const { return WTF::intHash(m_colorData.rgbaAndFlags); } |
228 | |
229 | // FIXME: ExtendedColor - these should be renamed (to be clear about their parameter types, or |
230 | // replaced with alternative accessors. |
231 | WEBCORE_EXPORT void getRGBA(float& r, float& g, float& b, float& a) const; |
232 | WEBCORE_EXPORT void getRGBA(double& r, double& g, double& b, double& a) const; |
233 | WEBCORE_EXPORT void getHSL(double& h, double& s, double& l) const; |
234 | WEBCORE_EXPORT void getHSV(double& h, double& s, double& v) const; |
235 | |
236 | Color light() const; |
237 | Color dark() const; |
238 | |
239 | bool isDark() const; |
240 | |
241 | // This is an implementation of Porter-Duff's "source-over" equation |
242 | Color blend(const Color&) const; |
243 | Color blendWithWhite() const; |
244 | |
245 | Color colorWithAlphaMultipliedBy(float) const; |
246 | |
247 | // Returns a color that has the same RGB values, but with the given A. |
248 | Color colorWithAlpha(float) const; |
249 | Color opaqueColor() const { return colorWithAlpha(1.0f); } |
250 | |
251 | // True if the color originated from a CSS semantic color name. |
252 | bool isSemantic() const { return !isExtended() && (m_colorData.rgbaAndFlags & isSemanticRBGAColorBit); } |
253 | |
254 | #if PLATFORM(GTK) |
255 | Color(const GdkColor&); |
256 | // We can't sensibly go back to GdkColor without losing the alpha value |
257 | #ifndef GTK_API_VERSION_2 |
258 | Color(const GdkRGBA&); |
259 | operator GdkRGBA() const; |
260 | #endif |
261 | #endif |
262 | |
263 | #if USE(CG) |
264 | WEBCORE_EXPORT Color(CGColorRef); |
265 | WEBCORE_EXPORT Color(CGColorRef, SemanticTag); |
266 | #endif |
267 | |
268 | #if PLATFORM(WIN) |
269 | WEBCORE_EXPORT Color(D2D1_COLOR_F); |
270 | WEBCORE_EXPORT operator D2D1_COLOR_F() const; |
271 | WEBCORE_EXPORT operator D2D1_VECTOR_4F() const; |
272 | #endif |
273 | |
274 | static bool parseHexColor(const String&, RGBA32&); |
275 | static bool parseHexColor(const StringView&, RGBA32&); |
276 | static bool parseHexColor(const LChar*, unsigned, RGBA32&); |
277 | static bool parseHexColor(const UChar*, unsigned, RGBA32&); |
278 | |
279 | static const RGBA32 black = 0xFF000000; |
280 | WEBCORE_EXPORT static const RGBA32 white = 0xFFFFFFFF; |
281 | static const RGBA32 darkGray = 0xFF808080; |
282 | static const RGBA32 gray = 0xFFA0A0A0; |
283 | static const RGBA32 lightGray = 0xFFC0C0C0; |
284 | WEBCORE_EXPORT static const RGBA32 transparent = 0x00000000; |
285 | static const RGBA32 cyan = 0xFF00FFFF; |
286 | static const RGBA32 yellow = 0xFFFFFF00; |
287 | |
288 | #if PLATFORM(IOS_FAMILY) |
289 | static const RGBA32 compositionFill = 0x3CAFC0E3; |
290 | #else |
291 | static const RGBA32 compositionFill = 0xFFE1DD55; |
292 | #endif |
293 | |
294 | bool isExtended() const |
295 | { |
296 | return !(m_colorData.rgbaAndFlags & invalidRGBAColor); |
297 | } |
298 | WEBCORE_EXPORT ExtendedColor& asExtended() const; |
299 | |
300 | WEBCORE_EXPORT Color& operator=(const Color&); |
301 | WEBCORE_EXPORT Color& operator=(Color&&); |
302 | |
303 | friend bool operator==(const Color& a, const Color& b); |
304 | friend bool equalIgnoringSemanticColor(const Color& a, const Color& b); |
305 | |
306 | static bool isBlackColor(const Color&); |
307 | static bool isWhiteColor(const Color&); |
308 | |
309 | private: |
310 | void setRGB(int r, int g, int b) { setRGB(makeRGB(r, g, b)); } |
311 | void setRGB(RGBA32); |
312 | void setIsSemantic() { m_colorData.rgbaAndFlags |= isSemanticRBGAColorBit; } |
313 | |
314 | // 0x_______00 is an ExtendedColor pointer. |
315 | // 0x_______01 is an invalid RGBA32. |
316 | // 0x_______11 is a valid RGBA32. |
317 | static const uint64_t extendedColor = 0x0; |
318 | static const uint64_t invalidRGBAColor = 0x1; |
319 | static const uint64_t validRGBAColorBit = 0x2; |
320 | static const uint64_t validRGBAColor = 0x3; |
321 | static const uint64_t isSemanticRBGAColorBit = 0x4; |
322 | |
323 | static const uint64_t deletedHashValue = 0xFFFFFFFFFFFFFFFD; |
324 | static const uint64_t emptyHashValue = 0xFFFFFFFFFFFFFFFB; |
325 | |
326 | WEBCORE_EXPORT void tagAsValid(); |
327 | |
328 | union { |
329 | uint64_t rgbaAndFlags { invalidRGBAColor }; |
330 | ExtendedColor* extendedColor; |
331 | } m_colorData; |
332 | }; |
333 | |
334 | // FIXME: These do not work for ExtendedColor because |
335 | // they become just pointer comparison. |
336 | bool operator==(const Color&, const Color&); |
337 | bool operator!=(const Color&, const Color&); |
338 | |
339 | Color colorFromPremultipliedARGB(RGBA32); |
340 | RGBA32 premultipliedARGBFromColor(const Color&); |
341 | |
342 | Color blend(const Color& from, const Color& to, double progress, bool blendPremultiplied = true); |
343 | |
344 | int differenceSquared(const Color&, const Color&); |
345 | |
346 | uint16_t fastMultiplyBy255(uint16_t value); |
347 | uint16_t fastDivideBy255(uint16_t); |
348 | |
349 | #if USE(CG) |
350 | WEBCORE_EXPORT CGColorRef cachedCGColor(const Color&); |
351 | #endif |
352 | |
353 | inline RGBA::RGBA() |
354 | { |
355 | } |
356 | |
357 | inline RGBA::RGBA(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) |
358 | : m_integer(alpha << 24 | red << 16 | green << 8 | blue) |
359 | { |
360 | } |
361 | |
362 | inline RGBA::RGBA(uint8_t red, uint8_t green, uint8_t blue) |
363 | : m_integer(0xFF000000 | red << 16 | green << 8 | blue) |
364 | { |
365 | } |
366 | |
367 | inline uint8_t RGBA::red() const |
368 | { |
369 | return m_integer >> 16; |
370 | } |
371 | |
372 | inline uint8_t RGBA::green() const |
373 | { |
374 | return m_integer >> 8; |
375 | } |
376 | |
377 | inline uint8_t RGBA::blue() const |
378 | { |
379 | return m_integer; |
380 | } |
381 | |
382 | inline uint8_t RGBA::alpha() const |
383 | { |
384 | return m_integer >> 24; |
385 | } |
386 | |
387 | inline bool RGBA::hasAlpha() const |
388 | { |
389 | return (m_integer & 0xFF000000) != 0xFF000000; |
390 | } |
391 | |
392 | inline Color::Color(RGBA color, ColorSpace space) |
393 | { |
394 | setRGB(color.m_integer); |
395 | ASSERT_UNUSED(space, space == ColorSpaceSRGB); |
396 | } |
397 | |
398 | inline bool operator==(const Color& a, const Color& b) |
399 | { |
400 | return a.m_colorData.rgbaAndFlags == b.m_colorData.rgbaAndFlags; |
401 | } |
402 | |
403 | inline bool operator!=(const Color& a, const Color& b) |
404 | { |
405 | return !(a == b); |
406 | } |
407 | |
408 | inline bool equalIgnoringSemanticColor(const Color& a, const Color& b) |
409 | { |
410 | return (a.m_colorData.rgbaAndFlags & ~Color::isSemanticRBGAColorBit) == (b.m_colorData.rgbaAndFlags & ~Color::isSemanticRBGAColorBit); |
411 | } |
412 | |
413 | inline uint8_t roundAndClampColorChannel(int value) |
414 | { |
415 | return std::max(0, std::min(255, value)); |
416 | } |
417 | |
418 | inline uint8_t roundAndClampColorChannel(float value) |
419 | { |
420 | return std::max(0.f, std::min(255.f, std::round(value))); |
421 | } |
422 | |
423 | inline uint16_t fastMultiplyBy255(uint16_t value) |
424 | { |
425 | return (value << 8) - value; |
426 | } |
427 | |
428 | inline uint16_t fastDivideBy255(uint16_t value) |
429 | { |
430 | // While this is an approximate algorithm for division by 255, it gives perfectly accurate results for 16-bit values. |
431 | // FIXME: Since this gives accurate results for 16-bit values, we should get this optimization into compilers like clang. |
432 | uint16_t approximation = value >> 8; |
433 | uint16_t remainder = value - (approximation * 255) + 1; |
434 | return approximation + (remainder >> 8); |
435 | } |
436 | |
437 | inline RGBA32 colorWithOverrideAlpha(RGBA32 color, Optional<float> overrideAlpha) |
438 | { |
439 | return overrideAlpha ? colorWithOverrideAlpha(color, overrideAlpha.value()) : color; |
440 | } |
441 | |
442 | inline RGBA32 Color::rgb() const |
443 | { |
444 | // FIXME: We should ASSERT(!isExtended()) here, or produce |
445 | // an RGBA32 equivalent for an ExtendedColor. Ideally the former, |
446 | // so we can audit all the rgb() call sites to handle extended. |
447 | return static_cast<RGBA32>(m_colorData.rgbaAndFlags >> 32); |
448 | } |
449 | |
450 | inline void Color::setRGB(RGBA32 rgb) |
451 | { |
452 | m_colorData.rgbaAndFlags = static_cast<uint64_t>(rgb) << 32; |
453 | tagAsValid(); |
454 | } |
455 | |
456 | inline bool Color::isBlackColor(const Color& color) |
457 | { |
458 | if (color.isExtended()) { |
459 | const ExtendedColor& extendedColor = color.asExtended(); |
460 | return !extendedColor.red() && !extendedColor.green() && !extendedColor.blue() && extendedColor.alpha() == 1; |
461 | } |
462 | |
463 | return color.isValid() && color.rgb() == Color::black; |
464 | } |
465 | |
466 | inline bool Color::isWhiteColor(const Color& color) |
467 | { |
468 | if (color.isExtended()) { |
469 | const ExtendedColor& extendedColor = color.asExtended(); |
470 | return extendedColor.red() == 1 && extendedColor.green() == 1 && extendedColor.blue() == 1 && extendedColor.alpha() == 1; |
471 | } |
472 | |
473 | return color.isValid() && color.rgb() == Color::white; |
474 | } |
475 | |
476 | WEBCORE_EXPORT WTF::TextStream& operator<<(WTF::TextStream&, const Color&); |
477 | WEBCORE_EXPORT WTF::TextStream& operator<<(WTF::TextStream&, ColorSpace); |
478 | |
479 | } // namespace WebCore |
480 | |
481 | namespace WTF { |
482 | template<> struct DefaultHash<WebCore::Color>; |
483 | template<> struct HashTraits<WebCore::Color>; |
484 | } |
485 | |