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*
pango_color_copy(const PangoColor * src)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
pango_color_free(PangoColor * color)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 *
pango_color_to_string(const PangoColor * color)95 pango_color_to_string (const PangoColor *color)
96 {
97   g_return_val_if_fail (color != NULL, NULL);
98 
99   return g_strdup_printf ("#%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
compare_xcolor_entries(const void * a,const void * b)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
find_color(const char * name,PangoColor * color)176 find_color(const char *name,
177 	   PangoColor *color)
178 {
179   ColorEntry *found;
180 
181   found = bsearch (name, color_entries, G_N_ELEMENTS (color_entries),
182 		   sizeof (ColorEntry),
183 		   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
hex(const char * spec,int len,unsigned int * c)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 (*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
pango_color_parse_with_alpha(PangoColor * color,guint16 * alpha,const char * spec)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 (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, &r) ||
281           !hex (spec + len, len, &g) ||
282           !hex (spec + len * 2, len, &b) ||
283           (has_alpha && !hex (spec + len * 3, len, &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 (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
pango_color_parse(PangoColor * color,const char * spec)344 pango_color_parse (PangoColor *color,
345                    const char *spec)
346 {
347   return pango_color_parse_with_alpha (color, NULL, spec);
348 }
349