NetSurf
hints.c
Go to the documentation of this file.
1/*
2 * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * NetSurf is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <string.h>
20#include <strings.h>
21
22#include "utils/nsoption.h"
23#include "utils/corestrings.h"
24#include "utils/log.h"
25#include "utils/nsurl.h"
26#include "utils/utils.h"
27
28#include "css/hints.h"
29#include "css/select.h"
30
31#define LOG_STATS
32#undef LOG_STATS
33
34/******************************************************************************
35 * Utility functions *
36 ******************************************************************************/
37
38/**
39 * Determine if a given character is whitespace
40 *
41 * \param c Character to consider
42 * \return true if character is whitespace, false otherwise
43 */
44static bool isWhitespace(char c)
45{
46 return c == ' ' || c == '\t' || c == '\f' || c == '\r' || c == '\n';
47}
48
49/**
50 * Determine if a given character is a valid hex digit
51 *
52 * \param c Character to consider
53 * \return true if character is a valid hex digit, false otherwise
54 */
55static bool isHex(char c)
56{
57 return ('0' <= c && c <= '9') ||
58 ('A' <= (c & ~0x20) && (c & ~0x20) <= 'F');
59}
60
61/**
62 * Convert a character representing a hex digit to the corresponding hex value
63 *
64 * \param c Character to convert
65 * \return Hex value represented by character
66 *
67 * \note This function assumes an ASCII-compatible character set
68 */
69static uint8_t charToHex(char c)
70{
71 /* 0-9 */
72 c -= '0';
73
74 /* A-F */
75 if (c > 9)
76 c -= 'A' - '9' - 1;
77
78 /* a-f */
79 if (c > 15)
80 c -= 'a' - 'A';
81
82 return c;
83}
84
85
86/******************************************************************************
87 * Common parsing functions *
88 ******************************************************************************/
89
90/**
91 * Parse a number string
92 *
93 * \param data Data to parse (NUL-terminated)
94 * \param maybe_negative Negative numbers permitted
95 * \param real Floating point numbers permitted
96 * \param value Pointer to location to receive numeric value
97 * \param consumed Pointer to location to receive number of input
98 * bytes consumed
99 * \return true on success, false on invalid input
100 */
101static bool parse_number(const char *data, bool maybe_negative, bool real,
102 css_fixed *value, size_t *consumed)
103{
104 size_t len;
105 const uint8_t *ptr;
106 int32_t intpart = 0;
107 int32_t fracpart = 0;
108 int32_t pwr = 1;
109 int sign = 1;
110
111 *consumed = 0;
112
113 len = strlen(data);
114 ptr = (const uint8_t *) data;
115
116 if (len == 0)
117 return false;
118
119 /* Skip leading whitespace */
120 while (len > 0 && isWhitespace(ptr[0])) {
121 len--;
122 ptr++;
123 }
124
125 if (len == 0)
126 return false;
127
128 /* Extract sign, if any */
129 if (ptr[0] == '+') {
130 len--;
131 ptr++;
132 } else if (ptr[0] == '-' && maybe_negative) {
133 sign = -1;
134 len--;
135 ptr++;
136 }
137
138 if (len == 0)
139 return false;
140
141 /* Must have a digit [0,9] */
142 if ('0' > ptr[0] || ptr[0] > '9')
143 return false;
144
145 /* Now extract intpart, assuming base 10 */
146 while (len > 0) {
147 /* Stop on first non-digit */
148 if (ptr[0] < '0' || '9' < ptr[0])
149 break;
150
151 /* Prevent overflow of 'intpart'; proper clamping below */
152 if (intpart < (1 << 22)) {
153 intpart *= 10;
154 intpart += ptr[0] - '0';
155 }
156 ptr++;
157 len--;
158 }
159
160 /* And fracpart, again, assuming base 10 */
161 if (real && len > 1 && ptr[0] == '.' &&
162 ('0' <= ptr[1] && ptr[1] <= '9')) {
163 ptr++;
164 len--;
165
166 while (len > 0) {
167 if (ptr[0] < '0' || '9' < ptr[0])
168 break;
169
170 if (pwr < 1000000) {
171 pwr *= 10;
172 fracpart *= 10;
173 fracpart += ptr[0] - '0';
174 }
175 ptr++;
176 len--;
177 }
178
179 fracpart = ((1 << 10) * fracpart + pwr/2) / pwr;
180 if (fracpart >= (1 << 10)) {
181 intpart++;
182 fracpart &= (1 << 10) - 1;
183 }
184 }
185
186 if (sign > 0) {
187 /* If the result is larger than we can represent,
188 * then clamp to the maximum value we can store. */
189 if (intpart >= (1 << 21)) {
190 intpart = (1 << 21) - 1;
191 fracpart = (1 << 10) - 1;
192 }
193 } else {
194 /* If the negated result is smaller than we can represent
195 * then clamp to the minimum value we can store. */
196 if (intpart >= (1 << 21)) {
197 intpart = -(1 << 21);
198 fracpart = 0;
199 } else {
200 intpart = -intpart;
201 if (fracpart) {
202 fracpart = (1 << 10) - fracpart;
203 intpart--;
204 }
205 }
206 }
207
208 *value = (intpart << 10) | fracpart;
209
210 *consumed = ptr - (const uint8_t *) data;
211
212 return true;
213}
214
215/**
216 * Parse a dimension string
217 *
218 * \param data Data to parse (NUL-terminated)
219 * \param strict Whether to enforce strict parsing rules
220 * \param length Pointer to location to receive dimension's length
221 * \param unit Pointer to location to receive dimension's unit
222 * \return true on success, false on invalid input
223 */
224static bool parse_dimension(const char *data, bool strict, css_fixed *length,
225 css_unit *unit)
226{
227 size_t len;
228 size_t read;
229 css_fixed value;
230
231 len = strlen(data);
232
233 if (parse_number(data, false, true, &value, &read) == false)
234 return false;
235
236 if (strict && value < INTTOFIX(1))
237 return false;
238
239 *length = value;
240
241 if (len > read && data[read] == '%')
242 *unit = CSS_UNIT_PCT;
243 else
244 *unit = CSS_UNIT_PX;
245
246 return true;
247}
248
249/**
250 * Mapping of colour name to CSS color
251 */
253 const char *name;
254 css_color color;
255};
256
257/**
258 * Name comparator for named colour matching
259 *
260 * \param a Name to match
261 * \param b Colour map entry to consider
262 * \return 0 on match,
263 * < 0 if a < b,
264 * > 0 if b > a.
265 */
266static int cmp_colour_name(const void *a, const void *b)
267{
268 const char *aa = a;
269 const struct colour_map *bb = b;
270
271 return strcasecmp(aa, bb->name);
272}
273
274/**
275 * Parse a named colour
276 *
277 * \param name Name to parse
278 * \param result Pointer to location to receive css_color
279 * \return true on success, false on invalid input
280 */
281static bool parse_named_colour(const char *name, css_color *result)
282{
283 static const struct colour_map named_colours[] = {
284 { "aliceblue", 0xfff0f8ff },
285 { "antiquewhite", 0xfffaebd7 },
286 { "aqua", 0xff00ffff },
287 { "aquamarine", 0xff7fffd4 },
288 { "azure", 0xfff0ffff },
289 { "beige", 0xfff5f5dc },
290 { "bisque", 0xffffe4c4 },
291 { "black", 0xff000000 },
292 { "blanchedalmond", 0xffffebcd },
293 { "blue", 0xff0000ff },
294 { "blueviolet", 0xff8a2be2 },
295 { "brown", 0xffa52a2a },
296 { "burlywood", 0xffdeb887 },
297 { "cadetblue", 0xff5f9ea0 },
298 { "chartreuse", 0xff7fff00 },
299 { "chocolate", 0xffd2691e },
300 { "coral", 0xffff7f50 },
301 { "cornflowerblue", 0xff6495ed },
302 { "cornsilk", 0xfffff8dc },
303 { "crimson", 0xffdc143c },
304 { "cyan", 0xff00ffff },
305 { "darkblue", 0xff00008b },
306 { "darkcyan", 0xff008b8b },
307 { "darkgoldenrod", 0xffb8860b },
308 { "darkgray", 0xffa9a9a9 },
309 { "darkgreen", 0xff006400 },
310 { "darkgrey", 0xffa9a9a9 },
311 { "darkkhaki", 0xffbdb76b },
312 { "darkmagenta", 0xff8b008b },
313 { "darkolivegreen", 0xff556b2f },
314 { "darkorange", 0xffff8c00 },
315 { "darkorchid", 0xff9932cc },
316 { "darkred", 0xff8b0000 },
317 { "darksalmon", 0xffe9967a },
318 { "darkseagreen", 0xff8fbc8f },
319 { "darkslateblue", 0xff483d8b },
320 { "darkslategray", 0xff2f4f4f },
321 { "darkslategrey", 0xff2f4f4f },
322 { "darkturquoise", 0xff00ced1 },
323 { "darkviolet", 0xff9400d3 },
324 { "deeppink", 0xffff1493 },
325 { "deepskyblue", 0xff00bfff },
326 { "dimgray", 0xff696969 },
327 { "dimgrey", 0xff696969 },
328 { "dodgerblue", 0xff1e90ff },
329 { "feldspar", 0xffd19275 },
330 { "firebrick", 0xffb22222 },
331 { "floralwhite", 0xfffffaf0 },
332 { "forestgreen", 0xff228b22 },
333 { "fuchsia", 0xffff00ff },
334 { "gainsboro", 0xffdcdcdc },
335 { "ghostwhite", 0xfff8f8ff },
336 { "gold", 0xffffd700 },
337 { "goldenrod", 0xffdaa520 },
338 { "gray", 0xff808080 },
339 { "green", 0xff008000 },
340 { "greenyellow", 0xffadff2f },
341 { "grey", 0xff808080 },
342 { "honeydew", 0xfff0fff0 },
343 { "hotpink", 0xffff69b4 },
344 { "indianred", 0xffcd5c5c },
345 { "indigo", 0xff4b0082 },
346 { "ivory", 0xfffffff0 },
347 { "khaki", 0xfff0e68c },
348 { "lavender", 0xffe6e6fa },
349 { "lavenderblush", 0xfffff0f5 },
350 { "lawngreen", 0xff7cfc00 },
351 { "lemonchiffon", 0xfffffacd },
352 { "lightblue", 0xffadd8e6 },
353 { "lightcoral", 0xfff08080 },
354 { "lightcyan", 0xffe0ffff },
355 { "lightgoldenrodyellow", 0xfffafad2 },
356 { "lightgray", 0xffd3d3d3 },
357 { "lightgreen", 0xff90ee90 },
358 { "lightgrey", 0xffd3d3d3 },
359 { "lightpink", 0xffffb6c1 },
360 { "lightsalmon", 0xffffa07a },
361 { "lightseagreen", 0xff20b2aa },
362 { "lightskyblue", 0xff87cefa },
363 { "lightslateblue", 0xff8470ff },
364 { "lightslategray", 0xff778899 },
365 { "lightslategrey", 0xff778899 },
366 { "lightsteelblue", 0xffb0c4de },
367 { "lightyellow", 0xffffffe0 },
368 { "lime", 0xff00ff00 },
369 { "limegreen", 0xff32cd32 },
370 { "linen", 0xfffaf0e6 },
371 { "magenta", 0xffff00ff },
372 { "maroon", 0xff800000 },
373 { "mediumaquamarine", 0xff66cdaa },
374 { "mediumblue", 0xff0000cd },
375 { "mediumorchid", 0xffba55d3 },
376 { "mediumpurple", 0xff9370db },
377 { "mediumseagreen", 0xff3cb371 },
378 { "mediumslateblue", 0xff7b68ee },
379 { "mediumspringgreen", 0xff00fa9a },
380 { "mediumturquoise", 0xff48d1cc },
381 { "mediumvioletred", 0xffc71585 },
382 { "midnightblue", 0xff191970 },
383 { "mintcream", 0xfff5fffa },
384 { "mistyrose", 0xffffe4e1 },
385 { "moccasin", 0xffffe4b5 },
386 { "navajowhite", 0xffffdead },
387 { "navy", 0xff000080 },
388 { "oldlace", 0xfffdf5e6 },
389 { "olive", 0xff808000 },
390 { "olivedrab", 0xff6b8e23 },
391 { "orange", 0xffffa500 },
392 { "orangered", 0xffff4500 },
393 { "orchid", 0xffda70d6 },
394 { "palegoldenrod", 0xffeee8aa },
395 { "palegreen", 0xff98fb98 },
396 { "paleturquoise", 0xffafeeee },
397 { "palevioletred", 0xffdb7093 },
398 { "papayawhip", 0xffffefd5 },
399 { "peachpuff", 0xffffdab9 },
400 { "peru", 0xffcd853f },
401 { "pink", 0xffffc0cb },
402 { "plum", 0xffdda0dd },
403 { "powderblue", 0xffb0e0e6 },
404 { "purple", 0xff800080 },
405 { "red", 0xffff0000 },
406 { "rosybrown", 0xffbc8f8f },
407 { "royalblue", 0xff4169e1 },
408 { "saddlebrown", 0xff8b4513 },
409 { "salmon", 0xfffa8072 },
410 { "sandybrown", 0xfff4a460 },
411 { "seagreen", 0xff2e8b57 },
412 { "seashell", 0xfffff5ee },
413 { "sienna", 0xffa0522d },
414 { "silver", 0xffc0c0c0 },
415 { "skyblue", 0xff87ceeb },
416 { "slateblue", 0xff6a5acd },
417 { "slategray", 0xff708090 },
418 { "slategrey", 0xff708090 },
419 { "snow", 0xfffffafa },
420 { "springgreen", 0xff00ff7f },
421 { "steelblue", 0xff4682b4 },
422 { "tan", 0xffd2b48c },
423 { "teal", 0xff008080 },
424 { "thistle", 0xffd8bfd8 },
425 { "tomato", 0xffff6347 },
426 { "turquoise", 0xff40e0d0 },
427 { "violet", 0xffee82ee },
428 { "violetred", 0xffd02090 },
429 { "wheat", 0xfff5deb3 },
430 { "white", 0xffffffff },
431 { "whitesmoke", 0xfff5f5f5 },
432 { "yellow", 0xffffff00 },
433 { "yellowgreen", 0xff9acd32 }
434 };
435 const struct colour_map *entry;
436
437 entry = bsearch(name, named_colours,
438 sizeof(named_colours) / sizeof(named_colours[0]),
439 sizeof(named_colours[0]),
441
442 if (entry != NULL)
443 *result = entry->color;
444
445 return entry != NULL;
446}
447
448/* exported interface documented in content/handlers/css/hints.h */
449bool nscss_parse_colour(const char *data, css_color *result)
450{
451 size_t len = strlen(data);
452 uint8_t r, g, b;
453
454 /* 2 */
455 if (len == 0)
456 return false;
457
458 /* 3 */
459 if (len == SLEN("transparent") && strcasecmp(data, "transparent") == 0)
460 return false;
461
462 /* 4 */
463 if (parse_named_colour(data, result))
464 return true;
465
466 /** \todo Implement HTML5's utterly insane legacy colour parsing */
467
468 if (data[0] == '#') {
469 data++;
470 len--;
471 }
472
473 if (len == 3 && isHex(data[0]) && isHex(data[1]) && isHex(data[2])) {
474 r = charToHex(data[0]);
475 g = charToHex(data[1]);
476 b = charToHex(data[2]);
477
478 r |= (r << 4);
479 g |= (g << 4);
480 b |= (b << 4);
481
482 *result = (0xff << 24) | (r << 16) | (g << 8) | b;
483
484 return true;
485 } else if (len == 6 && isHex(data[0]) && isHex(data[1]) &&
486 isHex(data[2]) && isHex(data[3]) && isHex(data[4]) &&
487 isHex(data[5])) {
488 r = (charToHex(data[0]) << 4) | charToHex(data[1]);
489 g = (charToHex(data[2]) << 4) | charToHex(data[3]);
490 b = (charToHex(data[4]) << 4) | charToHex(data[5]);
491
492 *result = (0xff << 24) | (r << 16) | (g << 8) | b;
493
494 return true;
495 }
496
497 return false;
498}
499
500/**
501 * Parse a font \@size attribute
502 *
503 * \param size Data to parse (NUL-terminated)
504 * \param val Pointer to location to receive enum value
505 * \param len Pointer to location to receive length
506 * \param unit Pointer to location to receive unit
507 * \return True on success, false on failure
508 */
509static bool parse_font_size(const char *size, uint8_t *val,
510 css_fixed *len, css_unit *unit)
511{
512 static const uint8_t size_map[] = {
513 CSS_FONT_SIZE_XX_SMALL,
514 CSS_FONT_SIZE_SMALL,
515 CSS_FONT_SIZE_MEDIUM,
516 CSS_FONT_SIZE_LARGE,
517 CSS_FONT_SIZE_X_LARGE,
518 CSS_FONT_SIZE_XX_LARGE,
519 CSS_FONT_SIZE_DIMENSION /* xxx-large (see below) */
520 };
521
522 const char *p = size;
523 char mode;
524 int value = 0;
525
526 /* Skip whitespace */
527 while (*p != '\0' && isWhitespace(*p))
528 p++;
529
530 mode = *p;
531
532 /* Skip +/- */
533 if (mode == '+' || mode == '-')
534 p++;
535
536 /* Need at least one digit */
537 if (*p < '0' || *p > '9') {
538 return false;
539 }
540
541 /* Consume digits, computing value */
542 while ('0' <= *p && *p <= '9') {
543 value = value * 10 + (*p - '0');
544 p++;
545 }
546
547 /* Resolve relative sizes */
548 if (mode == '+')
549 value += 3;
550 else if (mode == '-')
551 value = 3 - value;
552
553 /* Clamp to range [1,7] */
554 if (value < 1)
555 value = 1;
556 else if (value > 7)
557 value = 7;
558
559 if (value == 7) {
560 /* Manufacture xxx-large */
561 *len = FDIV(FMUL(INTTOFIX(3), INTTOFIX(nsoption_int(font_size))),
562 F_10);
563 } else {
564 /* Len is irrelevant */
565 *len = 0;
566 }
567
568 *unit = CSS_UNIT_PT;
569 *val = size_map[value - 1];
570
571 return true;
572}
573
574
575/******************************************************************************
576 * Hint context management *
577 ******************************************************************************/
578
579#define MAX_HINTS_PER_ELEMENT 32
580
582 struct css_hint *hints;
583 uint32_t len;
584};
585
587
589{
590 hint_ctx.hints = malloc(sizeof(struct css_hint) *
592 if (hint_ctx.hints == NULL) {
593 return NSERROR_NOMEM;
594 }
595
596 return NSERROR_OK;
597}
598
600{
601 hint_ctx.len = 0;
602 free(hint_ctx.hints);
603}
604
605static void css_hint_clean(void)
606{
607 hint_ctx.len = 0;
608}
609
610static inline void css_hint_advance(struct css_hint **hint)
611{
612 hint_ctx.len++;
614
615 (*hint)++;
616}
617
618static void css_hint_get_hints(struct css_hint **hints, uint32_t *nhints)
619{
621 *nhints = hint_ctx.len;
622}
623
624
625/******************************************************************************
626 * Presentational hint handlers *
627 ******************************************************************************/
628
630 nscss_select_ctx *ctx,
631 dom_node *node)
632{
633 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
634 css_qname qs;
635 dom_string *attr = NULL;
636 dom_node *tablenode = NULL;
637 dom_exception exc;
638
639 qs.ns = NULL;
640 qs.name = lwc_string_ref(corestring_lwc_table);
641 if (named_ancestor_node(ctx, node, &qs,
642 (void *)&tablenode) != CSS_OK) {
643 /* Didn't find, or had error */
644 lwc_string_unref(qs.name);
645 return;
646 }
647 lwc_string_unref(qs.name);
648
649 if (tablenode == NULL) {
650 return;
651 }
652 /* No need to unref tablenode, named_ancestor_node does not
653 * return a reffed node to the CSS
654 */
655
656 exc = dom_element_get_attribute(tablenode,
657 corestring_dom_border, &attr);
658
659 if (exc == DOM_NO_ERR && attr != NULL) {
660 uint32_t hint_prop;
661 css_hint_length hint_length;
662
663 if (parse_dimension(
664 dom_string_data(attr), false,
665 &hint_length.value,
666 &hint_length.unit) &&
667 INTTOFIX(0) != hint_length.value) {
668
669 for (hint_prop = CSS_PROP_BORDER_TOP_STYLE;
670 hint_prop <= CSS_PROP_BORDER_LEFT_STYLE;
671 hint_prop++) {
672 hint->prop = hint_prop;
673 hint->status = CSS_BORDER_STYLE_INSET;
674 css_hint_advance(&hint);
675 }
676
677 for (hint_prop = CSS_PROP_BORDER_TOP_WIDTH;
678 hint_prop <= CSS_PROP_BORDER_LEFT_WIDTH;
679 hint_prop++) {
680 hint->prop = hint_prop;
681 hint->data.length.value = INTTOFIX(1);
682 hint->data.length.unit = CSS_UNIT_PX;
683 hint->status = CSS_BORDER_WIDTH_WIDTH;
684 css_hint_advance(&hint);
685 }
686 }
687 dom_string_unref(attr);
688 }
689
690 exc = dom_element_get_attribute(tablenode,
691 corestring_dom_bordercolor, &attr);
692
693 if (exc == DOM_NO_ERR && attr != NULL) {
694 uint32_t hint_prop;
695 css_color hint_color;
696
698 (const char *)dom_string_data(attr),
699 &hint_color)) {
700
701 for (hint_prop = CSS_PROP_BORDER_TOP_COLOR;
702 hint_prop <= CSS_PROP_BORDER_LEFT_COLOR;
703 hint_prop++) {
704 hint->prop = hint_prop;
705 hint->data.color = hint_color;
706 hint->status = CSS_BORDER_COLOR_COLOR;
707 css_hint_advance(&hint);
708 }
709 }
710 dom_string_unref(attr);
711 }
712
713 exc = dom_element_get_attribute(tablenode,
714 corestring_dom_cellpadding, &attr);
715
716 if (exc == DOM_NO_ERR && attr != NULL) {
717 uint32_t hint_prop;
718 css_hint_length hint_length;
719
720 if (parse_dimension(
721 dom_string_data(attr), false,
722 &hint_length.value,
723 &hint_length.unit)) {
724
725 for (hint_prop = CSS_PROP_PADDING_TOP;
726 hint_prop <= CSS_PROP_PADDING_LEFT;
727 hint_prop++) {
728 hint->prop = hint_prop;
729 hint->data.length.value = hint_length.value;
730 hint->data.length.unit = hint_length.unit;
731 hint->status = CSS_PADDING_SET;
732 css_hint_advance(&hint);
733 }
734 }
735 dom_string_unref(attr);
736 }
737}
738
740 nscss_select_ctx *ctx,
741 dom_node *node)
742{
743 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
744 dom_string *attr = NULL;
745 dom_exception err;
746
747 err = dom_element_get_attribute(node,
748 corestring_dom_valign, &attr);
749
750 if (err == DOM_NO_ERR && attr != NULL) {
751 hint->data.length.value = 0;
752 hint->data.length.unit = CSS_UNIT_PX;
753 if (dom_string_caseless_lwc_isequal(attr,
754 corestring_lwc_top)) {
755 hint->prop = CSS_PROP_VERTICAL_ALIGN;
756 hint->status = CSS_VERTICAL_ALIGN_TOP;
757 css_hint_advance(&hint);
758
759 } else if (dom_string_caseless_lwc_isequal(attr,
760 corestring_lwc_middle)) {
761 hint->prop = CSS_PROP_VERTICAL_ALIGN;
762 hint->status = CSS_VERTICAL_ALIGN_MIDDLE;
763 css_hint_advance(&hint);
764
765 } else if (dom_string_caseless_lwc_isequal(attr,
766 corestring_lwc_bottom)) {
767 hint->prop = CSS_PROP_VERTICAL_ALIGN;
768 hint->status = CSS_VERTICAL_ALIGN_BOTTOM;
769 css_hint_advance(&hint);
770
771 } else if (dom_string_caseless_lwc_isequal(attr,
772 corestring_lwc_baseline)) {
773 hint->prop = CSS_PROP_VERTICAL_ALIGN;
774 hint->status = CSS_VERTICAL_ALIGN_BASELINE;
775 css_hint_advance(&hint);
776 }
777 dom_string_unref(attr);
778 }
779}
780
782 nscss_select_ctx *ctx,
783 dom_node *node)
784{
785 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
786 dom_string *attr = NULL;
787 dom_exception err;
788
789 err = dom_element_get_attribute(node,
790 corestring_dom_valign, &attr);
791
792 if (err == DOM_NO_ERR && attr != NULL) {
793 if (dom_string_caseless_lwc_isequal(attr,
794 corestring_lwc_top)) {
795 hint->prop = CSS_PROP_VERTICAL_ALIGN;
796 hint->status = CSS_VERTICAL_ALIGN_TOP;
797 css_hint_advance(&hint);
798
799 } else if (dom_string_caseless_lwc_isequal(attr,
800 corestring_lwc_bottom) ||
801 dom_string_caseless_lwc_isequal(attr,
802 corestring_lwc_baseline)) {
803 hint->prop = CSS_PROP_VERTICAL_ALIGN;
804 hint->status = CSS_VERTICAL_ALIGN_BASELINE;
805 css_hint_advance(&hint);
806
807 } else if (dom_string_caseless_lwc_isequal(attr,
808 corestring_lwc_texttop)) {
809 hint->prop = CSS_PROP_VERTICAL_ALIGN;
810 hint->status = CSS_VERTICAL_ALIGN_TEXT_TOP;
811 css_hint_advance(&hint);
812
813 } else if (dom_string_caseless_lwc_isequal(attr,
814 corestring_lwc_absmiddle) ||
815 dom_string_caseless_lwc_isequal(attr,
816 corestring_lwc_abscenter)) {
817 hint->prop = CSS_PROP_VERTICAL_ALIGN;
818 hint->status = CSS_VERTICAL_ALIGN_MIDDLE;
819 css_hint_advance(&hint);
820 }
821 dom_string_unref(attr);
822 }
823}
824
826 nscss_select_ctx *ctx,
827 dom_node *node)
828{
829 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
830 dom_string *align = NULL;
831 dom_exception err;
832
833 err = dom_element_get_attribute(node,
834 corestring_dom_align, &align);
835 if (err == DOM_NO_ERR && align != NULL) {
836 if (dom_string_caseless_lwc_isequal(align,
837 corestring_lwc_left)) {
838 hint->prop = CSS_PROP_TEXT_ALIGN;
839 hint->status = CSS_TEXT_ALIGN_LEFT;
840 css_hint_advance(&hint);
841
842 } else if (dom_string_caseless_lwc_isequal(align,
843 corestring_lwc_center)) {
844 hint->prop = CSS_PROP_TEXT_ALIGN;
845 hint->status = CSS_TEXT_ALIGN_CENTER;
846 css_hint_advance(&hint);
847
848 } else if (dom_string_caseless_lwc_isequal(align,
849 corestring_lwc_right)) {
850 hint->prop = CSS_PROP_TEXT_ALIGN;
851 hint->status = CSS_TEXT_ALIGN_RIGHT;
852 css_hint_advance(&hint);
853
854 } else if (dom_string_caseless_lwc_isequal(align,
855 corestring_lwc_justify)) {
856 hint->prop = CSS_PROP_TEXT_ALIGN;
857 hint->status = CSS_TEXT_ALIGN_JUSTIFY;
858 css_hint_advance(&hint);
859 }
860 dom_string_unref(align);
861 }
862}
863
865 nscss_select_ctx *ctx,
866 dom_node *node)
867{
868 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
869
870 hint->prop = CSS_PROP_TEXT_ALIGN;
871 hint->status = CSS_TEXT_ALIGN_LIBCSS_CENTER;
872 css_hint_advance(&hint);
873}
874
876 nscss_select_ctx *ctx,
877 dom_node *node)
878{
879 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
880 dom_string *attr;
881 dom_exception exc;
882
883 exc = dom_element_get_attribute(node,
884 corestring_dom_align, &attr);
885
886 if (exc == DOM_NO_ERR && attr != NULL) {
887 memset(hint, 0, sizeof(*hint) * 2);
888 if (dom_string_caseless_lwc_isequal(attr,
889 corestring_lwc_center) ||
890 dom_string_caseless_lwc_isequal(attr,
891 corestring_lwc_abscenter) ||
892 dom_string_caseless_lwc_isequal(attr,
893 corestring_lwc_middle) ||
894 dom_string_caseless_lwc_isequal(attr,
895 corestring_lwc_absmiddle)) {
896 hint->prop = CSS_PROP_MARGIN_LEFT;
897 hint->status = CSS_MARGIN_AUTO;
898 css_hint_advance(&hint);
899
900 hint->prop = CSS_PROP_MARGIN_RIGHT;
901 hint->status = CSS_MARGIN_AUTO;
902 css_hint_advance(&hint);
903 }
904 dom_string_unref(attr);
905 }
906}
907
909 nscss_select_ctx *ctx,
910 dom_node *node)
911{
912 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
913 dom_string *align = NULL;
914 dom_exception err;
915
916 err = dom_element_get_attribute(node,
917 corestring_dom_align, &align);
918
919 if (err == DOM_NO_ERR && align != NULL) {
920 if (dom_string_caseless_lwc_isequal(align,
921 corestring_lwc_center)) {
922 hint->prop = CSS_PROP_TEXT_ALIGN;
923 hint->status = CSS_TEXT_ALIGN_LIBCSS_CENTER;
924 css_hint_advance(&hint);
925
926 } else if (dom_string_caseless_lwc_isequal(align,
927 corestring_lwc_left)) {
928 hint->prop = CSS_PROP_TEXT_ALIGN;
929 hint->status = CSS_TEXT_ALIGN_LIBCSS_LEFT;
930 css_hint_advance(&hint);
931
932 } else if (dom_string_caseless_lwc_isequal(align,
933 corestring_lwc_right)) {
934 hint->prop = CSS_PROP_TEXT_ALIGN;
935 hint->status = CSS_TEXT_ALIGN_LIBCSS_RIGHT;
936 css_hint_advance(&hint);
937
938 } else if (dom_string_caseless_lwc_isequal(align,
939 corestring_lwc_justify)) {
940 hint->prop = CSS_PROP_TEXT_ALIGN;
941 hint->status = CSS_TEXT_ALIGN_JUSTIFY;
942 css_hint_advance(&hint);
943 }
944 dom_string_unref(align);
945 }
946}
947
949 nscss_select_ctx *ctx,
950 dom_node *node)
951{
952 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
953
954 hint->prop = CSS_PROP_TEXT_ALIGN;
955 hint->status = CSS_TEXT_ALIGN_INHERIT_IF_NON_MAGIC;
956 css_hint_advance(&hint);
957}
958
960 nscss_select_ctx *ctx,
961 dom_node *node)
962{
963 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
964 dom_string *attr = NULL;
965 dom_exception exc;
966
967 exc = dom_element_get_attribute(node,
968 corestring_dom_vspace, &attr);
969
970 if (exc == DOM_NO_ERR && attr != NULL) {
971 css_hint_length hint_length;
972 if (parse_dimension(
973 dom_string_data(attr), false,
974 &hint_length.value,
975 &hint_length.unit)) {
976 hint->prop = CSS_PROP_MARGIN_TOP;
977 hint->data.length.value = hint_length.value;
978 hint->data.length.unit = hint_length.unit;
979 hint->status = CSS_MARGIN_SET;
980 css_hint_advance(&hint);
981
982 hint->prop = CSS_PROP_MARGIN_BOTTOM;
983 hint->data.length.value = hint_length.value;
984 hint->data.length.unit = hint_length.unit;
985 hint->status = CSS_MARGIN_SET;
986 css_hint_advance(&hint);
987 }
988 dom_string_unref(attr);
989 }
990
991 exc = dom_element_get_attribute(node,
992 corestring_dom_hspace, &attr);
993
994 if (exc == DOM_NO_ERR && attr != NULL) {
995 css_hint_length hint_length;
996 if (parse_dimension(
997 dom_string_data(attr), false,
998 &hint_length.value,
999 &hint_length.unit)) {
1000 hint->prop = CSS_PROP_MARGIN_LEFT;
1001 hint->data.length.value = hint_length.value;
1002 hint->data.length.unit = hint_length.unit;
1003 hint->status = CSS_MARGIN_SET;
1004 css_hint_advance(&hint);
1005
1006 hint->prop = CSS_PROP_MARGIN_RIGHT;
1007 hint->data.length.value = hint_length.value;
1008 hint->data.length.unit = hint_length.unit;
1009 hint->status = CSS_MARGIN_SET;
1010 css_hint_advance(&hint);
1011 }
1012 dom_string_unref(attr);
1013 }
1014}
1015
1017 nscss_select_ctx *ctx,
1018 dom_node *node)
1019{
1020 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
1021 dom_string *attr;
1022 dom_exception exc;
1023
1024 exc = dom_element_get_attribute(node,
1025 corestring_dom_align, &attr);
1026
1027 if (exc == DOM_NO_ERR && attr != NULL) {
1028 memset(hint, 0, sizeof(*hint) * 2);
1029 if (dom_string_caseless_lwc_isequal(attr,
1030 corestring_lwc_left)) {
1031 hint->prop = CSS_PROP_MARGIN_LEFT;
1032 hint->data.length.value = 0;
1033 hint->data.length.unit = CSS_UNIT_PX;
1034 hint->status = CSS_MARGIN_SET;
1035 css_hint_advance(&hint);
1036
1037 hint->prop = CSS_PROP_MARGIN_RIGHT;
1038 hint->status = CSS_MARGIN_AUTO;
1039 css_hint_advance(&hint);
1040
1041 } else if (dom_string_caseless_lwc_isequal(attr,
1042 corestring_lwc_center)) {
1043 hint->prop = CSS_PROP_MARGIN_LEFT;
1044 hint->status = CSS_MARGIN_AUTO;
1045 css_hint_advance(&hint);
1046
1047 hint->prop = CSS_PROP_MARGIN_RIGHT;
1048 hint->status = CSS_MARGIN_AUTO;
1049 css_hint_advance(&hint);
1050
1051 } else if (dom_string_caseless_lwc_isequal(attr,
1052 corestring_lwc_right)) {
1053 hint->prop = CSS_PROP_MARGIN_LEFT;
1054 hint->status = CSS_MARGIN_AUTO;
1055 css_hint_advance(&hint);
1056
1057 hint->prop = CSS_PROP_MARGIN_RIGHT;
1058 hint->data.length.value = 0;
1059 hint->data.length.unit = CSS_UNIT_PX;
1060 hint->status = CSS_MARGIN_SET;
1061 css_hint_advance(&hint);
1062 }
1063 dom_string_unref(attr);
1064 }
1065}
1066
1068 nscss_select_ctx *ctx,
1069 dom_node *node)
1070{
1071 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
1072 dom_exception exc;
1073 dom_string *attr = NULL;
1074
1075 exc = dom_element_get_attribute(node, corestring_dom_border, &attr);
1076
1077 if (exc == DOM_NO_ERR && attr != NULL) {
1078 uint32_t hint_prop;
1079 css_hint_length hint_length;
1080
1081 for (hint_prop = CSS_PROP_BORDER_TOP_STYLE;
1082 hint_prop <= CSS_PROP_BORDER_LEFT_STYLE;
1083 hint_prop++) {
1084 hint->prop = hint_prop;
1085 hint->status = CSS_BORDER_STYLE_OUTSET;
1086 css_hint_advance(&hint);
1087 }
1088
1089 if (parse_dimension(
1090 dom_string_data(attr), false,
1091 &hint_length.value,
1092 &hint_length.unit)) {
1093
1094 for (hint_prop = CSS_PROP_BORDER_TOP_WIDTH;
1095 hint_prop <= CSS_PROP_BORDER_LEFT_WIDTH;
1096 hint_prop++) {
1097 hint->prop = hint_prop;
1098 hint->data.length.value = hint_length.value;
1099 hint->data.length.unit = hint_length.unit;
1100 hint->status = CSS_BORDER_WIDTH_WIDTH;
1101 css_hint_advance(&hint);
1102 }
1103 }
1104 dom_string_unref(attr);
1105 }
1106
1107 exc = dom_element_get_attribute(node,
1108 corestring_dom_bordercolor, &attr);
1109
1110 if (exc == DOM_NO_ERR && attr != NULL) {
1111 uint32_t hint_prop;
1112 css_color hint_color;
1113
1115 (const char *)dom_string_data(attr),
1116 &hint_color)) {
1117
1118 for (hint_prop = CSS_PROP_BORDER_TOP_COLOR;
1119 hint_prop <= CSS_PROP_BORDER_LEFT_COLOR;
1120 hint_prop++) {
1121 hint->prop = hint_prop;
1122 hint->data.color = hint_color;
1123 hint->status = CSS_BORDER_COLOR_COLOR;
1124 css_hint_advance(&hint);
1125 }
1126 }
1127 dom_string_unref(attr);
1128 }
1129
1130 exc = dom_element_get_attribute(node,
1131 corestring_dom_cellspacing, &attr);
1132
1133 if (exc == DOM_NO_ERR && attr != NULL) {
1134 if (parse_dimension(
1135 (const char *)dom_string_data(attr), false,
1136 &hint->data.position.h.value,
1137 &hint->data.position.h.unit)) {
1138 hint->prop = CSS_PROP_BORDER_SPACING;
1139 hint->data.position.v = hint->data.position.h;
1140 hint->status = CSS_BORDER_SPACING_SET;
1141 css_hint_advance(&hint);
1142 }
1143 dom_string_unref(attr);
1144 }
1145}
1146
1148 nscss_select_ctx *ctx,
1149 dom_node *node)
1150{
1151 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
1152 dom_string *attr = NULL;
1153 dom_exception err;
1154
1155 err = dom_element_get_attribute(node,
1156 corestring_dom_height, &attr);
1157
1158 if (err == DOM_NO_ERR && attr != NULL) {
1159 if (parse_dimension(
1160 (const char *)dom_string_data(attr), false,
1161 &hint->data.length.value,
1162 &hint->data.length.unit)) {
1163 hint->prop = CSS_PROP_HEIGHT;
1164 hint->status = CSS_HEIGHT_SET;
1165 css_hint_advance(&hint);
1166 }
1167 dom_string_unref(attr);
1168 }
1169}
1170
1171static void css_hint_width(
1172 nscss_select_ctx *ctx,
1173 dom_node *node)
1174{
1175 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
1176 dom_string *attr = NULL;
1177 dom_exception err;
1178
1179 err = dom_element_get_attribute(node,
1180 corestring_dom_width, &attr);
1181
1182 if (err == DOM_NO_ERR && attr != NULL) {
1183 if (parse_dimension(
1184 (const char *)dom_string_data(attr), false,
1185 &hint->data.length.value,
1186 &hint->data.length.unit)) {
1187 hint->prop = CSS_PROP_WIDTH;
1188 hint->status = CSS_WIDTH_SET;
1189 css_hint_advance(&hint);
1190 }
1191 dom_string_unref(attr);
1192 }
1193}
1194
1196 nscss_select_ctx *ctx,
1197 dom_node *node)
1198{
1199 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
1200 dom_string *attr = NULL;
1201 dom_exception err;
1202
1203 err = dom_element_get_attribute(node,
1204 corestring_dom_rows, &attr);
1205
1206 if (err == DOM_NO_ERR && attr != NULL) {
1207 if (parse_dimension(
1208 (const char *)dom_string_data(attr), false,
1209 &hint->data.length.value,
1210 &hint->data.length.unit)) {
1211 hint->prop = CSS_PROP_HEIGHT;
1212 hint->data.length.unit = CSS_UNIT_EM;
1213 hint->status = CSS_HEIGHT_SET;
1214 css_hint_advance(&hint);
1215 }
1216 dom_string_unref(attr);
1217 }
1218
1219 err = dom_element_get_attribute(node,
1220 corestring_dom_cols, &attr);
1221
1222 if (err == DOM_NO_ERR && attr != NULL) {
1223 if (parse_dimension(
1224 (const char *)dom_string_data(attr), false,
1225 &hint->data.length.value,
1226 &hint->data.length.unit)) {
1227 hint->prop = CSS_PROP_WIDTH;
1228 hint->data.length.unit = CSS_UNIT_EX;
1229 hint->status = CSS_WIDTH_SET;
1230 css_hint_advance(&hint);
1231 }
1232 dom_string_unref(attr);
1233 }
1234}
1235
1237 nscss_select_ctx *ctx,
1238 dom_node *node)
1239{
1240 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
1241 dom_string *attr = NULL;
1242 dom_exception err;
1243 bool set_dim = false;
1244
1245 err = dom_element_get_attribute(node,
1246 corestring_dom_height, &attr);
1247
1248 if (err == DOM_NO_ERR && attr != NULL) {
1249 if (parse_dimension(
1250 (const char *)dom_string_data(attr), true,
1251 &hint->data.length.value,
1252 &hint->data.length.unit)) {
1253 hint->prop = CSS_PROP_HEIGHT;
1254 hint->data.length.unit = CSS_UNIT_PX;
1255 hint->status = CSS_HEIGHT_SET;
1256 css_hint_advance(&hint);
1257 set_dim = true;
1258 }
1259 dom_string_unref(attr);
1260 }
1261 if (set_dim == false) {
1262 /* canvas defaults to 150px tall */
1263 hint->prop = CSS_PROP_HEIGHT;
1264 hint->data.length.unit = CSS_UNIT_PX;
1265 hint->data.length.value = INTTOFIX(150);
1266 hint->status = CSS_HEIGHT_SET;
1267 css_hint_advance(&hint);
1268 } else {
1269 set_dim = false;
1270 }
1271
1272 err = dom_element_get_attribute(node,
1273 corestring_dom_width, &attr);
1274
1275 if (err == DOM_NO_ERR && attr != NULL) {
1276 if (parse_dimension(
1277 (const char *)dom_string_data(attr), true,
1278 &hint->data.length.value,
1279 &hint->data.length.unit)) {
1280 hint->prop = CSS_PROP_WIDTH;
1281 hint->data.length.unit = CSS_UNIT_PX;
1282 hint->status = CSS_WIDTH_SET;
1283 css_hint_advance(&hint);
1284 set_dim = true;
1285 }
1286 dom_string_unref(attr);
1287 }
1288 if (set_dim == false) {
1289 /* canvas defaults to 300px wide */
1290 hint->prop = CSS_PROP_WIDTH;
1291 hint->data.length.unit = CSS_UNIT_PX;
1292 hint->data.length.value = INTTOFIX(300);
1293 hint->status = CSS_WIDTH_SET;
1294 css_hint_advance(&hint);
1295 }
1296}
1297
1299 nscss_select_ctx *ctx,
1300 dom_node *node)
1301{
1302 struct css_hint *hint = &(hint_ctx.hints[hint_ctx.len]);
1303 dom_string *attr = NULL;
1304 dom_exception err;
1305
1306 err = dom_element_get_attribute(node,
1307 corestring_dom_size, &attr);
1308
1309 if (err == DOM_NO_ERR && attr != NULL) {
1310 if (parse_dimension(
1311 (const char *)dom_string_data(attr), false,
1312 &hint->data.length.value,
1313 &hint->data.length.unit)) {
1314 dom_string *attr2 = NULL;
1315
1316 err = dom_element_get_attribute(node,
1317 corestring_dom_type, &attr2);
1318 if (err == DOM_NO_ERR) {
1319
1320 hint->prop = CSS_PROP_WIDTH;
1321 hint->status = CSS_WIDTH_SET;
1322
1323 if (attr2 == NULL ||
1324 dom_string_caseless_lwc_isequal(
1325 attr2,
1326 corestring_lwc_text) ||
1327 dom_string_caseless_lwc_isequal(
1328 attr2,
1329 corestring_lwc_search) ||
1330 dom_string_caseless_lwc_isequal(
1331 attr2,
1332 corestring_lwc_password) ||
1333 dom_string_caseless_lwc_isequal(
1334 attr2,
1335 corestring_lwc_file)) {
1336 hint->data.length.unit = CSS_UNIT_EX;
1337 }
1338 if (attr2 != NULL) {
1339 dom_string_unref(attr2);
1340 }
1341 css_hint_advance(&hint);
1342 }
1343 }
1344 dom_string_unref(attr);
1345 }
1346}
1347
1349 nscss_select_ctx *ctx,
1350 dom_node *node)
1351{
1352 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
1353 css_error error;
1354 dom_exception err;
1355 dom_string *color;
1356 dom_node *bodynode = NULL;
1357
1358 /* find body node */
1359 css_qname qs;
1360 bool is_visited;
1361
1362 qs.ns = NULL;
1363 qs.name = lwc_string_ref(corestring_lwc_body);
1364 if (named_ancestor_node(ctx, node, &qs,
1365 (void *)&bodynode) != CSS_OK) {
1366 /* Didn't find, or had error */
1367 lwc_string_unref(qs.name);
1368 return ;
1369 }
1370 lwc_string_unref(qs.name);
1371
1372 if (bodynode == NULL) {
1373 return;
1374 }
1375
1376 error = node_is_visited(ctx, node, &is_visited);
1377 if (error != CSS_OK)
1378 return;
1379
1380 if (is_visited) {
1381 err = dom_element_get_attribute(bodynode,
1382 corestring_dom_vlink, &color);
1383 } else {
1384 err = dom_element_get_attribute(bodynode,
1385 corestring_dom_link, &color);
1386 }
1387
1388 if (err == DOM_NO_ERR && color != NULL) {
1390 (const char *)dom_string_data(color),
1391 &hint->data.color)) {
1392 hint->prop = CSS_PROP_COLOR;
1393 hint->status = CSS_COLOR_COLOR;
1394 css_hint_advance(&hint);
1395 }
1396 dom_string_unref(color);
1397 }
1398}
1399
1401 nscss_select_ctx *ctx,
1402 dom_node *node)
1403{
1404 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
1405 dom_exception err;
1406 dom_string *color;
1407
1408 err = dom_element_get_attribute(node, corestring_dom_text, &color);
1409
1410 if (err == DOM_NO_ERR && color != NULL) {
1412 (const char *)dom_string_data(color),
1413 &hint->data.color)) {
1414 hint->prop = CSS_PROP_COLOR;
1415 hint->status = CSS_COLOR_COLOR;
1416 css_hint_advance(&hint);
1417 }
1418 dom_string_unref(color);
1419 }
1420}
1421
1422static void css_hint_color(
1423 nscss_select_ctx *ctx,
1424 dom_node *node)
1425{
1426 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
1427 dom_exception err;
1428 dom_string *color;
1429
1430 err = dom_element_get_attribute(node, corestring_dom_color, &color);
1431
1432 if (err == DOM_NO_ERR && color != NULL) {
1434 (const char *)dom_string_data(color),
1435 &hint->data.color)) {
1436 hint->prop = CSS_PROP_COLOR;
1437 hint->status = CSS_COLOR_COLOR;
1438 css_hint_advance(&hint);
1439 }
1440 dom_string_unref(color);
1441 }
1442}
1443
1445 nscss_select_ctx *ctx,
1446 dom_node *node)
1447{
1448 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
1449 dom_exception err;
1450 dom_string *size;
1451
1452 err = dom_element_get_attribute(node, corestring_dom_size, &size);
1453 if (err == DOM_NO_ERR && size != NULL) {
1454 if (parse_font_size(
1455 (const char *)dom_string_data(size),
1456 &hint->status,
1457 &hint->data.length.value,
1458 &hint->data.length.unit)) {
1459 hint->prop = CSS_PROP_FONT_SIZE;
1460 css_hint_advance(&hint);
1461 }
1462 dom_string_unref(size);
1463 }
1464}
1465
1466static void css_hint_float(
1467 nscss_select_ctx *ctx,
1468 dom_node *node)
1469{
1470 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
1471 dom_exception err;
1472 dom_string *align;
1473
1474 err = dom_element_get_attribute(node, corestring_dom_align, &align);
1475 if (err == DOM_NO_ERR && align != NULL) {
1476 if (dom_string_caseless_lwc_isequal(align,
1477 corestring_lwc_left)) {
1478 hint->prop = CSS_PROP_FLOAT;
1479 hint->status = CSS_FLOAT_LEFT;
1480 css_hint_advance(&hint);
1481
1482 } else if (dom_string_caseless_lwc_isequal(align,
1483 corestring_lwc_right)) {
1484 hint->prop = CSS_PROP_FLOAT;
1485 hint->status = CSS_FLOAT_RIGHT;
1486 css_hint_advance(&hint);
1487 }
1488 dom_string_unref(align);
1489 }
1490}
1491
1493 nscss_select_ctx *ctx,
1494 dom_node *node)
1495{
1496 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
1497 dom_exception err;
1498 dom_string *align = NULL;
1499
1500 err = dom_element_get_attribute(node, corestring_dom_align, &align);
1501 if (err == DOM_NO_ERR && align != NULL) {
1502 if (dom_string_caseless_lwc_isequal(align,
1503 corestring_lwc_bottom)) {
1504 hint->prop = CSS_PROP_CAPTION_SIDE;
1505 hint->status = CSS_CAPTION_SIDE_BOTTOM;
1506 css_hint_advance(&hint);
1507 }
1508 dom_string_unref(align);
1509 }
1510}
1511
1513 nscss_select_ctx *ctx,
1514 dom_node *node)
1515{
1516 struct css_hint *hint = &hint_ctx.hints[hint_ctx.len];
1517 dom_exception err;
1518 dom_string *bgcolor;
1519
1520 err = dom_element_get_attribute(node,
1521 corestring_dom_bgcolor, &bgcolor);
1522 if (err == DOM_NO_ERR && bgcolor != NULL) {
1524 (const char *)dom_string_data(bgcolor),
1525 &hint->data.color)) {
1526 hint->prop = CSS_PROP_BACKGROUND_COLOR;
1527 hint->status = CSS_BACKGROUND_COLOR_COLOR;
1528 css_hint_advance(&hint);
1529 }
1530 dom_string_unref(bgcolor);
1531 }
1532}
1533
1535 nscss_select_ctx *ctx,
1536 dom_node *node)
1537{
1538 struct css_hint *hint = &(hint_ctx.hints[hint_ctx.len]);
1539 dom_exception err;
1540 dom_string *attr;
1541
1542 err = dom_element_get_attribute(node,
1543 corestring_dom_background, &attr);
1544 if (err == DOM_NO_ERR && attr != NULL) {
1545 nsurl *url;
1546 nserror error = nsurl_join(ctx->base_url,
1547 (const char *)dom_string_data(attr), &url);
1548 dom_string_unref(attr);
1549
1550 if (error == NSERROR_OK) {
1551 lwc_string *iurl;
1552 lwc_error lerror = lwc_intern_string(nsurl_access(url),
1553 nsurl_length(url), &iurl);
1554 nsurl_unref(url);
1555
1556 if (lerror == lwc_error_ok) {
1557 hint->prop = CSS_PROP_BACKGROUND_IMAGE;
1558 hint->data.string = iurl;
1559 hint->status = CSS_BACKGROUND_IMAGE_IMAGE;
1560 css_hint_advance(&hint);
1561 }
1562 }
1563 }
1564}
1565
1567 nscss_select_ctx *ctx,
1568 dom_node *node)
1569{
1570 struct css_hint *hint = &(hint_ctx.hints[hint_ctx.len]);
1571 dom_exception err;
1572 bool nowrap;
1573
1574 err = dom_element_has_attribute(node, corestring_dom_nowrap, &nowrap);
1575 if (err == DOM_NO_ERR && nowrap == true) {
1576 hint->prop = CSS_PROP_WHITE_SPACE;
1577 hint->status = CSS_WHITE_SPACE_NOWRAP;
1578 css_hint_advance(&hint);
1579 }
1580}
1581
1582static void css_hint_list(
1583 nscss_select_ctx *ctx,
1584 dom_node *node)
1585{
1586 struct css_hint *hint = &(hint_ctx.hints[hint_ctx.len]);
1587 dom_exception err;
1588 dom_string *attr;
1589
1590 err = dom_element_get_attribute(node, corestring_dom_type, &attr);
1591 if (err == DOM_NO_ERR && attr != NULL) {
1592 const char *attr_str = dom_string_data(attr);
1593 size_t attr_len = dom_string_byte_length(attr);
1594 enum css_list_style_type_e type = CSS_LIST_STYLE_TYPE_INHERIT;
1595
1596 if (attr_len == 1) {
1597 switch (attr_str[0]) {
1598 case 'a':
1599 type = CSS_LIST_STYLE_TYPE_LOWER_ALPHA;
1600 break;
1601 case 'A':
1602 type = CSS_LIST_STYLE_TYPE_UPPER_ALPHA;
1603 break;
1604 case 'i':
1605 type = CSS_LIST_STYLE_TYPE_LOWER_ROMAN;
1606 break;
1607 case 'I':
1608 type = CSS_LIST_STYLE_TYPE_UPPER_ROMAN;
1609 break;
1610 case '1':
1611 type = CSS_LIST_STYLE_TYPE_DECIMAL;
1612 break;
1613 }
1614 }
1615
1616 if (type != CSS_LIST_STYLE_TYPE_INHERIT) {
1617 hint->prop = CSS_PROP_LIST_STYLE_TYPE;
1618 hint->status = type;
1619 css_hint_advance(&hint);
1620 }
1621
1622 dom_string_unref(attr);
1623 }
1624}
1625
1626
1627/* Exported function, documented in css/hints.h */
1628css_error node_presentational_hint(void *pw, void *node,
1629 uint32_t *nhints, css_hint **hints)
1630{
1631 dom_exception exc;
1632 dom_html_element_type tag_type;
1633
1634 if (nsoption_bool(author_level_css) == false) {
1635 *nhints = 0;
1636 *hints = NULL;
1637 return CSS_OK;
1638 }
1639
1641
1642 exc = dom_html_element_get_tag_type(node, &tag_type);
1643 if (exc != DOM_NO_ERR) {
1644 tag_type = DOM_HTML_ELEMENT_TYPE__UNKNOWN;
1645 }
1646
1647 switch (tag_type) {
1648 case DOM_HTML_ELEMENT_TYPE_TH:
1649 case DOM_HTML_ELEMENT_TYPE_TD:
1650 css_hint_width(pw, node);
1654 case DOM_HTML_ELEMENT_TYPE_TR:
1655 css_hint_height(pw, node);
1657 case DOM_HTML_ELEMENT_TYPE_THEAD:
1658 case DOM_HTML_ELEMENT_TYPE_TBODY:
1659 case DOM_HTML_ELEMENT_TYPE_TFOOT:
1662 case DOM_HTML_ELEMENT_TYPE_COL:
1664 break;
1665 case DOM_HTML_ELEMENT_TYPE_APPLET:
1666 case DOM_HTML_ELEMENT_TYPE_IMG:
1669 case DOM_HTML_ELEMENT_TYPE_EMBED:
1670 case DOM_HTML_ELEMENT_TYPE_IFRAME:
1671 case DOM_HTML_ELEMENT_TYPE_OBJECT:
1672 css_hint_height(pw, node);
1673 css_hint_width(pw, node);
1675 css_hint_float(pw, node);
1676 break;
1677 case DOM_HTML_ELEMENT_TYPE_P:
1678 case DOM_HTML_ELEMENT_TYPE_H1:
1679 case DOM_HTML_ELEMENT_TYPE_H2:
1680 case DOM_HTML_ELEMENT_TYPE_H3:
1681 case DOM_HTML_ELEMENT_TYPE_H4:
1682 case DOM_HTML_ELEMENT_TYPE_H5:
1683 case DOM_HTML_ELEMENT_TYPE_H6:
1685 break;
1686 case DOM_HTML_ELEMENT_TYPE_CENTER:
1688 break;
1689 case DOM_HTML_ELEMENT_TYPE_CAPTION:
1690 css_hint_caption_side(pw, node);
1692 case DOM_HTML_ELEMENT_TYPE_DIV:
1694 break;
1695 case DOM_HTML_ELEMENT_TYPE_TABLE:
1698 css_hint_float(pw, node);
1700 css_hint_width(pw, node);
1701 break;
1702 case DOM_HTML_ELEMENT_TYPE_HR:
1703 css_hint_width(pw, node);
1705 break;
1706 case DOM_HTML_ELEMENT_TYPE_TEXTAREA:
1708 break;
1709 case DOM_HTML_ELEMENT_TYPE_INPUT:
1710 css_hint_width_input(pw, node);
1711 break;
1712 case DOM_HTML_ELEMENT_TYPE_A:
1713 css_hint_anchor_color(pw, node);
1714 break;
1715 case DOM_HTML_ELEMENT_TYPE_FONT:
1716 css_hint_font_size(pw, node);
1717 break;
1718 case DOM_HTML_ELEMENT_TYPE_BODY:
1719 css_hint_body_color(pw, node);
1720 break;
1721 case DOM_HTML_ELEMENT_TYPE_CANVAS:
1723 break;
1724 case DOM_HTML_ELEMENT_TYPE_OL:
1725 css_hint_list(pw, node);
1726 break;
1727 default:
1728 break;
1729 }
1730
1731 if (tag_type != DOM_HTML_ELEMENT_TYPE__UNKNOWN) {
1732 css_hint_color(pw, node);
1733 css_hint_bg_color(pw, node);
1734 css_hint_bg_image(pw, node);
1735 }
1736
1737#ifdef LOG_STATS
1738 NSLOG(netsurf, INFO, "Properties with hints: %i", hint_ctx.len);
1739#endif
1740
1741 css_hint_get_hints(hints, nhints);
1742
1743 return CSS_OK;
1744}
STATIC char result[100]
Definition: arexx.c:77
static os_mode mode
The current sprite mode.
Definition: buffer.c:72
Useful interned string pointers (interface).
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_NOMEM
Memory exhaustion.
Definition: errors.h:32
@ NSERROR_OK
No error.
Definition: errors.h:30
const char * type
Definition: filetype.cpp:44
css_error node_presentational_hint(void *pw, void *node, uint32_t *nhints, css_hint **hints)
Callback to retrieve presentational hints for a node.
Definition: hints.c:1628
static void css_hint_advance(struct css_hint **hint)
Definition: hints.c:610
static void css_hint_margin_hspace_vspace(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:959
static void css_hint_bg_image(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:1534
struct css_hint_ctx hint_ctx
Definition: hints.c:586
static bool parse_dimension(const char *data, bool strict, css_fixed *length, css_unit *unit)
Parse a dimension string.
Definition: hints.c:224
static void css_hint_table_cell_border_padding(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:629
static void css_hint_height(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:1147
static void css_hint_text_align_special(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:908
static bool isWhitespace(char c)
Determine if a given character is whitespace.
Definition: hints.c:44
static void css_hint_float(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:1466
static void css_hint_body_color(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:1400
static void css_hint_get_hints(struct css_hint **hints, uint32_t *nhints)
Definition: hints.c:618
void css_hint_fini(void)
Definition: hints.c:599
static void css_hint_margin_left_right_hr(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:1016
static void css_hint_vertical_align_table_cells(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:739
static bool isHex(char c)
Determine if a given character is a valid hex digit.
Definition: hints.c:55
static void css_hint_margin_left_right_align_center(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:875
static void css_hint_color(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:1422
static void css_hint_text_align_center(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:864
static void css_hint_table_spacing_border(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:1067
bool nscss_parse_colour(const char *data, css_color *result)
Parser for colours specified in attribute values.
Definition: hints.c:449
static void css_hint_caption_side(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:1492
static uint8_t charToHex(char c)
Convert a character representing a hex digit to the corresponding hex value.
Definition: hints.c:69
static bool parse_number(const char *data, bool maybe_negative, bool real, css_fixed *value, size_t *consumed)
Parse a number string.
Definition: hints.c:101
static void css_hint_vertical_align_replaced(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:781
static void css_hint_clean(void)
Definition: hints.c:605
static void css_hint_list(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:1582
static void css_hint_anchor_color(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:1348
static void css_hint_text_align_table_special(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:948
static void css_hint_bg_color(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:1512
static void css_hint_height_width_textarea(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:1195
#define MAX_HINTS_PER_ELEMENT
Definition: hints.c:579
static void css_hint_width(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:1171
static void css_hint_font_size(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:1444
static void css_hint_text_align_normal(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:825
nserror css_hint_init(void)
Definition: hints.c:588
static void css_hint_width_input(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:1298
static void css_hint_height_width_canvas(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:1236
static void css_hint_white_space_nowrap(nscss_select_ctx *ctx, dom_node *node)
Definition: hints.c:1566
static bool parse_font_size(const char *size, uint8_t *val, css_fixed *len, css_unit *unit)
Parse a font @size attribute.
Definition: hints.c:509
static int cmp_colour_name(const void *a, const void *b)
Name comparator for named colour matching.
Definition: hints.c:266
static bool parse_named_colour(const char *name, css_color *result)
Parse a named colour.
Definition: hints.c:281
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
NetSurf URL handling (interface).
void nsurl_unref(nsurl *url)
Drop a reference to a NetSurf URL object.
const char * nsurl_access(const nsurl *url)
Access a NetSurf URL object as a string.
size_t nsurl_length(const nsurl *url)
Find the length of a NetSurf URL object's URL, as returned by nsurl_access.
nserror nsurl_join(const nsurl *base, const char *rel, nsurl **joined)
Join a base url to a relative link part, creating a new NetSurf URL object.
struct nsurl nsurl
NetSurf URL object.
Definition: nsurl.h:31
css_error node_is_visited(void *pw, void *node, bool *match)
Callback to determine if a node is a linking element whose target has been visited.
Definition: select.c:1471
css_error named_ancestor_node(void *pw, void *node, const css_qname *qname, void **ancestor)
Callback to find a named ancestor node.
Definition: select.c:471
Interface to utility string handling.
Mapping of colour name to CSS color.
Definition: hints.c:252
css_color color
Definition: hints.c:254
const char * name
Definition: hints.c:253
uint32_t len
Definition: hints.c:583
struct css_hint * hints
Definition: hints.c:582
Selection context.
Definition: select.h:35
struct nsurl * base_url
Definition: select.h:38
Option reading and saving interface.
#define nsoption_int(OPTION)
Get the value of an integer option.
Definition: nsoption.h:313
#define nsoption_bool(OPTION)
Get the value of a boolean option.
Definition: nsoption.h:304
Interface to a number of general purpose functionality.
#define fallthrough
switch fall through
Definition: utils.h:119
#define SLEN(x)
Calculate length of constant C string.
Definition: utils.h:88