1# Licensed to the Software Freedom Conservancy (SFC) under one
2# or more contributor license agreements.  See the NOTICE file
3# distributed with this work for additional information
4# regarding copyright ownership.  The SFC licenses this file
5# to you under the Apache License, Version 2.0 (the
6# "License"); you may not use this file except in compliance
7# with the License.  You may obtain a copy of the License at
8#
9#   http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing,
12# software distributed under the License is distributed on an
13# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14# KIND, either express or implied.  See the License for the
15# specific language governing permissions and limitations
16# under the License.
17
18RGB_PATTERN = r"^\s*rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)\s*$"
19RGB_PCT_PATTERN = r"^\s*rgb\(\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*\)\s*$"
20RGBA_PATTERN = r"^\s*rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0|1|0\.\d+)\s*\)\s*$"
21RGBA_PCT_PATTERN = r"^\s*rgba\(\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,\s*(0|1|0\.\d+)\s*\)\s*$"
22HEX_PATTERN = r"#([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})([A-Fa-f0-9]{2})"
23HEX3_PATTERN = r"#([A-Fa-f0-9])([A-Fa-f0-9])([A-Fa-f0-9])"
24HSL_PATTERN = r"^\s*hsl\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*\)\s*$"
25HSLA_PATTERN = r"^\s*hsla\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*,\s*(0|1|0\.\d+)\s*\)\s*$"
26
27
28class Color(object):
29    """
30    Color conversion support class
31
32    Example:
33
34    .. code-block:: python
35
36        from selenium.webdriver.support.color import Color
37
38        print(Color.from_string('#00ff33').rgba)
39        print(Color.from_string('rgb(1, 255, 3)').hex)
40        print(Color.from_string('blue').rgba)
41    """
42
43    @staticmethod
44    def from_string(str_):
45        import re
46
47        class Matcher(object):
48            def __init__(self):
49                self.match_obj = None
50
51            def match(self, pattern, str_):
52                self.match_obj = re.match(pattern, str_)
53                return self.match_obj
54
55            @property
56            def groups(self):
57                return () if self.match_obj is None else self.match_obj.groups()
58
59        m = Matcher()
60
61        if m.match(RGB_PATTERN, str_):
62            return Color(*m.groups)
63        elif m.match(RGB_PCT_PATTERN, str_):
64            rgb = tuple([float(each) / 100 * 255 for each in m.groups])
65            return Color(*rgb)
66        elif m.match(RGBA_PATTERN, str_):
67            return Color(*m.groups)
68        elif m.match(RGBA_PCT_PATTERN, str_):
69            rgba = tuple([float(each) / 100 * 255 for each in m.groups[:3]] + [m.groups[3]])
70            return Color(*rgba)
71        elif m.match(HEX_PATTERN, str_):
72            rgb = tuple([int(each, 16) for each in m.groups])
73            return Color(*rgb)
74        elif m.match(HEX3_PATTERN, str_):
75            rgb = tuple([int(each * 2, 16) for each in m.groups])
76            return Color(*rgb)
77        elif m.match(HSL_PATTERN, str_) or m.match(HSLA_PATTERN, str_):
78            return Color._from_hsl(*m.groups)
79        elif str_.upper() in Colors.keys():
80            return Colors[str_.upper()]
81        else:
82            raise ValueError("Could not convert %s into color" % str_)
83
84    @staticmethod
85    def _from_hsl(h, s, l, a=1):
86        h = float(h) / 360
87        s = float(s) / 100
88        l = float(l) / 100
89
90        if s == 0:
91            r = l
92            g = r
93            b = r
94        else:
95            luminocity2 = l * (1 + s) if l < 0.5 else l + s - l * s
96            luminocity1 = 2 * l - luminocity2
97
98            def hue_to_rgb(lum1, lum2, hue):
99                if hue < 0.0:
100                    hue += 1
101                if hue > 1.0:
102                    hue -= 1
103
104                if hue < 1.0 / 6.0:
105                    return (lum1 + (lum2 - lum1) * 6.0 * hue)
106                elif hue < 1.0 / 2.0:
107                    return lum2
108                elif hue < 2.0 / 3.0:
109                    return lum1 + (lum2 - lum1) * ((2.0 / 3.0) - hue) * 6.0
110                else:
111                    return lum1
112
113            r = hue_to_rgb(luminocity1, luminocity2, h + 1.0 / 3.0)
114            g = hue_to_rgb(luminocity1, luminocity2, h)
115            b = hue_to_rgb(luminocity1, luminocity2, h - 1.0 / 3.0)
116
117        return Color(round(r * 255), round(g * 255), round(b * 255), a)
118
119    def __init__(self, red, green, blue, alpha=1):
120        self.red = int(red)
121        self.green = int(green)
122        self.blue = int(blue)
123        self.alpha = "1" if float(alpha) == 1 else str(float(alpha) or 0)
124
125    @property
126    def rgb(self):
127        return "rgb(%d, %d, %d)" % (self.red, self.green, self.blue)
128
129    @property
130    def rgba(self):
131        return "rgba(%d, %d, %d, %s)" % (self.red, self.green, self.blue, self.alpha)
132
133    @property
134    def hex(self):
135        return "#%02x%02x%02x" % (self.red, self.green, self.blue)
136
137    def __eq__(self, other):
138        if isinstance(other, Color):
139            return self.rgba == other.rgba
140        return NotImplemented
141
142    def __ne__(self, other):
143        result = self.__eq__(other)
144        if result is NotImplemented:
145            return result
146        return not result
147
148    def __hash__(self):
149        return hash((self.red, self.green, self.blue, self.alpha))
150
151    def __repr__(self):
152        return "Color(red=%d, green=%d, blue=%d, alpha=%s)" % (self.red, self.green, self.blue, self.alpha)
153
154    def __str__(self):
155        return "Color: %s" % self.rgba
156
157
158# Basic, extended and transparent colour keywords as defined by the W3C HTML4 spec
159# See http://www.w3.org/TR/css3-color/#html4
160Colors = {
161    "TRANSPARENT": Color(0, 0, 0, 0),
162    "ALICEBLUE": Color(240, 248, 255),
163    "ANTIQUEWHITE": Color(250, 235, 215),
164    "AQUA": Color(0, 255, 255),
165    "AQUAMARINE": Color(127, 255, 212),
166    "AZURE": Color(240, 255, 255),
167    "BEIGE": Color(245, 245, 220),
168    "BISQUE": Color(255, 228, 196),
169    "BLACK": Color(0, 0, 0),
170    "BLANCHEDALMOND": Color(255, 235, 205),
171    "BLUE": Color(0, 0, 255),
172    "BLUEVIOLET": Color(138, 43, 226),
173    "BROWN": Color(165, 42, 42),
174    "BURLYWOOD": Color(222, 184, 135),
175    "CADETBLUE": Color(95, 158, 160),
176    "CHARTREUSE": Color(127, 255, 0),
177    "CHOCOLATE": Color(210, 105, 30),
178    "CORAL": Color(255, 127, 80),
179    "CORNFLOWERBLUE": Color(100, 149, 237),
180    "CORNSILK": Color(255, 248, 220),
181    "CRIMSON": Color(220, 20, 60),
182    "CYAN": Color(0, 255, 255),
183    "DARKBLUE": Color(0, 0, 139),
184    "DARKCYAN": Color(0, 139, 139),
185    "DARKGOLDENROD": Color(184, 134, 11),
186    "DARKGRAY": Color(169, 169, 169),
187    "DARKGREEN": Color(0, 100, 0),
188    "DARKGREY": Color(169, 169, 169),
189    "DARKKHAKI": Color(189, 183, 107),
190    "DARKMAGENTA": Color(139, 0, 139),
191    "DARKOLIVEGREEN": Color(85, 107, 47),
192    "DARKORANGE": Color(255, 140, 0),
193    "DARKORCHID": Color(153, 50, 204),
194    "DARKRED": Color(139, 0, 0),
195    "DARKSALMON": Color(233, 150, 122),
196    "DARKSEAGREEN": Color(143, 188, 143),
197    "DARKSLATEBLUE": Color(72, 61, 139),
198    "DARKSLATEGRAY": Color(47, 79, 79),
199    "DARKSLATEGREY": Color(47, 79, 79),
200    "DARKTURQUOISE": Color(0, 206, 209),
201    "DARKVIOLET": Color(148, 0, 211),
202    "DEEPPINK": Color(255, 20, 147),
203    "DEEPSKYBLUE": Color(0, 191, 255),
204    "DIMGRAY": Color(105, 105, 105),
205    "DIMGREY": Color(105, 105, 105),
206    "DODGERBLUE": Color(30, 144, 255),
207    "FIREBRICK": Color(178, 34, 34),
208    "FLORALWHITE": Color(255, 250, 240),
209    "FORESTGREEN": Color(34, 139, 34),
210    "FUCHSIA": Color(255, 0, 255),
211    "GAINSBORO": Color(220, 220, 220),
212    "GHOSTWHITE": Color(248, 248, 255),
213    "GOLD": Color(255, 215, 0),
214    "GOLDENROD": Color(218, 165, 32),
215    "GRAY": Color(128, 128, 128),
216    "GREY": Color(128, 128, 128),
217    "GREEN": Color(0, 128, 0),
218    "GREENYELLOW": Color(173, 255, 47),
219    "HONEYDEW": Color(240, 255, 240),
220    "HOTPINK": Color(255, 105, 180),
221    "INDIANRED": Color(205, 92, 92),
222    "INDIGO": Color(75, 0, 130),
223    "IVORY": Color(255, 255, 240),
224    "KHAKI": Color(240, 230, 140),
225    "LAVENDER": Color(230, 230, 250),
226    "LAVENDERBLUSH": Color(255, 240, 245),
227    "LAWNGREEN": Color(124, 252, 0),
228    "LEMONCHIFFON": Color(255, 250, 205),
229    "LIGHTBLUE": Color(173, 216, 230),
230    "LIGHTCORAL": Color(240, 128, 128),
231    "LIGHTCYAN": Color(224, 255, 255),
232    "LIGHTGOLDENRODYELLOW": Color(250, 250, 210),
233    "LIGHTGRAY": Color(211, 211, 211),
234    "LIGHTGREEN": Color(144, 238, 144),
235    "LIGHTGREY": Color(211, 211, 211),
236    "LIGHTPINK": Color(255, 182, 193),
237    "LIGHTSALMON": Color(255, 160, 122),
238    "LIGHTSEAGREEN": Color(32, 178, 170),
239    "LIGHTSKYBLUE": Color(135, 206, 250),
240    "LIGHTSLATEGRAY": Color(119, 136, 153),
241    "LIGHTSLATEGREY": Color(119, 136, 153),
242    "LIGHTSTEELBLUE": Color(176, 196, 222),
243    "LIGHTYELLOW": Color(255, 255, 224),
244    "LIME": Color(0, 255, 0),
245    "LIMEGREEN": Color(50, 205, 50),
246    "LINEN": Color(250, 240, 230),
247    "MAGENTA": Color(255, 0, 255),
248    "MAROON": Color(128, 0, 0),
249    "MEDIUMAQUAMARINE": Color(102, 205, 170),
250    "MEDIUMBLUE": Color(0, 0, 205),
251    "MEDIUMORCHID": Color(186, 85, 211),
252    "MEDIUMPURPLE": Color(147, 112, 219),
253    "MEDIUMSEAGREEN": Color(60, 179, 113),
254    "MEDIUMSLATEBLUE": Color(123, 104, 238),
255    "MEDIUMSPRINGGREEN": Color(0, 250, 154),
256    "MEDIUMTURQUOISE": Color(72, 209, 204),
257    "MEDIUMVIOLETRED": Color(199, 21, 133),
258    "MIDNIGHTBLUE": Color(25, 25, 112),
259    "MINTCREAM": Color(245, 255, 250),
260    "MISTYROSE": Color(255, 228, 225),
261    "MOCCASIN": Color(255, 228, 181),
262    "NAVAJOWHITE": Color(255, 222, 173),
263    "NAVY": Color(0, 0, 128),
264    "OLDLACE": Color(253, 245, 230),
265    "OLIVE": Color(128, 128, 0),
266    "OLIVEDRAB": Color(107, 142, 35),
267    "ORANGE": Color(255, 165, 0),
268    "ORANGERED": Color(255, 69, 0),
269    "ORCHID": Color(218, 112, 214),
270    "PALEGOLDENROD": Color(238, 232, 170),
271    "PALEGREEN": Color(152, 251, 152),
272    "PALETURQUOISE": Color(175, 238, 238),
273    "PALEVIOLETRED": Color(219, 112, 147),
274    "PAPAYAWHIP": Color(255, 239, 213),
275    "PEACHPUFF": Color(255, 218, 185),
276    "PERU": Color(205, 133, 63),
277    "PINK": Color(255, 192, 203),
278    "PLUM": Color(221, 160, 221),
279    "POWDERBLUE": Color(176, 224, 230),
280    "PURPLE": Color(128, 0, 128),
281    "REBECCAPURPLE": Color(128, 51, 153),
282    "RED": Color(255, 0, 0),
283    "ROSYBROWN": Color(188, 143, 143),
284    "ROYALBLUE": Color(65, 105, 225),
285    "SADDLEBROWN": Color(139, 69, 19),
286    "SALMON": Color(250, 128, 114),
287    "SANDYBROWN": Color(244, 164, 96),
288    "SEAGREEN": Color(46, 139, 87),
289    "SEASHELL": Color(255, 245, 238),
290    "SIENNA": Color(160, 82, 45),
291    "SILVER": Color(192, 192, 192),
292    "SKYBLUE": Color(135, 206, 235),
293    "SLATEBLUE": Color(106, 90, 205),
294    "SLATEGRAY": Color(112, 128, 144),
295    "SLATEGREY": Color(112, 128, 144),
296    "SNOW": Color(255, 250, 250),
297    "SPRINGGREEN": Color(0, 255, 127),
298    "STEELBLUE": Color(70, 130, 180),
299    "TAN": Color(210, 180, 140),
300    "TEAL": Color(0, 128, 128),
301    "THISTLE": Color(216, 191, 216),
302    "TOMATO": Color(255, 99, 71),
303    "TURQUOISE": Color(64, 224, 208),
304    "VIOLET": Color(238, 130, 238),
305    "WHEAT": Color(245, 222, 179),
306    "WHITE": Color(255, 255, 255),
307    "WHITESMOKE": Color(245, 245, 245),
308    "YELLOW": Color(255, 255, 0),
309    "YELLOWGREEN": Color(154, 205, 50)
310}
311