home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libstyle / jssrules.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  6.3 KB  |  234 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "xp.h"
  20. #include "libstyle.h"
  21. #include "jsapi.h"
  22. #include "xp_mcom.h"
  23. #include "jsspriv.h"
  24. #include "jssrules.h"
  25.  
  26. /*
  27.  * Helper routine to determine whether the array of simple selectors matches
  28.  * the selectors for the specified rule
  29.  */
  30. static JSBool
  31. jss_IsSelectorEqual(JSContext *mc,
  32.                     StyleRule *rule,
  33.                     unsigned   nSelectors,
  34.                     jsval      *selectors)
  35. {
  36.     unsigned    i;
  37.  
  38.     if (rule->nSelectors == nSelectors) {
  39.         for (i = 0; i < rule->nSelectors; i++) {
  40.             /* We expect each simple selector to be a JavaScript object */
  41.             XP_ASSERT(JSVAL_IS_OBJECT(selectors[i]));
  42.     
  43.             /* The simple selectors match if they point to the same StyleTag structure */
  44.             if (rule->selectors[i] != JS_GetPrivate(mc, (JSObject *)selectors[i]))
  45.                 return JS_FALSE;
  46.         }
  47.  
  48.         return JS_TRUE;
  49.     }
  50.     
  51.     return JS_FALSE;
  52. }
  53.  
  54. /*
  55.  * Given a list of rules and a contextual selector (array of simple
  56.  * selectors), looks to see if the contextual selector matches an
  57.  * existing rule
  58.  *
  59.  * Returns the rule if successful, and 0 otherwise
  60.  */
  61. StyleRule *
  62. jss_LookupRule(JSContext *mc,
  63.                StyleRule *rules,
  64.                unsigned   nSelectors,
  65.                jsval     *selectors)
  66. {
  67.     while (rules) {
  68.         if (jss_IsSelectorEqual(mc, rules, nSelectors, selectors))
  69.             return rules;
  70.  
  71.         rules = rules->next;
  72.     }
  73.  
  74.     return 0;
  75. }
  76.  
  77. /* This routine creates and returns a new rule */
  78. StyleRule *
  79. jss_NewRule(JSContext *mc, unsigned argc, jsval *argv)
  80. {
  81.     StyleRule *rule;
  82.     unsigned   i;
  83.  
  84.     /* Create a new rule */
  85.     rule = (StyleRule *)XP_CALLOC(1, sizeof(StyleRule));
  86.     if (!rule) {
  87.         JS_ReportOutOfMemory(mc);
  88.         return 0;
  89.     }
  90.  
  91.     /* Initialize the list of selectors. While we're at it compute the specificity */
  92.     rule->nSelectors = argc;
  93.     rule->selectors = XP_CALLOC((size_t)rule->nSelectors, sizeof(StyleTag *));
  94.     rule->tag.specificity = 0;
  95.  
  96.     for (i = 0; i < rule->nSelectors; i++) {
  97.         /* We expect each simple selector to be a JavaScript object */
  98.         XP_ASSERT(JSVAL_IS_OBJECT(argv[i]));
  99.  
  100.         rule->selectors[i] = JS_GetPrivate(mc, (JSObject *)argv[i]);
  101.         if (!rule->selectors[i]) {
  102.             XP_ASSERT(FALSE);
  103.             XP_FREE(rule);
  104.             return 0;
  105.         }
  106.  
  107.         /* The specificity of the rule is just the sum of the specificity of each selector */
  108.         rule->tag.specificity += rule->selectors[i]->specificity;
  109.     }
  110.  
  111.     return rule;
  112. }
  113.  
  114. /* Destroys a list of rules */
  115. void
  116. jss_DestroyRules(StyleRule *rules)
  117. {
  118.     StyleRule *next;
  119.  
  120.     while (rules) {
  121.         next = rules->next;
  122.  
  123.         /* Destroy any properties associated with the tag structure */
  124.         XP_ASSERT(rules->tag.name == 0);
  125.         XP_ASSERT(rules->tag.rules == 0);
  126.         jss_DestroyProperties(rules->tag.properties);
  127.  
  128.         /* Destroy the array of selectors */
  129.         if (rules->selectors)
  130.             XP_FREE(rules->selectors);
  131.  
  132.         XP_FREE(rules);
  133.         rules = next;
  134.     }
  135. }
  136.  
  137. /*
  138.  * Helper function to determine if a simple selector applies. index
  139.  * represents where in the tag stack the search should begin
  140.  *
  141.  * Returns JS_TRUE if selector applies. In this case index will be set
  142.  * to the tag stack entry where the match occured. Returns JS_FALSE if
  143.  * the selector doesn't apply
  144.  */
  145. static  JSBool
  146. jss_SelectorApplies(JSSContext          *jc,
  147.                     StyleTag         *jsstag,
  148.                     StyleAndTagStack *styleStack,
  149.                     int32             *index)
  150. {
  151.     TagStruct    *tag;
  152.  
  153.     for (tag = STYLESTACK_GetTagByIndex(styleStack, *index);
  154.          tag;
  155.          tag = STYLESTACK_GetTagByIndex(styleStack, ++(*index))) {
  156.  
  157.         /* We determine if the selector applies by comparing StyleTag pointers */
  158.         if (tag->id && jc->ids && jc->ids->table) {
  159.             if ((StyleTag *)PR_HashTableLookup(jc->ids->table, tag->id) == jsstag)
  160.                 return JS_TRUE;
  161.         }
  162.  
  163.         if (tag->class_name && jc->classes && jc->classes->table) {
  164.             StyleObject *classes = (StyleObject *)PR_HashTableLookup(jc->classes->table, tag->class_name);
  165.  
  166.             if (classes && classes->table) {
  167.                 /* Check against all elements of the class, e.g. classes.punk.all */
  168.                 if ((StyleTag *)PR_HashTableLookup(classes->table, "all") == jsstag)
  169.                     return JS_TRUE;
  170.  
  171.                 /* Now check for the specified tag, e.g. classes.punk.H1 */
  172.                 XP_ASSERT(tag->name);
  173.                 if (tag->name && ((StyleTag *)PR_HashTableLookup(classes->table, tag->name) == jsstag))
  174.                     return JS_TRUE;
  175.             }
  176.         }
  177.  
  178.         XP_ASSERT(tag->name);
  179.         if (tag->name && jc->tags && jc->tags->table) {
  180.             if ((StyleTag *)PR_HashTableLookup(jc->tags->table, tag->name) == jsstag)
  181.                 return JS_TRUE;
  182.         }
  183.     }
  184.  
  185.     /* The selector didn't match against any element of the tag stack */
  186.     return JS_FALSE;
  187. }
  188.  
  189. /*
  190.  * Helper function to determine if a contextual selector applies. Returns
  191.  * JS_TRUE if the selector applies and JS_FALSE otherwise
  192.  */
  193. static JSBool
  194. jss_RuleApplies(JSSContext *jc, StyleRule *rule, StyleAndTagStack *styleStack)
  195. {
  196.     int        i;
  197.     int32    index = 0;
  198.  
  199.     /*
  200.      * Starting with the right-most selector, check each selector to see
  201.      * if it applies
  202.      */
  203.     for (i = (int)rule->nSelectors - 1; i >= 0; i--) {
  204.         if (!jss_SelectorApplies(jc, rule->selectors[i], styleStack, &index))
  205.             return JS_FALSE;
  206.  
  207.         index++;  /* continue with the next HTML element */
  208.     }
  209.  
  210.     return JS_TRUE;
  211. }
  212.  
  213. /*
  214.  * This routine takes as an argument a list of rules, a stack of open HTML
  215.  * elements, and a callback function. The callback function is called once for
  216.  * each rule that applies
  217.  */
  218. JSBool
  219. jss_EnumApplicableRules(JSSContext         *jc,
  220.                         StyleRule          *rules,
  221.                         StyleAndTagStack *styleStack,
  222.                         RULECALLBACK      callback,
  223.                         void             *data)
  224. {
  225.     while (rules) {
  226.         if (jss_RuleApplies(jc, rules, styleStack))
  227.             callback(&rules->tag, data);
  228.  
  229.         rules = rules->next;
  230.     }
  231.  
  232.     return JS_TRUE;
  233. }
  234.