home *** CD-ROM | disk | FTP | other *** search
- /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * The contents of this file are subject to the Netscape Public License
- * Version 1.0 (the "NPL"); you may not use this file except in
- * compliance with the NPL. You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- *
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- *
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All Rights
- * Reserved.
- */
-
- #include "xp.h"
- #include "libstyle.h"
- #include "jsapi.h"
- #include "xp_mcom.h"
- #include "jsspriv.h"
- #include "jssrules.h"
-
- /*
- * Helper routine to determine whether the array of simple selectors matches
- * the selectors for the specified rule
- */
- static JSBool
- jss_IsSelectorEqual(JSContext *mc,
- StyleRule *rule,
- unsigned nSelectors,
- jsval *selectors)
- {
- unsigned i;
-
- if (rule->nSelectors == nSelectors) {
- for (i = 0; i < rule->nSelectors; i++) {
- /* We expect each simple selector to be a JavaScript object */
- XP_ASSERT(JSVAL_IS_OBJECT(selectors[i]));
-
- /* The simple selectors match if they point to the same StyleTag structure */
- if (rule->selectors[i] != JS_GetPrivate(mc, (JSObject *)selectors[i]))
- return JS_FALSE;
- }
-
- return JS_TRUE;
- }
-
- return JS_FALSE;
- }
-
- /*
- * Given a list of rules and a contextual selector (array of simple
- * selectors), looks to see if the contextual selector matches an
- * existing rule
- *
- * Returns the rule if successful, and 0 otherwise
- */
- StyleRule *
- jss_LookupRule(JSContext *mc,
- StyleRule *rules,
- unsigned nSelectors,
- jsval *selectors)
- {
- while (rules) {
- if (jss_IsSelectorEqual(mc, rules, nSelectors, selectors))
- return rules;
-
- rules = rules->next;
- }
-
- return 0;
- }
-
- /* This routine creates and returns a new rule */
- StyleRule *
- jss_NewRule(JSContext *mc, unsigned argc, jsval *argv)
- {
- StyleRule *rule;
- unsigned i;
-
- /* Create a new rule */
- rule = (StyleRule *)XP_CALLOC(1, sizeof(StyleRule));
- if (!rule) {
- JS_ReportOutOfMemory(mc);
- return 0;
- }
-
- /* Initialize the list of selectors. While we're at it compute the specificity */
- rule->nSelectors = argc;
- rule->selectors = XP_CALLOC((size_t)rule->nSelectors, sizeof(StyleTag *));
- rule->tag.specificity = 0;
-
- for (i = 0; i < rule->nSelectors; i++) {
- /* We expect each simple selector to be a JavaScript object */
- XP_ASSERT(JSVAL_IS_OBJECT(argv[i]));
-
- rule->selectors[i] = JS_GetPrivate(mc, (JSObject *)argv[i]);
- if (!rule->selectors[i]) {
- XP_ASSERT(FALSE);
- XP_FREE(rule);
- return 0;
- }
-
- /* The specificity of the rule is just the sum of the specificity of each selector */
- rule->tag.specificity += rule->selectors[i]->specificity;
- }
-
- return rule;
- }
-
- /* Destroys a list of rules */
- void
- jss_DestroyRules(StyleRule *rules)
- {
- StyleRule *next;
-
- while (rules) {
- next = rules->next;
-
- /* Destroy any properties associated with the tag structure */
- XP_ASSERT(rules->tag.name == 0);
- XP_ASSERT(rules->tag.rules == 0);
- jss_DestroyProperties(rules->tag.properties);
-
- /* Destroy the array of selectors */
- if (rules->selectors)
- XP_FREE(rules->selectors);
-
- XP_FREE(rules);
- rules = next;
- }
- }
-
- /*
- * Helper function to determine if a simple selector applies. index
- * represents where in the tag stack the search should begin
- *
- * Returns JS_TRUE if selector applies. In this case index will be set
- * to the tag stack entry where the match occured. Returns JS_FALSE if
- * the selector doesn't apply
- */
- static JSBool
- jss_SelectorApplies(JSSContext *jc,
- StyleTag *jsstag,
- StyleAndTagStack *styleStack,
- int32 *index)
- {
- TagStruct *tag;
-
- for (tag = STYLESTACK_GetTagByIndex(styleStack, *index);
- tag;
- tag = STYLESTACK_GetTagByIndex(styleStack, ++(*index))) {
-
- /* We determine if the selector applies by comparing StyleTag pointers */
- if (tag->id && jc->ids && jc->ids->table) {
- if ((StyleTag *)PR_HashTableLookup(jc->ids->table, tag->id) == jsstag)
- return JS_TRUE;
- }
-
- if (tag->class_name && jc->classes && jc->classes->table) {
- StyleObject *classes = (StyleObject *)PR_HashTableLookup(jc->classes->table, tag->class_name);
-
- if (classes && classes->table) {
- /* Check against all elements of the class, e.g. classes.punk.all */
- if ((StyleTag *)PR_HashTableLookup(classes->table, "all") == jsstag)
- return JS_TRUE;
-
- /* Now check for the specified tag, e.g. classes.punk.H1 */
- XP_ASSERT(tag->name);
- if (tag->name && ((StyleTag *)PR_HashTableLookup(classes->table, tag->name) == jsstag))
- return JS_TRUE;
- }
- }
-
- XP_ASSERT(tag->name);
- if (tag->name && jc->tags && jc->tags->table) {
- if ((StyleTag *)PR_HashTableLookup(jc->tags->table, tag->name) == jsstag)
- return JS_TRUE;
- }
- }
-
- /* The selector didn't match against any element of the tag stack */
- return JS_FALSE;
- }
-
- /*
- * Helper function to determine if a contextual selector applies. Returns
- * JS_TRUE if the selector applies and JS_FALSE otherwise
- */
- static JSBool
- jss_RuleApplies(JSSContext *jc, StyleRule *rule, StyleAndTagStack *styleStack)
- {
- int i;
- int32 index = 0;
-
- /*
- * Starting with the right-most selector, check each selector to see
- * if it applies
- */
- for (i = (int)rule->nSelectors - 1; i >= 0; i--) {
- if (!jss_SelectorApplies(jc, rule->selectors[i], styleStack, &index))
- return JS_FALSE;
-
- index++; /* continue with the next HTML element */
- }
-
- return JS_TRUE;
- }
-
- /*
- * This routine takes as an argument a list of rules, a stack of open HTML
- * elements, and a callback function. The callback function is called once for
- * each rule that applies
- */
- JSBool
- jss_EnumApplicableRules(JSSContext *jc,
- StyleRule *rules,
- StyleAndTagStack *styleStack,
- RULECALLBACK callback,
- void *data)
- {
- while (rules) {
- if (jss_RuleApplies(jc, rules, styleStack))
- callback(&rules->tag, data);
-
- rules = rules->next;
- }
-
- return JS_TRUE;
- }
-