1 | /* pango |
2 | * pango-color.c: Color handling |
3 | * |
4 | * Copyright (C) 2000 Red Hat Software |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Library General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the License, or (at your option) any later version. |
10 | * |
11 | * This library is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Library General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Library General Public |
17 | * License along with this library; if not, write to the |
18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
19 | * Boston, MA 02111-1307, USA. |
20 | */ |
21 | |
22 | #include "config.h" |
23 | #include <stdio.h> |
24 | #include <stdlib.h> |
25 | #include <string.h> |
26 | |
27 | #include "pango-attributes.h" |
28 | #include "pango-impl-utils.h" |
29 | #include "pango-utils-internal.h" |
30 | |
31 | G_DEFINE_BOXED_TYPE (PangoColor, pango_color, |
32 | pango_color_copy, |
33 | pango_color_free); |
34 | |
35 | /** |
36 | * pango_color_copy: |
37 | * @src: (nullable): color to copy |
38 | * |
39 | * Creates a copy of @src. |
40 | * |
41 | * The copy should be freed with [method@Pango.Color.free]. |
42 | * Primarily used by language bindings, not that useful |
43 | * otherwise (since colors can just be copied by assignment |
44 | * in C). |
45 | * |
46 | * Return value: (nullable): the newly allocated `PangoColor`, |
47 | * which should be freed with [method@Pango.Color.free] |
48 | */ |
49 | PangoColor* |
50 | pango_color_copy (const PangoColor *src) |
51 | { |
52 | PangoColor *ret; |
53 | |
54 | if (src == NULL) |
55 | return NULL; |
56 | |
57 | ret = g_slice_new (PangoColor); |
58 | |
59 | *ret = *src; |
60 | |
61 | return ret; |
62 | } |
63 | |
64 | /** |
65 | * pango_color_free: |
66 | * @color: (nullable): an allocated `PangoColor` |
67 | * |
68 | * Frees a color allocated by [method@Pango.Color.copy]. |
69 | */ |
70 | void |
71 | pango_color_free (PangoColor *color) |
72 | { |
73 | if (color == NULL) |
74 | return; |
75 | |
76 | g_slice_free (PangoColor, color); |
77 | } |
78 | |
79 | /** |
80 | * pango_color_to_string: |
81 | * @color: a `PangoColor` |
82 | * |
83 | * Returns a textual specification of @color. |
84 | * |
85 | * The string is in the hexadecimal form `#rrrrggggbbbb`, |
86 | * where `r`, `g` and `b` are hex digits representing the |
87 | * red, green, and blue components respectively. |
88 | * |
89 | * Return value: a newly-allocated text string that must |
90 | * be freed with g_free(). |
91 | * |
92 | * Since: 1.16 |
93 | */ |
94 | gchar * |
95 | pango_color_to_string (const PangoColor *color) |
96 | { |
97 | g_return_val_if_fail (color != NULL, NULL); |
98 | |
99 | return g_strdup_printf (format: "#%04x%04x%04x" , color->red, color->green, color->blue); |
100 | } |
101 | |
102 | /* Color parsing |
103 | */ |
104 | |
105 | /* The following 2 routines (parse_color, find_color) come from Tk, via the Win32 |
106 | * port of GDK. The licensing terms on these (longer than the functions) is: |
107 | * |
108 | * This software is copyrighted by the Regents of the University of |
109 | * California, Sun Microsystems, Inc., and other parties. The following |
110 | * terms apply to all files associated with the software unless explicitly |
111 | * disclaimed in individual files. |
112 | * |
113 | * The authors hereby grant permission to use, copy, modify, distribute, |
114 | * and license this software and its documentation for any purpose, provided |
115 | * that existing copyright notices are retained in all copies and that this |
116 | * notice is included verbatim in any distributions. No written agreement, |
117 | * license, or royalty fee is required for any of the authorized uses. |
118 | * Modifications to this software may be copyrighted by their authors |
119 | * and need not follow the licensing terms described here, provided that |
120 | * the new terms are clearly indicated on the first page of each file where |
121 | * they apply. |
122 | * |
123 | * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY |
124 | * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
125 | * ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY |
126 | * DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE |
127 | * POSSIBILITY OF SUCH DAMAGE. |
128 | * |
129 | * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, |
130 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, |
131 | * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE |
132 | * IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE |
133 | * NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR |
134 | * MODIFICATIONS. |
135 | * |
136 | * GOVERNMENT USE: If you are acquiring this software on behalf of the |
137 | * U.S. government, the Government shall have only "Restricted Rights" |
138 | * in the software and related documentation as defined in the Federal |
139 | * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you |
140 | * are acquiring the software on behalf of the Department of Defense, the |
141 | * software shall be classified as "Commercial Computer Software" and the |
142 | * Government shall have only "Restricted Rights" as defined in Clause |
143 | * 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the |
144 | * authors grant the U.S. Government and others acting in its behalf |
145 | * permission to use and distribute the software in accordance with the |
146 | * terms specified in this license. |
147 | */ |
148 | |
149 | #include "pango-color-table.h" |
150 | |
151 | #define ISUPPER(c) ((c) >= 'A' && (c) <= 'Z') |
152 | #define TOLOWER(c) (ISUPPER (c) ? (c) - 'A' + 'a' : (c)) |
153 | |
154 | static int |
155 | compare_xcolor_entries (const void *a, const void *b) |
156 | { |
157 | const guchar *s1 = (const guchar *) a; |
158 | const guchar *s2 = (const guchar *) (color_names + ((const ColorEntry *) b)->name_offset); |
159 | |
160 | while (*s1 && *s2) |
161 | { |
162 | int c1, c2; |
163 | while (*s1 == ' ') s1++; |
164 | while (*s2 == ' ') s1++; |
165 | c1 = (gint)(guchar) TOLOWER (*s1); |
166 | c2 = (gint)(guchar) TOLOWER (*s2); |
167 | if (c1 != c2) |
168 | return (c1 - c2); |
169 | s1++; s2++; |
170 | } |
171 | |
172 | return ((gint) *s1) - ((gint) *s2); |
173 | } |
174 | |
175 | static gboolean |
176 | find_color(const char *name, |
177 | PangoColor *color) |
178 | { |
179 | ColorEntry *found; |
180 | |
181 | found = bsearch (key: name, base: color_entries, G_N_ELEMENTS (color_entries), |
182 | size: sizeof (ColorEntry), |
183 | compar: compare_xcolor_entries); |
184 | if (found == NULL) |
185 | return FALSE; |
186 | |
187 | if (color) |
188 | { |
189 | color->red = (found->red * 65535) / 255; |
190 | color->green = (found->green * 65535) / 255; |
191 | color->blue = (found->blue * 65535) / 255; |
192 | } |
193 | |
194 | return TRUE; |
195 | } |
196 | |
197 | static gboolean |
198 | hex (const char *spec, |
199 | int len, |
200 | unsigned int *c) |
201 | { |
202 | const char *end; |
203 | *c = 0; |
204 | for (end = spec + len; spec != end; spec++) |
205 | if (g_ascii_isxdigit (*spec)) |
206 | *c = (*c << 4) | g_ascii_xdigit_value (c: *spec); |
207 | else |
208 | return FALSE; |
209 | return TRUE; |
210 | } |
211 | |
212 | |
213 | /** |
214 | * pango_color_parse_with_alpha: |
215 | * @color: (nullable): a `PangoColor` structure in which |
216 | * to store the result |
217 | * @alpha: (out) (optional): return location for alpha |
218 | * @spec: a string specifying the new color |
219 | * |
220 | * Fill in the fields of a color from a string specification. |
221 | * |
222 | * The string can either one of a large set of standard names. |
223 | * (Taken from the CSS Color [specification](https://www.w3.org/TR/css-color-4/#named-colors), |
224 | * or it can be a hexadecimal value in the form `#rgb`, |
225 | * `#rrggbb`, `#rrrgggbbb` or `#rrrrggggbbbb` where `r`, `g` |
226 | * and `b` are hex digits of the red, green, and blue components |
227 | * of the color, respectively. (White in the four forms is |
228 | * `#fff`, `#ffffff`, `#fffffffff` and `#ffffffffffff`.) |
229 | * |
230 | * Additionally, parse strings of the form `#rgba`, `#rrggbbaa`, |
231 | * `#rrrrggggbbbbaaaa`, if @alpha is not %NULL, and set @alpha |
232 | * to the value specified by the hex digits for `a`. If no alpha |
233 | * component is found in @spec, @alpha is set to 0xffff (for a |
234 | * solid color). |
235 | * |
236 | * Return value: %TRUE if parsing of the specifier succeeded, |
237 | * otherwise %FALSE |
238 | * |
239 | * Since: 1.46 |
240 | */ |
241 | gboolean |
242 | pango_color_parse_with_alpha (PangoColor *color, |
243 | guint16 *alpha, |
244 | const char *spec) |
245 | { |
246 | g_return_val_if_fail (spec != NULL, FALSE); |
247 | |
248 | if (alpha) |
249 | *alpha = 0xffff; |
250 | |
251 | if (spec[0] == '#') |
252 | { |
253 | size_t len; |
254 | unsigned int r, g, b, a; |
255 | gboolean has_alpha; |
256 | |
257 | spec++; |
258 | len = strlen (s: spec); |
259 | switch (len) |
260 | { |
261 | case 3: |
262 | case 6: |
263 | case 9: |
264 | case 12: |
265 | len /= 3; |
266 | has_alpha = FALSE; |
267 | break; |
268 | case 4: |
269 | case 8: |
270 | case 16: |
271 | if (!alpha) |
272 | return FALSE; |
273 | len /= 4; |
274 | has_alpha = TRUE; |
275 | break; |
276 | default: |
277 | return FALSE; |
278 | } |
279 | |
280 | if (!hex (spec, len, c: &r) || |
281 | !hex (spec: spec + len, len, c: &g) || |
282 | !hex (spec: spec + len * 2, len, c: &b) || |
283 | (has_alpha && !hex (spec: spec + len * 3, len, c: &a))) |
284 | return FALSE; |
285 | |
286 | if (color) |
287 | { |
288 | int bits = len * 4; |
289 | r <<= 16 - bits; |
290 | g <<= 16 - bits; |
291 | b <<= 16 - bits; |
292 | while (bits < 16) |
293 | { |
294 | r |= (r >> bits); |
295 | g |= (g >> bits); |
296 | b |= (b >> bits); |
297 | bits *= 2; |
298 | } |
299 | color->red = r; |
300 | color->green = g; |
301 | color->blue = b; |
302 | } |
303 | |
304 | if (alpha && has_alpha) |
305 | { |
306 | int bits = len * 4; |
307 | a <<= 16 - bits; |
308 | while (bits < 16) |
309 | { |
310 | a |= (a >> bits); |
311 | bits *= 2; |
312 | } |
313 | *alpha = a; |
314 | } |
315 | } |
316 | else |
317 | { |
318 | if (!find_color (name: spec, color)) |
319 | return FALSE; |
320 | } |
321 | return TRUE; |
322 | } |
323 | |
324 | /** |
325 | * pango_color_parse: |
326 | * @color: (nullable): a `PangoColor` structure in which |
327 | * to store the result |
328 | * @spec: a string specifying the new color |
329 | * |
330 | * Fill in the fields of a color from a string specification. |
331 | * |
332 | * The string can either one of a large set of standard names. |
333 | * (Taken from the CSS Color [specification](https://www.w3.org/TR/css-color-4/#named-colors), |
334 | * or it can be a value in the form `#rgb`, `#rrggbb`, |
335 | * `#rrrgggbbb` or `#rrrrggggbbbb`, where `r`, `g` and `b` |
336 | * are hex digits of the red, green, and blue components |
337 | * of the color, respectively. (White in the four forms is |
338 | * `#fff`, `#ffffff`, `#fffffffff` and `#ffffffffffff`.) |
339 | * |
340 | * Return value: %TRUE if parsing of the specifier succeeded, |
341 | * otherwise %FALSE |
342 | */ |
343 | gboolean |
344 | pango_color_parse (PangoColor *color, |
345 | const char *spec) |
346 | { |
347 | return pango_color_parse_with_alpha (color, NULL, spec); |
348 | } |
349 | |