NetSurf
select.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 <assert.h>
20#include <string.h>
21#include <strings.h>
22
23#include "utils/nsoption.h"
24#include "utils/corestrings.h"
25#include "utils/log.h"
26#include "utils/nsurl.h"
27#include "netsurf/plot_style.h"
28#include "netsurf/url_db.h"
30
31#include "css/internal.h"
32#include "css/hints.h"
33#include "css/select.h"
34
35static css_error node_name(void *pw, void *node, css_qname *qname);
36static css_error node_classes(void *pw, void *node,
37 lwc_string ***classes, uint32_t *n_classes);
38static css_error node_id(void *pw, void *node, lwc_string **id);
39static css_error named_parent_node(void *pw, void *node,
40 const css_qname *qname, void **parent);
41static css_error named_sibling_node(void *pw, void *node,
42 const css_qname *qname, void **sibling);
43static css_error named_generic_sibling_node(void *pw, void *node,
44 const css_qname *qname, void **sibling);
45static css_error parent_node(void *pw, void *node, void **parent);
46static css_error sibling_node(void *pw, void *node, void **sibling);
47static css_error node_has_name(void *pw, void *node,
48 const css_qname *qname, bool *match);
49static css_error node_has_class(void *pw, void *node,
50 lwc_string *name, bool *match);
51static css_error node_has_id(void *pw, void *node,
52 lwc_string *name, bool *match);
53static css_error node_has_attribute(void *pw, void *node,
54 const css_qname *qname, bool *match);
55static css_error node_has_attribute_equal(void *pw, void *node,
56 const css_qname *qname, lwc_string *value,
57 bool *match);
58static css_error node_has_attribute_dashmatch(void *pw, void *node,
59 const css_qname *qname, lwc_string *value,
60 bool *match);
61static css_error node_has_attribute_includes(void *pw, void *node,
62 const css_qname *qname, lwc_string *value,
63 bool *match);
64static css_error node_has_attribute_prefix(void *pw, void *node,
65 const css_qname *qname, lwc_string *value,
66 bool *match);
67static css_error node_has_attribute_suffix(void *pw, void *node,
68 const css_qname *qname, lwc_string *value,
69 bool *match);
70static css_error node_has_attribute_substring(void *pw, void *node,
71 const css_qname *qname, lwc_string *value,
72 bool *match);
73static css_error node_is_root(void *pw, void *node, bool *match);
74static css_error node_count_siblings(void *pw, void *node,
75 bool same_name, bool after, int32_t *count);
76static css_error node_is_empty(void *pw, void *node, bool *match);
77static css_error node_is_link(void *pw, void *node, bool *match);
78static css_error node_is_hover(void *pw, void *node, bool *match);
79static css_error node_is_active(void *pw, void *node, bool *match);
80static css_error node_is_focus(void *pw, void *node, bool *match);
81static css_error node_is_enabled(void *pw, void *node, bool *match);
82static css_error node_is_disabled(void *pw, void *node, bool *match);
83static css_error node_is_checked(void *pw, void *node, bool *match);
84static css_error node_is_target(void *pw, void *node, bool *match);
85static css_error node_is_lang(void *pw, void *node,
86 lwc_string *lang, bool *match);
87static css_error ua_default_for_property(void *pw, uint32_t property,
88 css_hint *hint);
89static css_error set_libcss_node_data(void *pw, void *node,
90 void *libcss_node_data);
91static css_error get_libcss_node_data(void *pw, void *node,
92 void **libcss_node_data);
93
94/**
95 * Selection callback table for libcss
96 */
97static css_select_handler selection_handler = {
98 CSS_SELECT_HANDLER_VERSION_1,
99
100 node_name,
102 node_id,
136};
137
138/**
139 * Create an inline style
140 *
141 * \param data Source data
142 * \param len Length of data in bytes
143 * \param charset Charset of data, or NULL if unknown
144 * \param url Base URL of document containing data
145 * \param allow_quirks True to permit CSS parsing quirks
146 * \return Pointer to stylesheet, or NULL on failure.
147 */
148css_stylesheet *nscss_create_inline_style(const uint8_t *data, size_t len,
149 const char *charset, const char *url, bool allow_quirks)
150{
151 css_stylesheet_params params;
152 css_stylesheet *sheet;
153 css_error error;
154
155 params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1;
156 params.level = CSS_LEVEL_DEFAULT;
157 params.charset = charset;
158 params.url = url;
159 params.title = NULL;
160 params.allow_quirks = allow_quirks;
161 params.inline_style = true;
162 params.resolve = nscss_resolve_url;
163 params.resolve_pw = NULL;
164 params.import = NULL;
165 params.import_pw = NULL;
166 params.color = ns_system_colour;
167 params.color_pw = NULL;
168 params.font = NULL;
169 params.font_pw = NULL;
170
171 error = css_stylesheet_create(&params, &sheet);
172 if (error != CSS_OK) {
173 NSLOG(netsurf, INFO, "Failed creating sheet: %d", error);
174 return NULL;
175 }
176
177 error = css_stylesheet_append_data(sheet, data, len);
178 if (error != CSS_OK && error != CSS_NEEDDATA) {
179 NSLOG(netsurf, INFO, "failed appending data: %d", error);
180 css_stylesheet_destroy(sheet);
181 return NULL;
182 }
183
184 error = css_stylesheet_data_done(sheet);
185 if (error != CSS_OK) {
186 NSLOG(netsurf, INFO, "failed completing parse: %d", error);
187 css_stylesheet_destroy(sheet);
188 return NULL;
189 }
190
191 return sheet;
192}
193
194/* Handler for libcss_node_data, stored as libdom node user data */
195static void nscss_dom_user_data_handler(dom_node_operation operation,
196 dom_string *key, void *data, struct dom_node *src,
197 struct dom_node *dst)
198{
199 css_error error;
200
201 if (dom_string_isequal(corestring_dom___ns_key_libcss_node_data,
202 key) == false || data == NULL) {
203 return;
204 }
205
206 switch (operation) {
207 case DOM_NODE_CLONED:
208 error = css_libcss_node_data_handler(&selection_handler,
209 CSS_NODE_CLONED,
210 NULL, src, dst, data);
211 if (error != CSS_OK)
212 NSLOG(netsurf, INFO,
213 "Failed to clone libcss_node_data.");
214 break;
215
216 case DOM_NODE_RENAMED:
217 error = css_libcss_node_data_handler(&selection_handler,
218 CSS_NODE_MODIFIED,
219 NULL, src, NULL, data);
220 if (error != CSS_OK)
221 NSLOG(netsurf, INFO,
222 "Failed to update libcss_node_data.");
223 break;
224
225 case DOM_NODE_IMPORTED:
226 case DOM_NODE_ADOPTED:
227 case DOM_NODE_DELETED:
228 error = css_libcss_node_data_handler(&selection_handler,
229 CSS_NODE_DELETED,
230 NULL, src, NULL, data);
231 if (error != CSS_OK)
232 NSLOG(netsurf, INFO,
233 "Failed to delete libcss_node_data.");
234 break;
235
236 default:
237 NSLOG(netsurf, INFO, "User data operation not handled.");
238 assert(0);
239 }
240}
241
242/**
243 * Get style selection results for an element
244 *
245 * \param ctx CSS selection context
246 * \param n Element to select for
247 * \param media Permitted media types
248 * \param unit_unit_len_ctx Unit length conversion context
249 * \param inline_style Inline style associated with element, or NULL
250 * \return Pointer to selection results (containing computed styles),
251 * or NULL on failure
252 */
253css_select_results *nscss_get_style(nscss_select_ctx *ctx, dom_node *n,
254 const css_media *media,
255 const css_unit_ctx *unit_len_ctx,
256 const css_stylesheet *inline_style)
257{
258 css_computed_style *composed;
259 css_select_results *styles;
260 int pseudo_element;
261 css_error error;
262
263 /* Select style for node */
264 error = css_select_style(ctx->ctx, n, unit_len_ctx, media, inline_style,
265 &selection_handler, ctx, &styles);
266
267 if (error != CSS_OK || styles == NULL) {
268 /* Failed selecting partial style -- bail out */
269 return NULL;
270 }
271
272 /* If there's a parent style, compose with partial to obtain
273 * complete computed style for element */
274 if (ctx->parent_style != NULL) {
275 /* Complete the computed style, by composing with the parent
276 * element's style */
277 error = css_computed_style_compose(ctx->parent_style,
278 styles->styles[CSS_PSEUDO_ELEMENT_NONE],
279 unit_len_ctx, &composed);
280 if (error != CSS_OK) {
281 css_select_results_destroy(styles);
282 return NULL;
283 }
284
285 /* Replace select_results style with composed style */
286 css_computed_style_destroy(
287 styles->styles[CSS_PSEUDO_ELEMENT_NONE]);
288 styles->styles[CSS_PSEUDO_ELEMENT_NONE] = composed;
289 }
290
291 for (pseudo_element = CSS_PSEUDO_ELEMENT_NONE + 1;
292 pseudo_element < CSS_PSEUDO_ELEMENT_COUNT;
293 pseudo_element++) {
294
295 if (pseudo_element == CSS_PSEUDO_ELEMENT_FIRST_LETTER ||
296 pseudo_element == CSS_PSEUDO_ELEMENT_FIRST_LINE)
297 /* TODO: Handle first-line and first-letter pseudo
298 * element computed style completion */
299 continue;
300
301 if (styles->styles[pseudo_element] == NULL)
302 /* There were no rules concerning this pseudo element */
303 continue;
304
305 /* Complete the pseudo element's computed style, by composing
306 * with the base element's style */
307 error = css_computed_style_compose(
308 styles->styles[CSS_PSEUDO_ELEMENT_NONE],
309 styles->styles[pseudo_element],
310 unit_len_ctx, &composed);
311 if (error != CSS_OK) {
312 /* TODO: perhaps this shouldn't be quite so
313 * catastrophic? */
314 css_select_results_destroy(styles);
315 return NULL;
316 }
317
318 /* Replace select_results style with composed style */
319 css_computed_style_destroy(styles->styles[pseudo_element]);
320 styles->styles[pseudo_element] = composed;
321 }
322
323 return styles;
324}
325
326/**
327 * Get a blank style
328 *
329 * \param ctx CSS selection context
330 * \param unit_unit_len_ctx Unit length conversion context
331 * \param parent Parent style to cascade inherited properties from
332 * \return Pointer to blank style, or NULL on failure
333 */
335 const css_unit_ctx *unit_len_ctx,
336 const css_computed_style *parent)
337{
338 css_computed_style *partial, *composed;
339 css_error error;
340
341 error = css_select_default_style(ctx->ctx,
342 &selection_handler, ctx, &partial);
343 if (error != CSS_OK) {
344 return NULL;
345 }
346
347 /* TODO: Do we really need to compose? Initial style shouldn't
348 * have any inherited properties. */
349 error = css_computed_style_compose(parent, partial,
350 unit_len_ctx, &composed);
351 css_computed_style_destroy(partial);
352 if (error != CSS_OK) {
353 css_computed_style_destroy(composed);
354 return NULL;
355 }
356
357 return composed;
358}
359
360/******************************************************************************
361 * Style selection callbacks *
362 ******************************************************************************/
363
364/**
365 * Callback to retrieve a node's name.
366 *
367 * \param pw HTML document
368 * \param node DOM node
369 * \param qname Pointer to location to receive node name
370 * \return CSS_OK on success,
371 * CSS_NOMEM on memory exhaustion.
372 */
373css_error node_name(void *pw, void *node, css_qname *qname)
374{
375 dom_node *n = node;
376 dom_string *name;
377 dom_exception err;
378
379 err = dom_node_get_node_name(n, &name);
380 if (err != DOM_NO_ERR)
381 return CSS_NOMEM;
382
383 qname->ns = NULL;
384
385 err = dom_string_intern(name, &qname->name);
386 if (err != DOM_NO_ERR) {
387 dom_string_unref(name);
388 return CSS_NOMEM;
389 }
390
391 dom_string_unref(name);
392
393 return CSS_OK;
394}
395
396/**
397 * Callback to retrieve a node's classes.
398 *
399 * \param pw HTML document
400 * \param node DOM node
401 * \param classes Pointer to location to receive class name array
402 * \param n_classes Pointer to location to receive length of class name array
403 * \return CSS_OK on success,
404 * CSS_NOMEM on memory exhaustion.
405 *
406 * \note The returned array will be destroyed by libcss. Therefore, it must
407 * be allocated using the same allocator as used by libcss during style
408 * selection.
409 */
410css_error node_classes(void *pw, void *node,
411 lwc_string ***classes, uint32_t *n_classes)
412{
413 dom_node *n = node;
414 dom_exception err;
415
416 *classes = NULL;
417 *n_classes = 0;
418
419 err = dom_element_get_classes(n, classes, n_classes);
420 if (err != DOM_NO_ERR)
421 return CSS_NOMEM;
422
423 return CSS_OK;
424}
425
426/**
427 * Callback to retrieve a node's ID.
428 *
429 * \param pw HTML document
430 * \param node DOM node
431 * \param id Pointer to location to receive id value
432 * \return CSS_OK on success,
433 * CSS_NOMEM on memory exhaustion.
434 */
435css_error node_id(void *pw, void *node, lwc_string **id)
436{
437 dom_node *n = node;
438 dom_string *attr;
439 dom_exception err;
440
441 *id = NULL;
442
443 /** \todo Assumes an HTML DOM */
444 err = dom_html_element_get_id(n, &attr);
445 if (err != DOM_NO_ERR)
446 return CSS_NOMEM;
447
448 if (attr != NULL) {
449 err = dom_string_intern(attr, id);
450 if (err != DOM_NO_ERR) {
451 dom_string_unref(attr);
452 return CSS_NOMEM;
453 }
454 dom_string_unref(attr);
455 }
456
457 return CSS_OK;
458}
459
460/**
461 * Callback to find a named ancestor node.
462 *
463 * \param pw HTML document
464 * \param node DOM node
465 * \param qname Node name to search for
466 * \param ancestor Pointer to location to receive ancestor
467 * \return CSS_OK.
468 *
469 * \post \a ancestor will contain the result, or NULL if there is no match
470 */
471css_error named_ancestor_node(void *pw, void *node,
472 const css_qname *qname, void **ancestor)
473{
474 dom_element_named_ancestor_node(node, qname->name,
475 (struct dom_element **)ancestor);
476 dom_node_unref(*ancestor);
477
478 return CSS_OK;
479}
480
481/**
482 * Callback to find a named parent node
483 *
484 * \param pw HTML document
485 * \param node DOM node
486 * \param qname Node name to search for
487 * \param parent Pointer to location to receive parent
488 * \return CSS_OK.
489 *
490 * \post \a parent will contain the result, or NULL if there is no match
491 */
492css_error named_parent_node(void *pw, void *node,
493 const css_qname *qname, void **parent)
494{
495 dom_element_named_parent_node(node, qname->name,
496 (struct dom_element **)parent);
497 dom_node_unref(*parent);
498
499 return CSS_OK;
500}
501
502/**
503 * Callback to find a named sibling node.
504 *
505 * \param pw HTML document
506 * \param node DOM node
507 * \param qname Node name to search for
508 * \param sibling Pointer to location to receive sibling
509 * \return CSS_OK.
510 *
511 * \post \a sibling will contain the result, or NULL if there is no match
512 */
513css_error named_sibling_node(void *pw, void *node,
514 const css_qname *qname, void **sibling)
515{
516 dom_node *n = node;
517 dom_node *prev;
518 dom_exception err;
519
520 *sibling = NULL;
521
522 /* Find sibling element */
523 err = dom_node_get_previous_sibling(n, &n);
524 if (err != DOM_NO_ERR)
525 return CSS_OK;
526
527 while (n != NULL) {
528 dom_node_type type;
529
530 err = dom_node_get_node_type(n, &type);
531 if (err != DOM_NO_ERR) {
532 dom_node_unref(n);
533 return CSS_OK;
534 }
535
536 if (type == DOM_ELEMENT_NODE)
537 break;
538
539 err = dom_node_get_previous_sibling(n, &prev);
540 if (err != DOM_NO_ERR) {
541 dom_node_unref(n);
542 return CSS_OK;
543 }
544
545 dom_node_unref(n);
546 n = prev;
547 }
548
549 if (n != NULL) {
550 dom_string *name;
551
552 err = dom_node_get_node_name(n, &name);
553 if (err != DOM_NO_ERR) {
554 dom_node_unref(n);
555 return CSS_OK;
556 }
557
558 dom_node_unref(n);
559
560 if (dom_string_caseless_lwc_isequal(name, qname->name)) {
561 *sibling = n;
562 }
563
564 dom_string_unref(name);
565 }
566
567 return CSS_OK;
568}
569
570/**
571 * Callback to find a named generic sibling node.
572 *
573 * \param pw HTML document
574 * \param node DOM node
575 * \param qname Node name to search for
576 * \param sibling Pointer to location to receive ancestor
577 * \return CSS_OK.
578 *
579 * \post \a sibling will contain the result, or NULL if there is no match
580 */
581css_error named_generic_sibling_node(void *pw, void *node,
582 const css_qname *qname, void **sibling)
583{
584 dom_node *n = node;
585 dom_node *prev;
586 dom_exception err;
587
588 *sibling = NULL;
589
590 err = dom_node_get_previous_sibling(n, &n);
591 if (err != DOM_NO_ERR)
592 return CSS_OK;
593
594 while (n != NULL) {
595 dom_node_type type;
596 dom_string *name;
597
598 err = dom_node_get_node_type(n, &type);
599 if (err != DOM_NO_ERR) {
600 dom_node_unref(n);
601 return CSS_OK;
602 }
603
604 if (type == DOM_ELEMENT_NODE) {
605 err = dom_node_get_node_name(n, &name);
606 if (err != DOM_NO_ERR) {
607 dom_node_unref(n);
608 return CSS_OK;
609 }
610
611 if (dom_string_caseless_lwc_isequal(name,
612 qname->name)) {
613 dom_string_unref(name);
614 dom_node_unref(n);
615 *sibling = n;
616 break;
617 }
618 dom_string_unref(name);
619 }
620
621 err = dom_node_get_previous_sibling(n, &prev);
622 if (err != DOM_NO_ERR) {
623 dom_node_unref(n);
624 return CSS_OK;
625 }
626
627 dom_node_unref(n);
628 n = prev;
629 }
630
631 return CSS_OK;
632}
633
634/**
635 * Callback to retrieve the parent of a node.
636 *
637 * \param pw HTML document
638 * \param node DOM node
639 * \param parent Pointer to location to receive parent
640 * \return CSS_OK.
641 *
642 * \post \a parent will contain the result, or NULL if there is no match
643 */
644css_error parent_node(void *pw, void *node, void **parent)
645{
646 dom_element_parent_node(node, (struct dom_element **)parent);
647 dom_node_unref(*parent);
648
649 return CSS_OK;
650}
651
652/**
653 * Callback to retrieve the preceding sibling of a node.
654 *
655 * \param pw HTML document
656 * \param node DOM node
657 * \param sibling Pointer to location to receive sibling
658 * \return CSS_OK.
659 *
660 * \post \a sibling will contain the result, or NULL if there is no match
661 */
662css_error sibling_node(void *pw, void *node, void **sibling)
663{
664 dom_node *n = node;
665 dom_node *prev;
666 dom_exception err;
667
668 *sibling = NULL;
669
670 /* Find sibling element */
671 err = dom_node_get_previous_sibling(n, &n);
672 if (err != DOM_NO_ERR)
673 return CSS_OK;
674
675 while (n != NULL) {
676 dom_node_type type;
677
678 err = dom_node_get_node_type(n, &type);
679 if (err != DOM_NO_ERR) {
680 dom_node_unref(n);
681 return CSS_OK;
682 }
683
684 if (type == DOM_ELEMENT_NODE)
685 break;
686
687 err = dom_node_get_previous_sibling(n, &prev);
688 if (err != DOM_NO_ERR) {
689 dom_node_unref(n);
690 return CSS_OK;
691 }
692
693 dom_node_unref(n);
694 n = prev;
695 }
696
697 if (n != NULL) {
698 /** \todo Sort out reference counting */
699 dom_node_unref(n);
700
701 *sibling = n;
702 }
703
704 return CSS_OK;
705}
706
707/**
708 * Callback to determine if a node has the given name.
709 *
710 * \param pw HTML document
711 * \param node DOM node
712 * \param qname Name to match
713 * \param match Pointer to location to receive result
714 * \return CSS_OK.
715 *
716 * \post \a match will contain true if the node matches and false otherwise.
717 */
718css_error node_has_name(void *pw, void *node,
719 const css_qname *qname, bool *match)
720{
721 nscss_select_ctx *ctx = pw;
722 dom_node *n = node;
723
724 if (lwc_string_isequal(qname->name, ctx->universal, match) ==
725 lwc_error_ok && *match == false) {
726 dom_string *name;
727 dom_exception err;
728
729 err = dom_node_get_node_name(n, &name);
730 if (err != DOM_NO_ERR)
731 return CSS_OK;
732
733 /* Element names are case insensitive in HTML */
734 *match = dom_string_caseless_lwc_isequal(name, qname->name);
735
736 dom_string_unref(name);
737 }
738
739 return CSS_OK;
740}
741
742/**
743 * Callback to determine if a node has the given class.
744 *
745 * \param pw HTML document
746 * \param node DOM node
747 * \param name Name to match
748 * \param match Pointer to location to receive result
749 * \return CSS_OK.
750 *
751 * \post \a match will contain true if the node matches and false otherwise.
752 */
753css_error node_has_class(void *pw, void *node,
754 lwc_string *name, bool *match)
755{
756 dom_node *n = node;
757 dom_exception err;
758
759 /** \todo: Ensure that libdom performs case-insensitive
760 * matching in quirks mode */
761 err = dom_element_has_class(n, name, match);
762
763 assert(err == DOM_NO_ERR);
764
765 return CSS_OK;
766}
767
768/**
769 * Callback to determine if a node has the given id.
770 *
771 * \param pw HTML document
772 * \param node DOM node
773 * \param name Name to match
774 * \param match Pointer to location to receive result
775 * \return CSS_OK.
776 *
777 * \post \a match will contain true if the node matches and false otherwise.
778 */
779css_error node_has_id(void *pw, void *node,
780 lwc_string *name, bool *match)
781{
782 dom_node *n = node;
783 dom_string *attr;
784 dom_exception err;
785
786 *match = false;
787
788 /** \todo Assumes an HTML DOM */
789 err = dom_html_element_get_id(n, &attr);
790 if (err != DOM_NO_ERR)
791 return CSS_OK;
792
793 if (attr != NULL) {
794 *match = dom_string_lwc_isequal(attr, name);
795
796 dom_string_unref(attr);
797 }
798
799 return CSS_OK;
800}
801
802/**
803 * Callback to determine if a node has an attribute with the given name.
804 *
805 * \param pw HTML document
806 * \param node DOM node
807 * \param qname Name to match
808 * \param match Pointer to location to receive result
809 * \return CSS_OK on success,
810 * CSS_NOMEM on memory exhaustion.
811 *
812 * \post \a match will contain true if the node matches and false otherwise.
813 */
814css_error node_has_attribute(void *pw, void *node,
815 const css_qname *qname, bool *match)
816{
817 dom_node *n = node;
818 dom_string *name;
819 dom_exception err;
820
821 err = dom_string_create_interned(
822 (const uint8_t *) lwc_string_data(qname->name),
823 lwc_string_length(qname->name), &name);
824 if (err != DOM_NO_ERR)
825 return CSS_NOMEM;
826
827 err = dom_element_has_attribute(n, name, match);
828 if (err != DOM_NO_ERR) {
829 dom_string_unref(name);
830 return CSS_OK;
831 }
832
833 dom_string_unref(name);
834
835 return CSS_OK;
836}
837
838/**
839 * Callback to determine if a node has an attribute with given name and value.
840 *
841 * \param pw HTML document
842 * \param node DOM node
843 * \param qname Name to match
844 * \param value Value to match
845 * \param match Pointer to location to receive result
846 * \return CSS_OK on success,
847 * CSS_NOMEM on memory exhaustion.
848 *
849 * \post \a match will contain true if the node matches and false otherwise.
850 */
851css_error node_has_attribute_equal(void *pw, void *node,
852 const css_qname *qname, lwc_string *value,
853 bool *match)
854{
855 dom_node *n = node;
856 dom_string *name;
857 dom_string *atr_val;
858 dom_exception err;
859
860 size_t vlen = lwc_string_length(value);
861
862 if (vlen == 0) {
863 *match = false;
864 return CSS_OK;
865 }
866
867 err = dom_string_create_interned(
868 (const uint8_t *) lwc_string_data(qname->name),
869 lwc_string_length(qname->name), &name);
870 if (err != DOM_NO_ERR)
871 return CSS_NOMEM;
872
873 err = dom_element_get_attribute(n, name, &atr_val);
874 if ((err != DOM_NO_ERR) || (atr_val == NULL)) {
875 dom_string_unref(name);
876 *match = false;
877 return CSS_OK;
878 }
879
880 dom_string_unref(name);
881
882 *match = dom_string_caseless_lwc_isequal(atr_val, value);
883
884 dom_string_unref(atr_val);
885
886 return CSS_OK;
887}
888
889/**
890 * Callback to determine if a node has an attribute with the given name whose
891 * value dashmatches that given.
892 *
893 * \param pw HTML document
894 * \param node DOM node
895 * \param qname Name to match
896 * \param value Value to match
897 * \param match Pointer to location to receive result
898 * \return CSS_OK on success,
899 * CSS_NOMEM on memory exhaustion.
900 *
901 * \post \a match will contain true if the node matches and false otherwise.
902 */
903css_error node_has_attribute_dashmatch(void *pw, void *node,
904 const css_qname *qname, lwc_string *value,
905 bool *match)
906{
907 dom_node *n = node;
908 dom_string *name;
909 dom_string *atr_val;
910 dom_exception err;
911
912 size_t vlen = lwc_string_length(value);
913
914 if (vlen == 0) {
915 *match = false;
916 return CSS_OK;
917 }
918
919 err = dom_string_create_interned(
920 (const uint8_t *) lwc_string_data(qname->name),
921 lwc_string_length(qname->name), &name);
922 if (err != DOM_NO_ERR)
923 return CSS_NOMEM;
924
925 err = dom_element_get_attribute(n, name, &atr_val);
926 if ((err != DOM_NO_ERR) || (atr_val == NULL)) {
927 dom_string_unref(name);
928 *match = false;
929 return CSS_OK;
930 }
931
932 dom_string_unref(name);
933
934 /* check for exact match */
935 *match = dom_string_caseless_lwc_isequal(atr_val, value);
936
937 /* check for dashmatch */
938 if (*match == false) {
939 const char *vdata = lwc_string_data(value);
940 const char *data = (const char *) dom_string_data(atr_val);
941 size_t len = dom_string_byte_length(atr_val);
942
943 if (len > vlen && data[vlen] == '-' &&
944 strncasecmp(data, vdata, vlen) == 0) {
945 *match = true;
946 }
947 }
948
949 dom_string_unref(atr_val);
950
951 return CSS_OK;
952}
953
954/**
955 * Callback to determine if a node has an attribute with the given name whose
956 * value includes that given.
957 *
958 * \param pw HTML document
959 * \param node DOM node
960 * \param qname Name to match
961 * \param value Value to match
962 * \param match Pointer to location to receive result
963 * \return CSS_OK on success,
964 * CSS_NOMEM on memory exhaustion.
965 *
966 * \post \a match will contain true if the node matches and false otherwise.
967 */
968css_error node_has_attribute_includes(void *pw, void *node,
969 const css_qname *qname, lwc_string *value,
970 bool *match)
971{
972 dom_node *n = node;
973 dom_string *name;
974 dom_string *atr_val;
975 dom_exception err;
976 size_t vlen = lwc_string_length(value);
977 const char *p;
978 const char *start;
979 const char *end;
980
981 *match = false;
982
983 if (vlen == 0) {
984 return CSS_OK;
985 }
986
987 err = dom_string_create_interned(
988 (const uint8_t *) lwc_string_data(qname->name),
989 lwc_string_length(qname->name), &name);
990 if (err != DOM_NO_ERR)
991 return CSS_NOMEM;
992
993 err = dom_element_get_attribute(n, name, &atr_val);
994 if ((err != DOM_NO_ERR) || (atr_val == NULL)) {
995 dom_string_unref(name);
996 *match = false;
997 return CSS_OK;
998 }
999
1000 dom_string_unref(name);
1001
1002 /* check for match */
1003 start = (const char *) dom_string_data(atr_val);
1004 end = start + dom_string_byte_length(atr_val);
1005
1006 for (p = start; p <= end; p++) {
1007 if (*p == ' ' || *p == '\0') {
1008 if ((size_t) (p - start) == vlen &&
1009 strncasecmp(start,
1010 lwc_string_data(value),
1011 vlen) == 0) {
1012 *match = true;
1013 break;
1014 }
1015
1016 start = p + 1;
1017 }
1018 }
1019
1020 dom_string_unref(atr_val);
1021
1022 return CSS_OK;
1023}
1024
1025/**
1026 * Callback to determine if a node has an attribute with the given name whose
1027 * value has the prefix given.
1028 *
1029 * \param pw HTML document
1030 * \param node DOM node
1031 * \param qname Name to match
1032 * \param value Value to match
1033 * \param match Pointer to location to receive result
1034 * \return CSS_OK on success,
1035 * CSS_NOMEM on memory exhaustion.
1036 *
1037 * \post \a match will contain true if the node matches and false otherwise.
1038 */
1039css_error node_has_attribute_prefix(void *pw, void *node,
1040 const css_qname *qname, lwc_string *value,
1041 bool *match)
1042{
1043 dom_node *n = node;
1044 dom_string *name;
1045 dom_string *atr_val;
1046 dom_exception err;
1047
1048 size_t vlen = lwc_string_length(value);
1049
1050 if (vlen == 0) {
1051 *match = false;
1052 return CSS_OK;
1053 }
1054
1055 err = dom_string_create_interned(
1056 (const uint8_t *) lwc_string_data(qname->name),
1057 lwc_string_length(qname->name), &name);
1058 if (err != DOM_NO_ERR)
1059 return CSS_NOMEM;
1060
1061 err = dom_element_get_attribute(n, name, &atr_val);
1062 if ((err != DOM_NO_ERR) || (atr_val == NULL)) {
1063 dom_string_unref(name);
1064 *match = false;
1065 return CSS_OK;
1066 }
1067
1068 dom_string_unref(name);
1069
1070 /* check for exact match */
1071 *match = dom_string_caseless_lwc_isequal(atr_val, value);
1072
1073 /* check for prefix match */
1074 if (*match == false) {
1075 const char *data = (const char *) dom_string_data(atr_val);
1076 size_t len = dom_string_byte_length(atr_val);
1077
1078 if ((len >= vlen) &&
1079 (strncasecmp(data, lwc_string_data(value), vlen) == 0)) {
1080 *match = true;
1081 }
1082 }
1083
1084 dom_string_unref(atr_val);
1085
1086 return CSS_OK;
1087}
1088
1089/**
1090 * Callback to determine if a node has an attribute with the given name whose
1091 * value has the suffix given.
1092 *
1093 * \param pw HTML document
1094 * \param node DOM node
1095 * \param qname Name to match
1096 * \param value Value to match
1097 * \param match Pointer to location to receive result
1098 * \return CSS_OK on success,
1099 * CSS_NOMEM on memory exhaustion.
1100 *
1101 * \post \a match will contain true if the node matches and false otherwise.
1102 */
1103css_error node_has_attribute_suffix(void *pw, void *node,
1104 const css_qname *qname, lwc_string *value,
1105 bool *match)
1106{
1107 dom_node *n = node;
1108 dom_string *name;
1109 dom_string *atr_val;
1110 dom_exception err;
1111
1112 size_t vlen = lwc_string_length(value);
1113
1114 if (vlen == 0) {
1115 *match = false;
1116 return CSS_OK;
1117 }
1118
1119 err = dom_string_create_interned(
1120 (const uint8_t *) lwc_string_data(qname->name),
1121 lwc_string_length(qname->name), &name);
1122 if (err != DOM_NO_ERR)
1123 return CSS_NOMEM;
1124
1125 err = dom_element_get_attribute(n, name, &atr_val);
1126 if ((err != DOM_NO_ERR) || (atr_val == NULL)) {
1127 dom_string_unref(name);
1128 *match = false;
1129 return CSS_OK;
1130 }
1131
1132 dom_string_unref(name);
1133
1134 /* check for exact match */
1135 *match = dom_string_caseless_lwc_isequal(atr_val, value);
1136
1137 /* check for prefix match */
1138 if (*match == false) {
1139 const char *data = (const char *) dom_string_data(atr_val);
1140 size_t len = dom_string_byte_length(atr_val);
1141
1142 const char *start = (char *) data + len - vlen;
1143
1144 if ((len >= vlen) &&
1145 (strncasecmp(start, lwc_string_data(value), vlen) == 0)) {
1146 *match = true;
1147 }
1148
1149
1150 }
1151
1152 dom_string_unref(atr_val);
1153
1154 return CSS_OK;
1155}
1156
1157/**
1158 * Callback to determine if a node has an attribute with the given name whose
1159 * value contains the substring given.
1160 *
1161 * \param pw HTML document
1162 * \param node DOM node
1163 * \param qname Name to match
1164 * \param value Value to match
1165 * \param match Pointer to location to receive result
1166 * \return CSS_OK on success,
1167 * CSS_NOMEM on memory exhaustion.
1168 *
1169 * \post \a match will contain true if the node matches and false otherwise.
1170 */
1171css_error node_has_attribute_substring(void *pw, void *node,
1172 const css_qname *qname, lwc_string *value,
1173 bool *match)
1174{
1175 dom_node *n = node;
1176 dom_string *name;
1177 dom_string *atr_val;
1178 dom_exception err;
1179
1180 size_t vlen = lwc_string_length(value);
1181
1182 if (vlen == 0) {
1183 *match = false;
1184 return CSS_OK;
1185 }
1186
1187 err = dom_string_create_interned(
1188 (const uint8_t *) lwc_string_data(qname->name),
1189 lwc_string_length(qname->name), &name);
1190 if (err != DOM_NO_ERR)
1191 return CSS_NOMEM;
1192
1193 err = dom_element_get_attribute(n, name, &atr_val);
1194 if ((err != DOM_NO_ERR) || (atr_val == NULL)) {
1195 dom_string_unref(name);
1196 *match = false;
1197 return CSS_OK;
1198 }
1199
1200 dom_string_unref(name);
1201
1202 /* check for exact match */
1203 *match = dom_string_caseless_lwc_isequal(atr_val, value);
1204
1205 /* check for prefix match */
1206 if (*match == false) {
1207 const char *vdata = lwc_string_data(value);
1208 const char *start = (const char *) dom_string_data(atr_val);
1209 size_t len = dom_string_byte_length(atr_val);
1210 const char *last_start = start + len - vlen;
1211
1212 if (len >= vlen) {
1213 while (start <= last_start) {
1214 if (strncasecmp(start, vdata,
1215 vlen) == 0) {
1216 *match = true;
1217 break;
1218 }
1219
1220 start++;
1221 }
1222 }
1223 }
1224
1225 dom_string_unref(atr_val);
1226
1227 return CSS_OK;
1228}
1229
1230/**
1231 * Callback to determine if a node is the root node of the document.
1232 *
1233 * \param pw HTML document
1234 * \param node DOM node
1235 * \param match Pointer to location to receive result
1236 * \return CSS_OK.
1237 *
1238 * \post \a match will contain true if the node matches and false otherwise.
1239 */
1240css_error node_is_root(void *pw, void *node, bool *match)
1241{
1242 dom_node *n = node;
1243 dom_node *parent;
1244 dom_node_type type;
1245 dom_exception err;
1246
1247 err = dom_node_get_parent_node(n, &parent);
1248 if (err != DOM_NO_ERR) {
1249 return CSS_NOMEM;
1250 }
1251
1252 if (parent != NULL) {
1253 err = dom_node_get_node_type(parent, &type);
1254
1255 dom_node_unref(parent);
1256
1257 if (err != DOM_NO_ERR)
1258 return CSS_NOMEM;
1259
1260 if (type != DOM_DOCUMENT_NODE) {
1261 *match = false;
1262 return CSS_OK;
1263 }
1264 }
1265
1266 *match = true;
1267
1268 return CSS_OK;
1269}
1270
1271static int
1273 bool check_name,
1274 dom_string *name)
1275{
1276 dom_node_type type;
1277 int ret = 0;
1278 dom_exception exc;
1279
1280 if (node == NULL)
1281 return 0;
1282
1283 exc = dom_node_get_node_type(node, &type);
1284 if ((exc != DOM_NO_ERR) || (type != DOM_ELEMENT_NODE)) {
1285 return 0;
1286 }
1287
1288 if (check_name) {
1289 dom_string *node_name = NULL;
1290 exc = dom_node_get_node_name(node, &node_name);
1291
1292 if ((exc == DOM_NO_ERR) && (node_name != NULL)) {
1293
1294 if (dom_string_caseless_isequal(name,
1295 node_name)) {
1296 ret = 1;
1297 }
1298 dom_string_unref(node_name);
1299 }
1300 } else {
1301 ret = 1;
1302 }
1303
1304 return ret;
1305}
1306
1307/**
1308 * Callback to count a node's siblings.
1309 *
1310 * \param pw HTML document
1311 * \param n DOM node
1312 * \param same_name Only count siblings with the same name, or all
1313 * \param after Count anteceding instead of preceding siblings
1314 * \param count Pointer to location to receive result
1315 * \return CSS_OK.
1316 *
1317 * \post \a count will contain the number of siblings
1318 */
1319css_error node_count_siblings(void *pw, void *n, bool same_name,
1320 bool after, int32_t *count)
1321{
1322 int32_t cnt = 0;
1323 dom_exception exc;
1324 dom_string *node_name = NULL;
1325
1326 if (same_name) {
1327 dom_node *node = n;
1328 exc = dom_node_get_node_name(node, &node_name);
1329 if ((exc != DOM_NO_ERR) || (node_name == NULL)) {
1330 return CSS_NOMEM;
1331 }
1332 }
1333
1334 if (after) {
1335 dom_node *node = dom_node_ref(n);
1336 dom_node *next;
1337
1338 do {
1339 exc = dom_node_get_next_sibling(node, &next);
1340 if ((exc != DOM_NO_ERR))
1341 break;
1342
1343 dom_node_unref(node);
1344 node = next;
1345
1346 cnt += node_count_siblings_check(node, same_name, node_name);
1347 } while (node != NULL);
1348 } else {
1349 dom_node *node = dom_node_ref(n);
1350 dom_node *next;
1351
1352 do {
1353 exc = dom_node_get_previous_sibling(node, &next);
1354 if ((exc != DOM_NO_ERR))
1355 break;
1356
1357 dom_node_unref(node);
1358 node = next;
1359
1360 cnt += node_count_siblings_check(node, same_name, node_name);
1361
1362 } while (node != NULL);
1363 }
1364
1365 if (node_name != NULL) {
1366 dom_string_unref(node_name);
1367 }
1368
1369 *count = cnt;
1370 return CSS_OK;
1371}
1372
1373/**
1374 * Callback to determine if a node is empty.
1375 *
1376 * \param pw HTML document
1377 * \param node DOM node
1378 * \param match Pointer to location to receive result
1379 * \return CSS_OK.
1380 *
1381 * \post \a match will contain true if the node is empty and false otherwise.
1382 */
1383css_error node_is_empty(void *pw, void *node, bool *match)
1384{
1385 dom_node *n = node, *next;
1386 dom_exception err;
1387
1388 *match = true;
1389
1390 err = dom_node_get_first_child(n, &n);
1391 if (err != DOM_NO_ERR) {
1392 return CSS_BADPARM;
1393 }
1394
1395 while (n != NULL) {
1396 dom_node_type ntype;
1397 err = dom_node_get_node_type(n, &ntype);
1398 if (err != DOM_NO_ERR) {
1399 dom_node_unref(n);
1400 return CSS_BADPARM;
1401 }
1402
1403 if (ntype == DOM_ELEMENT_NODE ||
1404 ntype == DOM_TEXT_NODE) {
1405 *match = false;
1406 dom_node_unref(n);
1407 break;
1408 }
1409
1410 err = dom_node_get_next_sibling(n, &next);
1411 if (err != DOM_NO_ERR) {
1412 dom_node_unref(n);
1413 return CSS_BADPARM;
1414 }
1415 dom_node_unref(n);
1416 n = next;
1417 }
1418
1419 return CSS_OK;
1420}
1421
1422/**
1423 * Callback to determine if a node is a linking element.
1424 *
1425 * \param pw HTML document
1426 * \param n DOM node
1427 * \param match Pointer to location to receive result
1428 * \return CSS_OK.
1429 *
1430 * \post \a match will contain true if the node matches and false otherwise.
1431 */
1432css_error node_is_link(void *pw, void *n, bool *match)
1433{
1434 dom_node *node = n;
1435 dom_exception exc;
1436 dom_string *node_name = NULL;
1437
1438 exc = dom_node_get_node_name(node, &node_name);
1439 if ((exc != DOM_NO_ERR) || (node_name == NULL)) {
1440 return CSS_NOMEM;
1441 }
1442
1443 if (dom_string_caseless_lwc_isequal(node_name, corestring_lwc_a)) {
1444 bool has_href;
1445 exc = dom_element_has_attribute(node, corestring_dom_href,
1446 &has_href);
1447 if ((exc == DOM_NO_ERR) && (has_href)) {
1448 *match = true;
1449 } else {
1450 *match = false;
1451 }
1452 } else {
1453 *match = false;
1454 }
1455 dom_string_unref(node_name);
1456
1457 return CSS_OK;
1458}
1459
1460/**
1461 * Callback to determine if a node is a linking element whose target has been
1462 * visited.
1463 *
1464 * \param pw HTML document
1465 * \param node DOM node
1466 * \param match Pointer to location to receive result
1467 * \return CSS_OK.
1468 *
1469 * \post \a match will contain true if the node matches and false otherwise.
1470 */
1471css_error node_is_visited(void *pw, void *node, bool *match)
1472{
1473 nscss_select_ctx *ctx = pw;
1474 nsurl *url;
1475 nserror error;
1476 const struct url_data *data;
1477
1478 dom_exception exc;
1479 dom_node *n = node;
1480 dom_string *s = NULL;
1481
1482 *match = false;
1483
1484 exc = dom_node_get_node_name(n, &s);
1485 if ((exc != DOM_NO_ERR) || (s == NULL)) {
1486 return CSS_NOMEM;
1487 }
1488
1489 if (!dom_string_caseless_lwc_isequal(s, corestring_lwc_a)) {
1490 /* Can't be visited; not ancher element */
1491 dom_string_unref(s);
1492 return CSS_OK;
1493 }
1494
1495 /* Finished with node name string */
1496 dom_string_unref(s);
1497 s = NULL;
1498
1499 exc = dom_element_get_attribute(n, corestring_dom_href, &s);
1500 if ((exc != DOM_NO_ERR) || (s == NULL)) {
1501 /* Can't be visited; not got a URL */
1502 return CSS_OK;
1503 }
1504
1505 /* Make href absolute */
1506 /* TODO: this duplicates what we do for box->href
1507 * should we put the absolute URL on the dom node? */
1508 error = nsurl_join(ctx->base_url, dom_string_data(s), &url);
1509
1510 /* Finished with href string */
1511 dom_string_unref(s);
1512
1513 if (error != NSERROR_OK) {
1514 /* Couldn't make nsurl object */
1515 return CSS_NOMEM;
1516 }
1517
1518 data = urldb_get_url_data(url);
1519
1520 /* Visited if in the db and has
1521 * non-zero visit count */
1522 if (data != NULL && data->visits > 0)
1523 *match = true;
1524
1525 nsurl_unref(url);
1526
1527 return CSS_OK;
1528}
1529
1530/**
1531 * Callback to determine if a node is currently being hovered over.
1532 *
1533 * \param pw HTML document
1534 * \param node DOM node
1535 * \param match Pointer to location to receive result
1536 * \return CSS_OK.
1537 *
1538 * \post \a match will contain true if the node matches and false otherwise.
1539 */
1540css_error node_is_hover(void *pw, void *node, bool *match)
1541{
1542 /** \todo Support hovering */
1543
1544 *match = false;
1545
1546 return CSS_OK;
1547}
1548
1549/**
1550 * Callback to determine if a node is currently activated.
1551 *
1552 * \param pw HTML document
1553 * \param node DOM node
1554 * \param match Pointer to location to receive result
1555 * \return CSS_OK.
1556 *
1557 * \post \a match will contain true if the node matches and false otherwise.
1558 */
1559css_error node_is_active(void *pw, void *node, bool *match)
1560{
1561 /** \todo Support active nodes */
1562
1563 *match = false;
1564
1565 return CSS_OK;
1566}
1567
1568/**
1569 * Callback to determine if a node has the input focus.
1570 *
1571 * \param pw HTML document
1572 * \param node DOM node
1573 * \param match Pointer to location to receive result
1574 * \return CSS_OK.
1575 *
1576 * \post \a match will contain true if the node matches and false otherwise.
1577 */
1578css_error node_is_focus(void *pw, void *node, bool *match)
1579{
1580 /** \todo Support focussed nodes */
1581
1582 *match = false;
1583
1584 return CSS_OK;
1585}
1586
1587/**
1588 * Callback to determine if a node is enabled.
1589 *
1590 * \param pw HTML document
1591 * \param node DOM node
1592 * \param match Pointer to location to receive result
1593 * \return CSS_OK.
1594 *
1595 * \post \a match with contain true if the node is enabled and false otherwise.
1596 */
1597css_error node_is_enabled(void *pw, void *node, bool *match)
1598{
1599 /** \todo Support enabled nodes */
1600
1601 *match = false;
1602
1603 return CSS_OK;
1604}
1605
1606/**
1607 * Callback to determine if a node is disabled.
1608 *
1609 * \param pw HTML document
1610 * \param node DOM node
1611 * \param match Pointer to location to receive result
1612 * \return CSS_OK.
1613 *
1614 * \post \a match with contain true if the node is disabled and false otherwise.
1615 */
1616css_error node_is_disabled(void *pw, void *node, bool *match)
1617{
1618 /** \todo Support disabled nodes */
1619
1620 *match = false;
1621
1622 return CSS_OK;
1623}
1624
1625/**
1626 * Callback to determine if a node is checked.
1627 *
1628 * \param pw HTML document
1629 * \param node DOM node
1630 * \param match Pointer to location to receive result
1631 * \return CSS_OK.
1632 *
1633 * \post \a match with contain true if the node is checked and false otherwise.
1634 */
1635css_error node_is_checked(void *pw, void *node, bool *match)
1636{
1637 /** \todo Support checked nodes */
1638
1639 *match = false;
1640
1641 return CSS_OK;
1642}
1643
1644/**
1645 * Callback to determine if a node is the target of the document URL.
1646 *
1647 * \param pw HTML document
1648 * \param node DOM node
1649 * \param match Pointer to location to receive result
1650 * \return CSS_OK.
1651 *
1652 * \post \a match with contain true if the node matches and false otherwise.
1653 */
1654css_error node_is_target(void *pw, void *node, bool *match)
1655{
1656 /** \todo Support target */
1657
1658 *match = false;
1659
1660 return CSS_OK;
1661}
1662
1663/**
1664 * Callback to determine if a node has the given language
1665 *
1666 * \param pw HTML document
1667 * \param node DOM node
1668 * \param lang Language specifier to match
1669 * \param match Pointer to location to receive result
1670 * \return CSS_OK.
1671 *
1672 * \post \a match will contain true if the node matches and false otherwise.
1673 */
1674css_error node_is_lang(void *pw, void *node,
1675 lwc_string *lang, bool *match)
1676{
1677 /** \todo Support languages */
1678
1679 *match = false;
1680
1681 return CSS_OK;
1682}
1683
1684/**
1685 * Callback to retrieve the User-Agent defaults for a CSS property.
1686 *
1687 * \param pw HTML document
1688 * \param property Property to retrieve defaults for
1689 * \param hint Pointer to hint object to populate
1690 * \return CSS_OK on success,
1691 * CSS_INVALID if the property should not have a user-agent default.
1692 */
1693css_error ua_default_for_property(void *pw, uint32_t property, css_hint *hint)
1694{
1695 if (property == CSS_PROP_COLOR) {
1696 hint->data.color = 0xff000000;
1697 hint->status = CSS_COLOR_COLOR;
1698 } else if (property == CSS_PROP_FONT_FAMILY) {
1699 hint->data.strings = NULL;
1700 switch (nsoption_int(font_default)) {
1702 hint->status = CSS_FONT_FAMILY_SANS_SERIF;
1703 break;
1705 hint->status = CSS_FONT_FAMILY_SERIF;
1706 break;
1708 hint->status = CSS_FONT_FAMILY_MONOSPACE;
1709 break;
1711 hint->status = CSS_FONT_FAMILY_CURSIVE;
1712 break;
1714 hint->status = CSS_FONT_FAMILY_FANTASY;
1715 break;
1716 }
1717 } else if (property == CSS_PROP_QUOTES) {
1718 /** \todo Not exactly useful :) */
1719 hint->data.strings = NULL;
1720 hint->status = CSS_QUOTES_NONE;
1721 } else if (property == CSS_PROP_VOICE_FAMILY) {
1722 /** \todo Fix this when we have voice-family done */
1723 hint->data.strings = NULL;
1724 hint->status = 0;
1725 } else {
1726 return CSS_INVALID;
1727 }
1728
1729 return CSS_OK;
1730}
1731
1732css_error set_libcss_node_data(void *pw, void *node, void *libcss_node_data)
1733{
1734 dom_node *n = node;
1735 dom_exception err;
1736 void *old_node_data;
1737
1738 /* Set this node's node data */
1739 err = dom_node_set_user_data(n,
1740 corestring_dom___ns_key_libcss_node_data,
1741 libcss_node_data, nscss_dom_user_data_handler,
1742 (void *) &old_node_data);
1743 if (err != DOM_NO_ERR) {
1744 return CSS_NOMEM;
1745 }
1746
1747 assert(old_node_data == NULL);
1748
1749 return CSS_OK;
1750}
1751
1752css_error get_libcss_node_data(void *pw, void *node, void **libcss_node_data)
1753{
1754 dom_node *n = node;
1755 dom_exception err;
1756
1757 /* Get this node's node data */
1758 err = dom_node_get_user_data(n,
1759 corestring_dom___ns_key_libcss_node_data,
1760 libcss_node_data);
1761 if (err != DOM_NO_ERR) {
1762 return CSS_NOMEM;
1763 }
1764
1765 return CSS_OK;
1766}
static uint32_t count(const http_directive *list, lwc_string *key)
Useful interned string pointers (interface).
wimp_w parent
Definition: dialog.c:88
nserror
Enumeration of error codes.
Definition: errors.h:29
@ 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
css_error nscss_resolve_url(void *pw, const char *base, lwc_string *rel, lwc_string **abs)
URL resolution callback for libcss.
Definition: internal.c:27
#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.
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
plotter style interfaces, generic styles and style colour helpers.
@ PLOT_FONT_FAMILY_CURSIVE
Definition: plot_style.h:92
@ PLOT_FONT_FAMILY_SANS_SERIF
Definition: plot_style.h:89
@ PLOT_FONT_FAMILY_FANTASY
Definition: plot_style.h:93
@ PLOT_FONT_FAMILY_MONOSPACE
Definition: plot_style.h:91
@ PLOT_FONT_FAMILY_SERIF
Definition: plot_style.h:90
static void nscss_dom_user_data_handler(dom_node_operation operation, dom_string *key, void *data, struct dom_node *src, struct dom_node *dst)
Definition: select.c:195
static css_error node_is_focus(void *pw, void *node, bool *match)
Callback to determine if a node has the input focus.
Definition: select.c:1578
static css_error node_has_attribute(void *pw, void *node, const css_qname *qname, bool *match)
Callback to determine if a node has an attribute with the given name.
Definition: select.c:814
static css_error named_sibling_node(void *pw, void *node, const css_qname *qname, void **sibling)
Callback to find a named sibling node.
Definition: select.c:513
static css_error node_has_attribute_suffix(void *pw, void *node, const css_qname *qname, lwc_string *value, bool *match)
Callback to determine if a node has an attribute with the given name whose value has the suffix given...
Definition: select.c:1103
static css_error node_has_id(void *pw, void *node, lwc_string *name, bool *match)
Callback to determine if a node has the given id.
Definition: select.c:779
static css_error node_has_attribute_substring(void *pw, void *node, const css_qname *qname, lwc_string *value, bool *match)
Callback to determine if a node has an attribute with the given name whose value contains the substri...
Definition: select.c:1171
static css_error set_libcss_node_data(void *pw, void *node, void *libcss_node_data)
Definition: select.c:1732
css_select_results * nscss_get_style(nscss_select_ctx *ctx, dom_node *n, const css_media *media, const css_unit_ctx *unit_len_ctx, const css_stylesheet *inline_style)
Get style selection results for an element.
Definition: select.c:253
static css_error ua_default_for_property(void *pw, uint32_t property, css_hint *hint)
Callback to retrieve the User-Agent defaults for a CSS property.
Definition: select.c:1693
static css_error node_has_attribute_equal(void *pw, void *node, const css_qname *qname, lwc_string *value, bool *match)
Callback to determine if a node has an attribute with given name and value.
Definition: select.c:851
css_stylesheet * nscss_create_inline_style(const uint8_t *data, size_t len, const char *charset, const char *url, bool allow_quirks)
Create an inline style.
Definition: select.c:148
static css_error node_has_class(void *pw, void *node, lwc_string *name, bool *match)
Callback to determine if a node has the given class.
Definition: select.c:753
static css_error node_is_enabled(void *pw, void *node, bool *match)
Callback to determine if a node is enabled.
Definition: select.c:1597
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
static css_error node_is_root(void *pw, void *node, bool *match)
Callback to determine if a node is the root node of the document.
Definition: select.c:1240
static css_error node_has_attribute_includes(void *pw, void *node, const css_qname *qname, lwc_string *value, bool *match)
Callback to determine if a node has an attribute with the given name whose value includes that given.
Definition: select.c:968
static css_error node_is_link(void *pw, void *node, bool *match)
Callback to determine if a node is a linking element.
Definition: select.c:1432
static css_error node_is_hover(void *pw, void *node, bool *match)
Callback to determine if a node is currently being hovered over.
Definition: select.c:1540
static css_error node_has_attribute_dashmatch(void *pw, void *node, const css_qname *qname, lwc_string *value, bool *match)
Callback to determine if a node has an attribute with the given name whose value dashmatches that giv...
Definition: select.c:903
static int node_count_siblings_check(dom_node *node, bool check_name, dom_string *name)
Definition: select.c:1272
static css_error get_libcss_node_data(void *pw, void *node, void **libcss_node_data)
Definition: select.c:1752
static css_error node_count_siblings(void *pw, void *node, bool same_name, bool after, int32_t *count)
Callback to count a node's siblings.
Definition: select.c:1319
static css_error sibling_node(void *pw, void *node, void **sibling)
Callback to retrieve the preceding sibling of a node.
Definition: select.c:662
static css_error node_is_target(void *pw, void *node, bool *match)
Callback to determine if a node is the target of the document URL.
Definition: select.c:1654
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
static css_error node_has_attribute_prefix(void *pw, void *node, const css_qname *qname, lwc_string *value, bool *match)
Callback to determine if a node has an attribute with the given name whose value has the prefix given...
Definition: select.c:1039
static css_select_handler selection_handler
Selection callback table for libcss.
Definition: select.c:97
static css_error node_is_empty(void *pw, void *node, bool *match)
Callback to determine if a node is empty.
Definition: select.c:1383
static css_error node_classes(void *pw, void *node, lwc_string ***classes, uint32_t *n_classes)
Callback to retrieve a node's classes.
Definition: select.c:410
static css_error named_parent_node(void *pw, void *node, const css_qname *qname, void **parent)
Callback to find a named parent node.
Definition: select.c:492
css_computed_style * nscss_get_blank_style(nscss_select_ctx *ctx, const css_unit_ctx *unit_len_ctx, const css_computed_style *parent)
Get a blank style.
Definition: select.c:334
static css_error node_is_active(void *pw, void *node, bool *match)
Callback to determine if a node is currently activated.
Definition: select.c:1559
static css_error parent_node(void *pw, void *node, void **parent)
Callback to retrieve the parent of a node.
Definition: select.c:644
static css_error node_is_checked(void *pw, void *node, bool *match)
Callback to determine if a node is checked.
Definition: select.c:1635
static css_error node_is_lang(void *pw, void *node, lwc_string *lang, bool *match)
Callback to determine if a node has the given language.
Definition: select.c:1674
static css_error node_name(void *pw, void *node, css_qname *qname)
Callback to retrieve a node's name.
Definition: select.c:373
static css_error named_generic_sibling_node(void *pw, void *node, const css_qname *qname, void **sibling)
Callback to find a named generic sibling node.
Definition: select.c:581
static css_error node_has_name(void *pw, void *node, const css_qname *qname, bool *match)
Callback to determine if a node has the given name.
Definition: select.c:718
static css_error node_is_disabled(void *pw, void *node, bool *match)
Callback to determine if a node is disabled.
Definition: select.c:1616
static css_error node_id(void *pw, void *node, lwc_string **id)
Callback to retrieve a node's ID.
Definition: select.c:435
Interface to utility string handling.
Selection context.
Definition: select.h:35
struct nsurl * base_url
Definition: select.h:38
css_select_ctx * ctx
Definition: select.h:36
lwc_string * universal
Definition: select.h:39
const css_computed_style * parent_style
Definition: select.h:41
unsigned int visits
Visit count.
Definition: url_db.h:38
css_error ns_system_colour(void *pw, lwc_string *name, css_color *colour)
css callback to obtain named system colour.
Definition: system_colour.c:95
Interface to system colour values.
Unified URL information database public interface.
const struct url_data * urldb_get_url_data(struct nsurl *url)
Find data for an URL.
Definition: urldb.c:3309
Option reading and saving interface.
#define nsoption_int(OPTION)
Get the value of an integer option.
Definition: nsoption.h:313