source: trunk/third/librsvg/rsvg-css.c @ 18275

Revision 18275, 14.3 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18274, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2   rsvg-css.c: Parse CSS basic data types.
3 
4   Copyright (C) 2000 Eazel, Inc.
5 
6   This program is free software; you can redistribute it and/or
7   modify it under the terms of the GNU Library General Public License as
8   published by the Free Software Foundation; either version 2 of the
9   License, or (at your option) any later version.
10 
11   This program 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 program; if not, write to the
18   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19   Boston, MA 02111-1307, USA.
20 
21   Author: Raph Levien <raph@artofcode.com>
22*/
23
24#include "config.h"
25#include "rsvg-css.h"
26
27#include <glib.h>
28#include <math.h>
29#include <stdlib.h>
30#include <string.h>
31#include <errno.h>
32#include <stdio.h>
33
34#define POINTS_PER_INCH (72.0)
35#define CM_PER_INCH     (2.54)
36#define MM_PER_INCH     (25.4)
37#define PICA_PER_INCH   (6.0)
38
39/**
40 * rsvg_css_parse_length: Parse CSS2 length to a pixel value.
41 * @str: Original string.
42 * @pixels_per_inch: Pixels per inch
43 * @fixed: Where to store boolean value of whether length is fixed.
44 *
45 * Parses a CSS2 length into a pixel value.
46 *
47 * Returns: returns the length.
48 **/
49double
50rsvg_css_parse_length (const char *str, gdouble pixels_per_inch,
51                       gint *percent, gint *em, gint *ex)
52{
53  double length = 0.0;
54  char *p = NULL;
55 
56  /*
57   *  The supported CSS length unit specifiers are:
58   *  em, ex, px, pt, pc, cm, mm, in, and %
59   */
60  *percent = FALSE;
61  *em      = FALSE;
62  *ex      = FALSE;
63
64  length = g_ascii_strtod (str, &p);
65 
66  /* todo: error condition - figure out how to best represent it */
67  if ((length == -HUGE_VAL || length == HUGE_VAL) && (ERANGE == errno))
68    {
69      return 0.0;
70    }
71
72  /* test for either pixels or no unit, which is assumed to be pixels */
73  if (p && (strcmp(p, "px") != 0))
74    {
75      if (!strcmp(p, "pt"))
76        length *= (pixels_per_inch / POINTS_PER_INCH);
77      else if (!strcmp(p, "in"))
78        length *= pixels_per_inch;
79      else if (!strcmp(p, "cm"))
80        length *= (pixels_per_inch / CM_PER_INCH);
81      else if (!strcmp(p, "mm"))
82        length *= (pixels_per_inch / MM_PER_INCH);
83      else if (!strcmp(p, "pc"))
84        length *= (pixels_per_inch / PICA_PER_INCH);
85      else if (!strcmp(p, "em"))
86        *em = TRUE;
87      else if (!strcmp(p, "ex"))
88        *ex = TRUE;
89      else if (!strcmp(p, "%"))
90        {
91          *percent = TRUE;
92          length *= 0.01;
93        }
94    }
95
96  return length;
97}
98
99/**
100 * rsvg_css_parse_normalized_length: Parse CSS2 length to a pixel value.
101 * @str: Original string.
102 * @pixels_per_inch: Pixels per inch
103 * @normalize_to: Bounding box's width or height, as appropriate, or 0
104 *
105 * Parses a CSS2 length into a pixel value.
106 *
107 * Returns: returns the length.
108 */
109double
110rsvg_css_parse_normalized_length(const char *str, gdouble pixels_per_inch,
111                                 gdouble width_or_height, gdouble font_size,
112                                 gdouble x_height)
113{
114  double length;
115  gint percent, em, ex;
116  percent = em = ex = FALSE;
117
118  length = rsvg_css_parse_length (str, pixels_per_inch, &percent, &em, &ex);
119  if (percent)
120    return length * width_or_height;
121  else if (em)
122    return length * font_size;
123  else if (ex)
124    return length * x_height;
125  else
126    return length;
127}
128
129gboolean
130rsvg_css_param_match (const char *str, const char *param_name)
131{
132  int i;
133
134  for (i = 0; str[i] != '\0' && str[i] != ':'; i++)
135    if (param_name[i] != str[i])
136      return FALSE;
137  return str[i] == ':' && param_name[i] == '\0';
138}
139
140int
141rsvg_css_param_arg_offset (const char *str)
142{
143  int i;
144
145  for (i = 0; str[i] != '\0' && str[i] != ':'; i++);
146  if (str[i] != '\0') i++;
147  for (; str[i] == ' '; i++);
148  return i;
149}
150
151static gint
152rsvg_css_clip_rgb_percent (gint in_percent)
153{
154  /* spec says to clip these values */
155  if (in_percent > 100)
156    in_percent = 100;
157  else if (in_percent <= 0)
158    return 0;
159
160  return (gint)floor(255. * (double)in_percent / 100.);
161}
162
163static gint
164rsvg_css_clip_rgb (gint rgb)
165{
166  /* spec says to clip these values */
167  if (rgb > 255)
168    rgb = 255;
169  else if (rgb < 0)
170    rgb = 0;
171
172  return rgb;
173}
174
175typedef struct
176{
177  const char * name;
178  guint rgb;
179} ColorPair;
180
181/* compare function callback for bsearch */
182static int
183rsvg_css_color_compare (const void * a, const void * b)
184{
185  const char * needle = (const char *)a;
186  const ColorPair * haystack = (const ColorPair *)b;
187
188  return g_ascii_strcasecmp (needle, haystack->name);
189}
190
191/* pack 3 [0,255] ints into one 32 bit one */
192#define PACK_RGB(r,g,b) (((r) << 16) | ((g) << 8) | (b))
193
194/**
195 * Parse a CSS2 color specifier, return RGB value
196 */
197guint32
198rsvg_css_parse_color (const char *str)
199{
200  gint val = 0;
201
202  if (str[0] == '#')
203    {
204      int i;
205      for (i = 1; str[i]; i++)
206        {
207          int hexval;
208          if (str[i] >= '0' && str[i] <= '9')
209            hexval = str[i] - '0';
210          else if (str[i] >= 'A' && str[i] <= 'F')
211            hexval = str[i] - 'A' + 10;
212          else if (str[i] >= 'a' && str[i] <= 'f')
213            hexval = str[i] - 'a' + 10;
214          else
215            break;
216          val = (val << 4) + hexval;
217        }
218      /* handle #rgb case */
219      if (i == 4)
220        {
221          val = ((val & 0xf00) << 8) |
222            ((val & 0x0f0) << 4) |
223            (val & 0x00f);
224          val |= val << 4;
225        }
226    }
227  /* i want to use g_str_has_prefix but it isn't in my gstrfuncs.h?? */
228  else if (strstr (str, "rgb") != NULL)
229    {
230      gint r, g, b;
231      r = g = b = 0;
232
233      if (strstr (str, "%") != 0)
234        {
235          /* assume "rgb (r%, g%, b%)" */
236          if (3 == sscanf (str, " rgb ( %d %% , %d %% , %d %% ) ", &r, &g, &b))
237            {
238              r = rsvg_css_clip_rgb_percent (r);
239              g = rsvg_css_clip_rgb_percent (g);
240              b = rsvg_css_clip_rgb_percent (b);
241            }
242          else
243              r = g = b = 0;
244        }
245      else
246        {
247          /* assume "rgb (r, g, b)" */
248          if (3 == sscanf (str, " rgb ( %d , %d , %d ) ", &r, &g, &b))
249            {
250              r = rsvg_css_clip_rgb (r);
251              g = rsvg_css_clip_rgb (g);
252              b = rsvg_css_clip_rgb (b);
253            }
254          else
255            r = g = b = 0;
256        }
257
258      val = PACK_RGB (r,g,b);
259    }
260  else
261    {
262      const static ColorPair color_list [] =
263        {
264          { "aliceblue",            PACK_RGB (240,248,255) },
265          { "antiquewhite",         PACK_RGB (250,235,215) },
266          { "aqua",                 PACK_RGB (0,255,255) },
267          { "aquamarine",           PACK_RGB (127,255,212) },
268          { "azure",                PACK_RGB (240,255,255) },
269          { "beige",                PACK_RGB (245,245,220) },
270          { "bisque",               PACK_RGB (255,228,196) },
271          { "black",                PACK_RGB (0,0,0) },
272          { "blanchedalmond",       PACK_RGB (255,235,205) },
273          { "blue",                 PACK_RGB (0,0,255) },
274          { "blueviolet",           PACK_RGB (138,43,226) },
275          { "brown",                PACK_RGB (165,42,42) },
276          { "burlywood",            PACK_RGB (222,184,135) },
277          { "cadetblue",            PACK_RGB (95,158,160) },
278          { "chartreuse",           PACK_RGB (127,255,0) },
279          { "chocolate",            PACK_RGB (210,105,30) },
280          { "coral",                PACK_RGB (255,127,80) },
281          { "cornflowerblue",       PACK_RGB (100,149,237) },
282          { "cornsilk",             PACK_RGB (255,248,220) },
283          { "crimson",              PACK_RGB (220,20,60) },
284          { "cyan",                 PACK_RGB (0,255,255) },
285          { "darkblue",             PACK_RGB (0,0,139) },
286          { "darkcyan",             PACK_RGB (0,139,139) },
287          { "darkgoldenrod",        PACK_RGB (184,132,11) },
288          { "darkgray",             PACK_RGB (169,169,168) },
289          { "darkgreen",            PACK_RGB (0,100,0) },
290          { "darkgrey",             PACK_RGB (169,169,169) },
291          { "darkkhaki",            PACK_RGB (189,183,107) },
292          { "darkmagenta",          PACK_RGB (139,0,139) },
293          { "darkolivegreen",       PACK_RGB (85,107,47) },
294          { "darkorange",           PACK_RGB (255,140,0) },
295          { "darkorchid",           PACK_RGB (153,50,204) },
296          { "darkred",              PACK_RGB (139,0,0) },
297          { "darksalmon",           PACK_RGB (233,150,122) },
298          { "darkseagreen",         PACK_RGB (143,188,143) },
299          { "darkslateblue",        PACK_RGB (72,61,139) },
300          { "darkslategray",        PACK_RGB (47,79,79) },
301          { "darkslategrey",        PACK_RGB (47,79,79) },
302          { "darkturquoise",        PACK_RGB (0,206,209) },
303          { "darkviolet",           PACK_RGB (148,0,211) },
304          { "deeppink",             PACK_RGB (255,20,147) },
305          { "deepskyblue",          PACK_RGB (0,191,255) },
306          { "dimgray",              PACK_RGB (105,105,105) },
307          { "dimgrey",              PACK_RGB (105,105,105) },
308          { "dogerblue",            PACK_RGB (30,144,255) },
309          { "firebrick",            PACK_RGB (178,34,34) },
310          { "floralwhite" ,         PACK_RGB (255,255,240)},
311          { "forestgreen",          PACK_RGB (34,139,34) },
312          { "fuchsia",              PACK_RGB (255,0,255) },
313          { "gainsboro",            PACK_RGB (220,220,220) },
314          { "ghostwhite",           PACK_RGB (248,248,255) },
315          { "gold",                 PACK_RGB (215,215,0) },
316          { "goldenrod",            PACK_RGB (218,165,32) },
317          { "gray",                 PACK_RGB (128,128,128) },
318          { "grey",                 PACK_RGB (128,128,128) },
319          { "green",                PACK_RGB (0,128,0)},
320          { "greenyellow",          PACK_RGB (173,255,47) },
321          { "honeydew",             PACK_RGB (240,255,240) },
322          { "hotpink",              PACK_RGB (255,105,180) },
323          { "indianred",            PACK_RGB (205,92,92) },
324          { "indigo",               PACK_RGB (75,0,130) },
325          { "ivory",                PACK_RGB (255,255,240) },
326          { "khaki",                PACK_RGB (240,230,140) },
327          { "lavender",             PACK_RGB (230,230,250) },
328          { "lavenderblush",        PACK_RGB (255,240,245) },
329          { "lawngreen",            PACK_RGB (124,252,0) },
330          { "lemonchiffon",         PACK_RGB (255,250,205) },
331          { "lightblue",            PACK_RGB (173,216,230) },
332          { "lightcoral",           PACK_RGB (240,128,128) },
333          { "lightcyan",            PACK_RGB (224,255,255) },
334          { "lightgoldenrodyellow", PACK_RGB (250,250,210) },
335          { "lightgray",            PACK_RGB (211,211,211) },
336          { "lightgreen",           PACK_RGB (144,238,144) },
337          { "lightgrey",            PACK_RGB (211,211,211) },
338          { "lightpink",            PACK_RGB (255,182,193) },
339          { "lightsalmon",          PACK_RGB (255,160,122) },
340          { "lightseagreen",        PACK_RGB (32,178,170) },
341          { "lightskyblue",         PACK_RGB (135,206,250) },
342          { "lightslategray",       PACK_RGB (119,136,153) },
343          { "lightslategrey",       PACK_RGB (119,136,153) },
344          { "lightsteelblue",       PACK_RGB (176,196,222) },
345          { "lightyellow",          PACK_RGB (255,255,224) },
346          { "lime",                 PACK_RGB (0,255,0) },
347          { "limegreen",            PACK_RGB (50,205,50) },
348          { "linen",                PACK_RGB (250,240,230) },
349          { "magenta",              PACK_RGB (255,0,255) },
350          { "maroon",               PACK_RGB (128,0,0) },
351          { "mediumaquamarine",     PACK_RGB (102,205,170) },
352          { "mediumblue",           PACK_RGB (0,0,205) },
353          { "mediumorchid",         PACK_RGB (186,85,211) },
354          { "mediumpurple",         PACK_RGB (147,112,219) },
355          { "mediumseagreen",       PACK_RGB (60,179,113) },
356          { "mediumslateblue",      PACK_RGB (123,104,238) },
357          { "mediumspringgreen",    PACK_RGB (0,250,154) },
358          { "mediumturquoise",      PACK_RGB (72,209,204) },
359          { "mediumvioletred",      PACK_RGB (199,21,133) },
360          { "mediumnightblue",      PACK_RGB (25,25,112) },
361          { "mintcream",            PACK_RGB (245,255,250) },
362          { "mintyrose",            PACK_RGB (255,228,225) },
363          { "moccasin",             PACK_RGB (255,228,181) },
364          { "navajowhite",          PACK_RGB (255,222,173) },
365          { "navy",                 PACK_RGB (0,0,128) },
366          { "oldlace",              PACK_RGB (253,245,230) },
367          { "olive",                PACK_RGB (128,128,0) },
368          { "oliverab",             PACK_RGB (107,142,35) },
369          { "orange",               PACK_RGB (255,165,0) },
370          { "orangered",            PACK_RGB (255,69,0) },
371          { "orchid",               PACK_RGB (218,112,214) },
372          { "palegoldenrod",        PACK_RGB (238,232,170) },
373          { "palegreen",            PACK_RGB (152,251,152) },
374          { "paleturquoise",        PACK_RGB (175,238,238) },
375          { "palevioletred",        PACK_RGB (219,112,147) },
376          { "papayawhip",           PACK_RGB (255,239,213) },
377          { "peachpuff",            PACK_RGB (255,218,185) },
378          { "peru",                 PACK_RGB (205,133,63) },
379          { "pink",                 PACK_RGB (255,192,203) },
380          { "plum",                 PACK_RGB (221,160,203) },
381          { "powderblue",           PACK_RGB (176,224,230) },
382          { "purple",               PACK_RGB (128,0,128) },
383          { "red",                  PACK_RGB (255,0,0) },
384          { "rosybrown",            PACK_RGB (188,143,143) },
385          { "royalblue",            PACK_RGB (65,105,225) },
386          { "saddlebrown",          PACK_RGB (139,69,19) },
387          { "salmon",               PACK_RGB (250,128,114) },
388          { "sandybrown",           PACK_RGB (244,164,96) },
389          { "seagreen",             PACK_RGB (46,139,87) },
390          { "seashell",             PACK_RGB (255,245,238) },
391          { "sienna",               PACK_RGB (160,82,45) },
392          { "silver",               PACK_RGB (192,192,192) },
393          { "skyblue",              PACK_RGB (135,206,235) },
394          { "slateblue",            PACK_RGB (106,90,205) },
395          { "slategray",            PACK_RGB (112,128,144) },
396          { "slategrey",            PACK_RGB (112,128,114) },
397          { "snow",                 PACK_RGB (255,255,250) },
398          { "springgreen",          PACK_RGB (0,255,127) },
399          { "steelblue",            PACK_RGB (70,130,180) },
400          { "tan",                  PACK_RGB (210,180,140) },
401          { "teal",                 PACK_RGB (0,128,128) },
402          { "thistle",              PACK_RGB (216,191,216) },
403          { "tomato",               PACK_RGB (255,99,71) },
404          { "turquoise",            PACK_RGB (64,224,208) },
405          { "violet",               PACK_RGB (238,130,238) },
406          { "wheat",                PACK_RGB (245,222,179) },
407          { "white",                PACK_RGB (255,255,255) },
408          { "whitesmoke",           PACK_RGB (245,245,245) },
409          { "yellow",               PACK_RGB (255,255,0) },
410          { "yellowgreen",          PACK_RGB (154,205,50) }
411        };
412
413      ColorPair * result = bsearch (str, color_list,
414                                    sizeof (color_list)/sizeof (color_list[0]),
415                                    sizeof (ColorPair),
416                                    rsvg_css_color_compare);
417
418      /* default to black on failed lookup */
419      if (result == NULL)
420        val = 0;
421      else
422        val = result->rgb;
423    }
424
425  return val;
426}
427
428#undef PACK_RGB
429
430guint
431rsvg_css_parse_opacity (const char *str)
432{
433  char *end_ptr;
434  double opacity;
435
436  opacity = g_ascii_strtod (str, &end_ptr);
437
438  if (end_ptr && end_ptr[0] == '%')
439    opacity *= 0.01;
440
441  return (guint)floor (opacity * 255 + 0.5);
442}
Note: See TracBrowser for help on using the repository browser.