style.c
上传用户:zlh9724
上传日期:2007-01-04
资源大小:1991k
文件大小:62k
源码类别:

浏览器

开发平台:

Unix_Linux

  1. /*
  2. howcome  27/9/95:
  3. This is the style sheet module (i.e. the "styler") of Arena. It will
  4. parse CSS style sheets into structures that can be queried by the
  5. formatter of e.g an HTML browser.
  6. Typically, the application will create a new style sheet initialized
  7. with the application fallback values. For this, use StyleGetInit
  8. Then, if the user has a personal style sheet -- or if incoming
  9. documents have style sheets -- they can be parsed and added to an
  10. exsiting style sheet by StyleChew
  11. As the HTML/SGML parser encounters tags, FormatElementStart should be
  12. called to have style properties evaluated for the specific element in
  13. this specific context. The set of properties are pushed onto a stack
  14. which corresponds to the document structure.
  15. The formatter can query the style properties of the current element
  16. StyleGet.
  17. FormatElementEnd pops a set of style properties from the stack and
  18. shoul be called when the parser reports the end of an element.
  19. History:
  20. howcome 15/2/94: written from scratch
  21. Dave Raggett:
  22. How about the following notation for style:
  23.         * -> font.name = times
  24.         H1 -> font.name = garamond
  25.         H[2-6] -> font.name = helvetica
  26.         
  27.         P.CLASS = abstract ->
  28.             {
  29.                 font.name = helvetica
  30.                 font.size = 10 pt
  31.                 indent.left = 4 em
  32.                 indent.right = 4 em
  33.             }
  34. The left hand side of the "->" operator matches tag names and uses
  35. the dot notation for attribute values. You can use regular expressions
  36. such as [digit-digit] [letter-letter] * and ?. The browser is responsible
  37. for sorting the rules in order of most to least specificity so it doesn't
  38. matter that the first rule matches anything.
  39. The right hand side simply sets property values. The HTML formatter knows
  40. what properties are relevant to which elements. Some properties are
  41. specific to one kind of element, while others are generic. Properties
  42. set by a more specific rule (matching the current element) override values
  43. set by least specific rules or values inherited from nested or peer elements.
  44. howcome 1/4/95: 
  45.   Dave's proposal for syntax has been implemented with some shortcuts.
  46.   The "->" construct was replaced by ":" whish should have the same associations. 
  47.   The "P.CLASS = abstract" construct is more general than required for
  48.   the class attribute. As a shortcut, "P [abstract]" has been implemented.
  49. howcome 5/4/95: 
  50.   pattern searches implemented /H1 P/: color.text = #FFF
  51.   Also, commands can be put on the same line with a ";" separating.
  52.   # this is a comment
  53.   / so is this
  54. howcome 5/95: changes to the syntax:
  55.   class is now always denoted p.foo
  56.   elemets and hints can be grouped:
  57.   H1, H2: font.family = helvetica; font.color = #F00
  58. howcome 8/95:
  59.   style sheet module updated to support the august 10 version of
  60.     http://www.w3.org/hypertext/WWW/Style/css/draft.html
  61. */
  62. #include <stdio.h>
  63. #include <stdarg.h>
  64. #include <signal.h>
  65. #include <sys/types.h>
  66. #include <unistd.h>
  67. #include <sys/stat.h>
  68. #include <fcntl.h>
  69. #include <string.h>
  70. #include "www.h"
  71. extern int debug;
  72. extern Doc *CurrentDoc;
  73. extern Context *context;
  74. extern int PixOffset;
  75. extern int paintlen;
  76. extern int paintStartLine;
  77. extern Byte *paint;
  78. extern unsigned int ui_n;
  79. extern unsigned int win_width, win_height;
  80. extern int fontsize;
  81. extern int prepass;
  82. extern int sbar_width;
  83. extern unsigned int win_width, win_height;
  84. extern int ToolBarHeight;
  85. extern int statusHeight;
  86. extern int damn_table;
  87. double lens_factor = 1.0;
  88. extern int math_normal_sym_font, math_small_sym_font,
  89.     math_normal_text_font, math_small_text_font, math_italic_text_font,
  90.     math_bold_text_font;
  91. HTList *style_stack = NULL;
  92. StyleFlat *current_flat;
  93. StyleSheet *current_sheet;
  94. /* 
  95.   str2list is a convenience function to make a list out of two strings
  96. */
  97. HTList *str2list(char *s, char *t)
  98. {
  99.     HTList *l = HTList_new();
  100.     if (t)
  101. HTList_addObject(l, strdup(t));
  102.     if (s)
  103. HTList_addObject(l, strdup(s));
  104.     return l;       
  105. }
  106. /*
  107.   pt2px converts points to pixels
  108.   display_pt2px =  (25.4 / 72.0) * 
  109.     (((double) DisplayWidth(display,screen)) / ((double) DisplayWidthMM(display, screen)));
  110. */
  111. extern double display_pt2px;
  112. int pt2px(double pt)
  113. {
  114.     return (int) ((display_pt2px * pt) + 0.5);
  115. }
  116. /* 
  117.   The Flag functions are used to remember various settings. E.g., if
  118.   there is a big initial, we want that property to inherit to child
  119.   elements, but we do not want it to be used more than once. Depending
  120.   on your HTML/SGML parser, this problem may have more elegant solution
  121. */
  122. BOOL StyleGetFlag(int flag)
  123. {
  124.     switch (flag)
  125.     {
  126.     case S_INITIAL_FLAG:
  127. return current_sheet->initial_flag;
  128. break;
  129.     case S_LEADING_FLAG:
  130. return current_sheet->leading_flag;
  131. break;
  132.     case S_INDENT_FLAG:
  133. return current_sheet->indent_flag;
  134. break;
  135.     case S_MARGIN_TOP_FLAG:
  136. return current_sheet->margin_top_flag;
  137. break;
  138.     }
  139.     return FALSE;
  140. }
  141. void StyleSetFlag(int flag, BOOL value)
  142. {
  143.     switch (flag)
  144.     {
  145.     case S_INITIAL_FLAG:
  146. current_sheet->initial_flag = value;
  147. break;
  148.     case S_LEADING_FLAG:
  149. current_sheet->leading_flag = value;
  150. break;
  151.     case S_INDENT_FLAG:
  152. current_sheet->indent_flag = value;
  153. break;
  154.     case S_MARGIN_TOP_FLAG:
  155. current_sheet->margin_top_flag = value;
  156. break;
  157.     }
  158. }
  159. /* methods */
  160. StyleRule *NewStyleRule()
  161. {
  162.     return (StyleRule *)calloc(1,sizeof(StyleRule));
  163. }
  164. StyleSelector *NewStyleSelector()
  165. {
  166.     return (StyleSelector *)calloc(1,sizeof(StyleSelector));
  167. }
  168. StyleSheet *NewStyleSheet()
  169. {
  170.     return (StyleSheet *)calloc(1,sizeof(StyleSheet));
  171. }
  172. /* NewStyleFlat allocates memory AND sets initial values. CHANGE! */
  173. StyleFlat *NewStyleFlat()
  174. {
  175.     StyleFlat *sf;
  176.     sf = (StyleFlat *)calloc(1, sizeof(StyleFlat));
  177.     sf->value[S_MARGIN_LEFT] = (void *)20; /* 30 */
  178.     sf->status[S_MARGIN_LEFT] = S_INITIALIZED;
  179.     sf->value[S_MARGIN_RIGHT] = (void *)20; /* 20 */
  180.     sf->status[S_MARGIN_RIGHT] = S_INITIALIZED;
  181.     sf->value[S_MARGIN_TOP] = (void *)5; /* 5 */
  182.     sf->status[S_MARGIN_TOP] = S_INITIALIZED;
  183.     sf->value[S_MARGIN_BOTTOM] = (void *)5; /* 5 */
  184.     sf->status[S_MARGIN_BOTTOM] = S_INITIALIZED;
  185.     return sf;
  186. }
  187. void FreeStyleSelector(StyleSelector *selector)
  188. {
  189.     StyleSelector *prev_selector;
  190.     prev_selector = selector;
  191.     while((selector = selector->ancestor)) {
  192. Free(prev_selector->unit.class);
  193. Free(prev_selector);
  194. prev_selector = selector;
  195.     }
  196.     if(!prev_selector)
  197.     {
  198. Free(prev_selector->unit.class);
  199. Free(prev_selector);
  200.     }
  201. }
  202. void FreeStyleRule(StyleRule *r)
  203. {
  204.     if (!r)
  205. return;
  206.     FreeStyleSelector(r->selector);
  207.     Free(r->warning);
  208. }
  209.     
  210. void FreeStyleSheet(StyleSheet *s)
  211. {
  212.     HTList *l;
  213.     StyleRule *r;
  214.     int i;
  215.     if (!s)
  216. return;
  217.     for(i = 0; i<TAG_LAST; i++) {
  218. if ((l = s->element[i]))
  219.     while ((r = (StyleRule *)HTList_nextObject(l)))
  220. FreeStyleRule(r);
  221.     }
  222.     Free(s);
  223. }
  224. /*
  225. void StyleFree(StyleSheet *sheet)
  226. {
  227.     int i;
  228.     for(i=0; i<TAG_LAST; i++) {
  229. HTList_destroy(sheet->element[i]);
  230.     }
  231.     Free(sheet);
  232. }
  233. */
  234. StyleSelector *CopySelector(StyleSelector *s)
  235. {
  236.     StyleSelector *sc;
  237.     if (!s)
  238. return NULL;
  239.     sc = NewStyleSelector();
  240.     memcpy(sc, s, sizeof(StyleSelector));
  241.     sc->ancestor = CopySelector (s->ancestor);
  242.     return(sc);
  243. }
  244. StyleSheet *StyleCopy(StyleSheet *s)
  245. {
  246.     StyleSheet *sc = NewStyleSheet();
  247.     int i;
  248.     HTList *l, *lc;
  249.     StyleRule *r, *rc;
  250.     for (i=0; i<TAG_LAST; i++) {
  251. l = s->element[i];
  252. lc = sc->element[i];
  253. while ( (r = (StyleRule *) HTList_nextObject(l) )) {
  254.     rc = NewStyleRule();
  255.     rc->property = r->property;
  256.     rc->value = r->value;
  257.     rc->weight = r->weight;
  258.     if (r->warning)
  259. rc->warning = strdup(r->warning);
  260.     rc->selector = CopySelector(r->selector);
  261.     if (!lc)
  262. lc = sc->element[i] = HTList_new();
  263.     HTList_addObject(lc, (void *) rc);
  264. }
  265.     }
  266.     return sc;
  267. }
  268. /* find, and grade selector matches */
  269. /* 
  270.    SelectorUnitMatch matches two "selector utits", i.e. an element
  271.    with accompanying class (and, in level 2, attributes in general.
  272.    r = rule, s = stack
  273.    The gradins schems is simple: 
  274.    0 = failure, no match
  275.    1 = element matches, no classes specified in rule
  276.    2 = element matches, classes specified and matches
  277. */
  278. int SelectorUnitMatch(StyleSelectorUnit *r, StyleSelectorUnit *s)
  279. {
  280.     if (r->element == s->element) {
  281. if (r->class) {
  282.     if ((s->class) && (strcasecmp(r->class, s->class) == 0)) {
  283. return 2;
  284.     }
  285.     return 0;
  286. }
  287. return 1;
  288.     }
  289.     return 0;
  290. }
  291. int SelectorMatch(StyleSelector *s, StyleSelectorUnit *unit_p, HTList *style_stack)
  292. {
  293.     HTList *l = style_stack;
  294.     StyleStackElement *stack_el;
  295.     int score = 0;
  296.     if (! (score = SelectorUnitMatch(&s->unit, unit_p)))
  297. return score;
  298.     s = s->ancestor;
  299.     if (!s)
  300. return score;
  301.     while (s && (stack_el = (StyleStackElement *)HTList_nextObject(l))) {
  302. if ( (score += SelectorUnitMatch(&s->unit, &stack_el->unit)) )
  303.     s = s->ancestor;
  304. if (!s)
  305.     return 0;
  306.     }
  307.     return score;
  308. }
  309. /* 
  310.    StyleEval flattens the whole list of properties. One could argue
  311.    that properties should only be evaluated when needed. That would be
  312.    a little more complicated.
  313. */
  314. StyleFlat *StyleEval(StyleSheet *sheet, StyleSelectorUnit *unit_p, HTList *style_stack)
  315. {
  316.     StyleStackElement *stack_el;
  317.     StyleFlat *last_flat = NULL, *flat = NewStyleFlat();
  318.     StyleRule *rule;
  319.     StyleProperty i;
  320.     HTList *l;
  321.     BOOL recompute_font = FALSE, recompute_alt_font = FALSE;
  322.     long value;
  323.     int selector_score;
  324.     if (REGISTER_TRACE)
  325. fprintf(stderr,"StyleEval: %d, depth of list: %dn", unit_p->element, HTList_count(style_stack));
  326.     /* init flat */
  327.     stack_el = (StyleStackElement *)HTList_lastObject(style_stack);
  328.     if (stack_el) {
  329. last_flat = stack_el->flat;
  330. /* copy the inherited properties from ancestor */
  331. for (i=S_UNKNOWN; i < S_NPROPERTY; i++) {
  332.     switch (i) {
  333. /* these properies are not inherited */
  334.       case S_MARGIN_TOP:
  335.       case S_MARGIN_RIGHT:
  336.       case S_MARGIN_BOTTOM:
  337.       case S_MARGIN_LEFT:
  338.       case S_INDENT:
  339.       case S_PADDING:
  340.       case S_BACKGROUND:
  341.       case S_ALT_BACKGROUND:
  342. break;
  343.       default:
  344. if ((last_flat->status[i] == S_INHERITED) || (last_flat->status[i] == S_INFERRED)) {
  345.     flat->value[i] = last_flat->value[i];
  346.     flat->weight[i] = last_flat->weight[i];
  347.     flat->status[i] = S_INHERITED;
  348. }
  349.     }
  350. }
  351.     }
  352.     /* go through list of rules */
  353.     l = sheet->element[unit_p->element];
  354.     while ( (rule = (StyleRule *) HTList_nextObject(l) )) {
  355. if ((selector_score = SelectorMatch(rule->selector, unit_p, style_stack)) && (rule->weight + selector_score >= flat->weight[rule->property])) {
  356.     flat->value[rule->property] = rule->value;
  357.     flat->weight[rule->property] = rule->weight + selector_score;
  358.     flat->status[rule->property] = S_INFERRED;
  359.     switch (rule->property) {
  360.       case S_FONT_SHORTHAND:
  361.       case S_FONT_FAMILY:
  362.       case S_FONT_SIZE:
  363. /*       case S_FONT_SIZE_INDEX:*/
  364.       case S_FONT_WEIGHT:
  365.       case S_FONT_STYLE:
  366. /*        case S_FONT_LEADING: */
  367. recompute_font = TRUE;
  368. break;
  369.       case S_ALT_FONT_SHORTHAND:
  370.       case S_ALT_FONT_FAMILY:
  371.       case S_ALT_FONT_SIZE:
  372. /*       case S_ALT_FONT_SIZE_INDEX:*/
  373.       case S_ALT_FONT_WEIGHT:
  374.       case S_ALT_FONT_STYLE:
  375. /*        case S_ALT_FONT_LEADING: */
  376. recompute_alt_font = TRUE;
  377. break;
  378.       case S_TEXT_EFFECT:
  379. if ((int)flat->value[rule->property] == TEXT_EFFECT_INITIAL_CAP)
  380.     StyleSetFlag(S_INITIAL_FLAG, TRUE);
  381.       default:
  382. break;
  383.     }
  384. }
  385.     }
  386.     /* what are the compound properties? i.e. properties that depend
  387.        on other properties? is font the only one? */ 
  388.     if (recompute_font) {
  389. flat->value[S_FONT] = (void *)GetFont((HTList *)flat->value[S_FONT_FAMILY], (int)flat->value[S_FONT_SIZE], 
  390.       (int)flat->value[S_FONT_WEIGHT], (int)flat->value[S_FONT_STYLE], False);
  391. flat->status[S_FONT] = S_INFERRED;
  392.     }
  393.     if (recompute_alt_font) {
  394. flat->value[S_ALT_FONT] = (void *)
  395.     GetFont(
  396.     (HTList *)((flat->status[S_ALT_FONT_FAMILY] == S_INFERRED) ? 
  397.        (int)flat->value[S_ALT_FONT_FAMILY] : (int)flat->value[S_FONT_FAMILY]),
  398.     ((flat->status[S_ALT_FONT_SIZE] == S_INFERRED) ? 
  399.      (int)flat->value[S_ALT_FONT_SIZE] : (int)flat->value[S_FONT_SIZE]),
  400.     ((flat->status[S_ALT_FONT_WEIGHT] == S_INFERRED) ? 
  401.      (int)flat->value[S_ALT_FONT_WEIGHT] : (int)flat->value[S_FONT_WEIGHT]),
  402.     ((flat->status[S_ALT_FONT_STYLE] == S_INFERRED) ? 
  403.      (int)flat->value[S_ALT_FONT_STYLE] : (int)flat->value[S_FONT_STYLE]),
  404.     False);
  405. flat->status[S_ALT_FONT] = S_INFERRED;
  406.     }
  407.     /* we cannot compute the colormap index until we know if the color is blinking or not */
  408.     if (flat->status[S_COLOR] == S_INFERRED) {
  409. if (flat->status[S_ALT_COLOR] != S_INFERRED) {
  410.     flat->status[S_ALT_COLOR] = S_INFERRED;
  411.     flat->value[S_ALT_COLOR] = flat->value[S_COLOR];
  412.     flat->weight[S_ALT_COLOR] = flat->weight[S_COLOR];
  413. }
  414. value = (int)flat->value[S_COLOR];
  415. flat->value[S_COLOR] = (void *)rgb2ix( (int)(value >> 24), (int)((value >> 16) & 0xFF), 
  416.     (int)((value >> 8) & 0xFF), (int)(value & 0xFF), False);
  417. if (REGISTER_TRACE && VERBOSE_TRACE)
  418.     fprintf(stderr,"--> TEXT_COLOR = %ldn",(int)flat->value[S_COLOR]);
  419.     }
  420.     if (flat->status[S_BACKGROUND] == S_INFERRED) {
  421. if (flat->status[S_ALT_BACKGROUND] != S_INFERRED) {
  422.     flat->status[S_ALT_BACKGROUND] = S_INFERRED;
  423.     flat->value[S_ALT_BACKGROUND] = flat->value[S_BACKGROUND];
  424.     flat->weight[S_ALT_BACKGROUND] = flat->weight[S_BACKGROUND];
  425. }
  426. /*
  427. value = flat->value[S_BACKGROUND];
  428. flat->value[S_BACKGROUND] = rgb2ix( (int)(value >> 24), (int)((value >> 16) & 0xFF), 
  429.  (int)((value >> 8) & 0xFF), (int)(value & 0xFF), False);
  430. if (REGISTER_TRACE && VERBOSE_TRACE)
  431.     fprintf(stderr,"-> S_BACKGROUND = %ldn",flat->value[S_BACKGROUND]);
  432. */
  433.     }
  434.     if (flat->status[S_ALT_COLOR] == S_INFERRED) {
  435. value = (int)flat->value[S_ALT_COLOR];
  436. flat->value[S_ALT_COLOR] = (void *)rgb2ix( (int)(value >> 24), (int)((value >> 16) & 0xFF), 
  437. (int)((value >> 8) & 0xFF), (int)(value & 0xFF), False);
  438. if (REGISTER_TRACE && VERBOSE_TRACE)
  439.     fprintf(stderr,"--> TEXT_COLOR = %ldn",(int)flat->value[S_ALT_COLOR]);
  440.     }
  441.     if (flat->status[S_ALT_BACKGROUND] == S_INFERRED) {
  442. value = (int)flat->value[S_ALT_BACKGROUND];
  443. /*
  444. flat->value[S_ALT_BACKGROUND] = rgb2ix( (int)(value >> 24), (int)((value >> 16) & 0xFF), 
  445.      (int)((value >> 8) & 0xFF), (int)(value & 0xFF), False);
  446. if (REGISTER_TRACE && VERBOSE_TRACE)
  447.     fprintf(stderr,"-> TEXT_BACKGROUND = %ldn", flat->value[S_ALT_BACKGROUND]);
  448. */
  449.     }
  450.     /* math is a bit awkward */
  451.     if (unit_p->element == TAG_MATH) {
  452. long sym_size = (long)flat->value[S_FONT_SIZE];
  453. HTList *l = str2list("symbol", "symbol");
  454.     
  455. math_normal_sym_font = GetFont(l, sym_size, FONT_WEIGHT_MEDIUM, FONT_STYLE_NORMAL, False);
  456. math_small_sym_font = GetFont(l, sym_size/2,FONT_WEIGHT_MEDIUM, FONT_STYLE_NORMAL, True);
  457.     
  458. math_normal_text_font = 0;
  459. math_small_text_font = 0;
  460.     
  461. math_bold_text_font = GetFont(l, sym_size/2, FONT_WEIGHT_BOLD, FONT_STYLE_NORMAL, True);
  462. math_italic_text_font = GetFont(l, sym_size/2, FONT_WEIGHT_NORMAL, FONT_STYLE_ITALIC, True);
  463.     }
  464.     HTList_destroy(l); /* DJB 17-jan-96 */
  465.     return flat;
  466. }
  467. /*
  468.   StyleSane is a debugging functions which tries to print out the
  469.   content of a style sheet
  470. */
  471. void StyleSane(StyleSheet *s)
  472. {
  473.     int i;
  474.     StyleRule *r;
  475.     fprintf(stderr,"nstylesane:n");
  476.     if (!s)
  477. return;
  478.     for (i=0; i < TAG_LAST; i++) {
  479. HTList *l = s->element[i];
  480. StyleSelector *sel;
  481. fprintf(stderr,"  element %dn", i);
  482. while ( (r = (StyleRule *)HTList_nextObject(l)) ) {
  483.     fprintf(stderr,"    selector (");
  484.     sel = r->selector;
  485.     do {
  486. if (sel->unit.class)
  487.     fprintf(stderr,"%d.%s ",sel->unit.element, sel->unit.class);
  488. else
  489.     fprintf(stderr,"%d ",sel->unit.element);
  490.     } while ((sel = sel->ancestor));
  491.     fprintf(stderr,") ");
  492.     fprintf(stderr,"    property %d tweight %d tvalue ", r->property, r->weight);
  493.     switch (r->property) {
  494.       case S_FONT_FAMILY:
  495.       case S_ALT_FONT_FAMILY:
  496. {
  497.     HTList *ll = (HTList *)r->value;
  498.     char *family;
  499.     while ((family = (char *)HTList_nextObject(ll))) {
  500. fprintf(stderr,"%s+",family);
  501.     }
  502.     fprintf(stderr," ");
  503. }
  504. break;
  505.       case S_COLOR:
  506.       case S_BACKGROUND:
  507. fprintf(stderr,"#%x,%x,%x ",(int)(((int)r->value >> 16) & 0xFF),(int)(((int)r->value >> 8) & 0xFF),(int)(((int)r->value >> 0) & 0xFF));
  508. break;
  509.       default:
  510. fprintf(stderr,"%ld ", (long)r->value);
  511.     }
  512.     fprintf(stderr,"n");
  513. }
  514.     }
  515.     fprintf(stderr,"stylesane endn");
  516. }
  517. /* StyleAddRule adds a rule to the pool of style rules */
  518. void StyleAddRule(StyleSheet *sheet, StyleSelector *selector, StyleProperty property, long value, int weight)
  519. {
  520.     StyleRule *r = NewStyleRule();
  521.     r->selector = selector;
  522.     r->property = property;
  523.     r->value = value;
  524.     r->weight = weight;
  525.     if (!sheet->element[selector->unit.element])
  526. sheet->element[selector->unit.element] = HTList_new();
  527.     HTList_addObject(sheet->element[selector->unit.element], (void *) r);
  528. }
  529. void StyleAddSimpleRule(StyleSheet *sheet, int element, StyleProperty property, long value, int weight)
  530. {
  531.     StyleSelector *s = NewStyleSelector();
  532.     s->unit.element = element;
  533.     StyleAddRule(sheet, s, property, value, weight);
  534. }
  535. /* Parse functions start here */
  536. StyleProperty Property2enum(char *s)
  537. {
  538.     int l = strlen(s);
  539. /*     s = TOLOWER(s);*/
  540.     if(!strncmp(s,"padding",7))
  541. return S_PADDING;
  542.     if(!strncmp(s,"bg", 2))
  543.     {
  544. if((l == 8 )&&(!strcmp(s+3,"style")))
  545.     return S_BACKGROUND;
  546. if((l == 11 ) &&(!strcmp(s+3,"position")))
  547.     return S_BACKGROUND;
  548. if((l == 18 ) && (!strcmp(s+3,"blend-direction")))
  549.     return S_BACKGROUND_BLEND;
  550.   
  551.     };
  552.     if(!strncmp(s,"background", 10))
  553. return S_BACKGROUND;
  554.     if (strncmp(s,"font", 4) == 0) {
  555. if (l == 4)
  556.     return S_FONT_SHORTHAND;
  557. if ((l == 9) && (strcmp(&s[5], "size") == 0))
  558.     return S_FONT_SIZE;
  559. /*
  560. if ((l == 15) && (strcmp(&s[5], "size-index") == 0))
  561.     return S_FONT_SIZE_INDEX;
  562. */
  563. if ((l == 11) && (strcmp(&s[5], "family") == 0))
  564.     return S_FONT_FAMILY;
  565. if ((l == 11) && (strcmp(&s[5], "weight") == 0))
  566.     return S_FONT_WEIGHT;
  567. if ((l == 10) && (strcmp(&s[5], "style") == 0))
  568.     return S_FONT_STYLE;
  569. if ((l == 12) && (strcmp(&s[5], "leading") == 0))
  570.     return S_FONT_LEADING;
  571.     }
  572.     else if (strncmp(s,"letter", 6) == 0) {
  573. if ((l == 14) && (strcmp(&s[7], "spacing") == 0))
  574.     return S_TEXT_SPACING;
  575.     }
  576.      else if (strncmp(s,"word", 4) == 0) {
  577. if ((l == 12) && (strcmp(&s[5], "spacing") == 0))
  578.     return S_WORD_SPACING;
  579.     }
  580.     else if (strncmp(s,"text", 4) == 0) {
  581. if ((l == 10) && (strcmp(&s[5], "color") == 0))        /* historical */
  582.     return S_COLOR;
  583. if ((l == 15) && (strcmp(&s[5], "background") == 0))   /* historical */
  584.     return S_BACKGROUND;
  585. if ((l == 12) && (strcmp(&s[5], "spacing") == 0))
  586.     return S_TEXT_SPACING;
  587. if ((l == 9) && (strcmp(&s[5], "decoration") == 0))
  588.     return S_TEXT_DECORATION;
  589. if ((l == 9) && (strcmp(&s[5], "line") == 0))          /* historical */
  590.     return S_TEXT_DECORATION;
  591. if ((l == 13) && (strcmp(&s[5], "position") == 0))
  592.     return S_TEXT_POSITION;
  593. if ((l == 14) && (strcmp(&s[5], "transform") == 0))
  594.     return S_TEXT_TRANSFORM;
  595. if ((l == 11) && (strcmp(&s[5], "effect") == 0))
  596.     return S_TEXT_EFFECT;
  597. if ((l == 11) && (!strcmp(s+5, "indent")))
  598.     return S_INDENT;
  599. if ((l == 10) && (!strcmp(s+5, "align")))
  600.     return S_ALIGN;
  601.     } else if (strncmp(s,"margin", 6) == 0) {
  602. if (l == 6)
  603.     return S_MARGIN_SHORTHAND;
  604. if ((l == 10) && (strcmp(&s[7], "top") == 0))
  605.     return S_MARGIN_TOP;
  606. if ((l == 12) && (strcmp(&s[7], "right") == 0))
  607.     return S_MARGIN_RIGHT;
  608. if ((l == 13) && (strcmp(&s[7], "bottom") == 0))
  609.     return S_MARGIN_BOTTOM;
  610. if ((l == 11) && (strcmp(&s[7], "left") == 0))
  611.     return S_MARGIN_LEFT;
  612.     } else if (strncmp(s, "color", 5) == 0) {
  613.       return S_COLOR;
  614.     } else if (strncmp(s, "background", 10) == 0) {
  615.       return S_BACKGROUND;
  616.     } else if (strncmp(s,"alt", 3) == 0) {
  617. s += 4;
  618. l -= 4;
  619. if (strncmp(s,"font", 4) == 0) {
  620.     if (l == 4)
  621. return S_ALT_FONT_SHORTHAND;
  622.     if ((l == 9) && (strcmp(&s[5], "size") == 0))
  623. return S_ALT_FONT_SIZE;
  624. /*
  625.     if ((l == 15) && (strcmp(&s[5], "size-index") == 0))
  626. return S_ALT_FONT_SIZE_INDEX;
  627. */
  628.     if ((l == 11) && (strcmp(&s[5], "family") == 0))
  629. return S_ALT_FONT_FAMILY;
  630.     if ((l == 11) && (strcmp(&s[5], "weight") == 0))
  631. return S_ALT_FONT_WEIGHT;
  632.     if ((l == 10) && (strcmp(&s[5], "style") == 0))
  633. return S_ALT_FONT_STYLE;
  634.     if ((l == 12) && (strcmp(&s[5], "leading") == 0))
  635. return S_ALT_FONT_LEADING;
  636. } else if (strncmp(s,"text", 4) == 0) {
  637.     if ((l == 10) && (strcmp(&s[5], "color") == 0))           /* historical */
  638. return S_ALT_COLOR;
  639.     if ((l == 15) && (strcmp(&s[5], "background") == 0))      /* historical */
  640. return S_ALT_BACKGROUND;
  641.     if ((l == 13) && (strcmp(&s[5], "spacing") == 0))
  642. return S_ALT_TEXT_SPACING;
  643.     if ((l == 9) && (strcmp(&s[5], "decoration") == 0))
  644. return S_ALT_TEXT_DECORATION;
  645.     if ((l == 9) && (strcmp(&s[5], "line") == 0))             /* historical */
  646. return S_ALT_TEXT_DECORATION;
  647.     if ((l == 13) && (strcmp(&s[5], "position") == 0))
  648. return S_ALT_TEXT_POSITION;
  649.     if ((l == 14) && (strcmp(&s[5], "transform") == 0))
  650. return S_ALT_TEXT_TRANSFORM;
  651. } else if (strncmp(s, "color", 5) == 0) {
  652.   return S_COLOR;
  653. } else if (strncmp(s, "background", 10) == 0) {
  654.   return S_BACKGROUND;
  655. }
  656. if (STYLE_TRACE & VERBOSE_TRACE)
  657.     fprintf(stderr,"can't chew *prop_peter %sn", s);
  658. return S_UNKNOWN;
  659.     }
  660.     
  661.     if(strcasecmp(s,"indent")==0)
  662. return S_INDENT;
  663.     if (strcasecmp(s,"font.family")==0) {
  664. return S_FONT_FAMILY;
  665.     } else if (strcasecmp(s,"font.size")==0) {
  666. return S_FONT_SIZE;
  667.     } else if ( (strcasecmp(s,"font.color")==0) || (strcasecmp(s,"color.text")==0)) {
  668. return S_COLOR;
  669.     } else if (strcasecmp(s,"oversize.font.family")==0) {
  670. return S_ALT_FONT_FAMILY;
  671.     } else if (strcasecmp(s,"oversize.font.size")==0) {
  672. return S_ALT_FONT_SIZE;
  673.     } else if (strcasecmp(s,"oversize.font.color")==0) {
  674. return S_ALT_COLOR;
  675.     } else if (strcasecmp(s,"back.color")==0) {
  676. return S_BACKGROUND;
  677.     } else if (strcasecmp(s,"color.background")==0) {   /* backwards compatibility */
  678. return S_BACKGROUND;
  679.     } else {
  680. if (STYLE_TRACE & VERBOSE_TRACE)
  681.     fprintf(stderr,"can't chew *prop_peter %sn", s);
  682. return S_UNKNOWN;
  683.     }
  684. }
  685. int element_enum(char *s, int *token_class_p)
  686. {
  687.     int c, len;
  688.     len = strlen(s);
  689.     c = TOLOWER(*s);
  690.     if (isalpha(c))
  691.     {
  692.         if (c == 'a')
  693.         {
  694.             if (len == 1 && strncasecmp(s, "a", len) == 0)
  695.             {
  696.                 *token_class_p = EN_TEXT;
  697.                 return TAG_ANCHOR;
  698.             }
  699.             if (len == 3 && strncasecmp(s, "alt", len) == 0)
  700.             {
  701.                 *token_class_p = EN_BLOCK;
  702.                 return TAG_ALT;
  703.             }
  704.             if (len == 5 && strncasecmp(s, "added", len) == 0)
  705.             {
  706.                 *token_class_p = EN_TEXT;
  707.                 return TAG_ADDED;
  708.             }
  709.             if (len == 7 && strncasecmp(s, "address", len) == 0)
  710.             {
  711.                 *token_class_p = EN_BLOCK;
  712.                 return TAG_ADDRESS;
  713.             }
  714.             if (len == 8 && strncasecmp(s, "abstract", len) == 0)
  715.             {
  716.                 *token_class_p = EN_BLOCK;
  717.                 return TAG_ABSTRACT;
  718.             }
  719.         }
  720.         else if (c == 'b')
  721.         {
  722.             if (len == 1)
  723.             {
  724.                 *token_class_p = EN_TEXT;
  725.                 return TAG_BOLD;
  726.             }
  727.             if (len == 2 && strncasecmp(s, "br", len) == 0)
  728.             {
  729.                 *token_class_p = EN_TEXT;
  730.                 return TAG_BR;
  731.             }
  732.             if (len == 4 && strncasecmp(s, "body", len) == 0)
  733.             {
  734.                 *token_class_p = EN_MAIN;
  735.                 return TAG_BODY;
  736.             }
  737.             if (len == 10 && strncasecmp(s, "blockquote", len) == 0)
  738.             {
  739.                 *token_class_p = EN_BLOCK;
  740.                 return TAG_QUOTE;
  741.             }
  742.             if (len == 4 && strncasecmp(s, "base", len) == 0)
  743.             {
  744.                 *token_class_p = EN_SETUP;
  745.                 return TAG_BASE;
  746.             }
  747.         }
  748.         else if (c == 'c')
  749.         {
  750.             if (len == 4)
  751.             {
  752.                 if (strncasecmp(s, "code", len) == 0)
  753.                 {
  754.                     *token_class_p = EN_TEXT;
  755.                     return TAG_CODE;
  756.                 }
  757.                 if (strncasecmp(s, "cite", len) == 0)
  758.                 {
  759.                     *token_class_p = EN_TEXT;
  760.                     return TAG_CITE;
  761.                 }
  762.             }
  763.             else if (len == 7 && (strncasecmp(s, "caption", len) == 0))/* howcome 3/2/95: = -> == after hint from P.M.Hounslow@reading.ac.uk */
  764.             {
  765.                 *token_class_p = EN_BLOCK;
  766.                 return TAG_CAPTION;
  767.             }
  768.         }
  769.         else if (c == 'd')
  770.         {
  771.             if (len == 3 && strncasecmp(s, "dfn", len) == 0)
  772.             {
  773.                 *token_class_p = EN_TEXT;
  774.                 return TAG_DFN;
  775.             }
  776.     /* howcome 11/8/95: added upport for DIR */
  777.             if (len == 3 && strncasecmp(s, "dir", len) == 0)
  778.             {
  779.                 *token_class_p = EN_LIST;
  780.                 return TAG_UL;
  781.             }
  782.             if (len != 2)
  783.                 return 0;
  784.             if (strncasecmp(s, "dl", len) == 0)
  785.             {
  786.                 *token_class_p = EN_LIST;
  787.                 return TAG_DL;
  788.             }
  789.             if (strncasecmp(s, "dt", len) == 0)
  790.             {
  791.                 *token_class_p = EL_DEFLIST;
  792.                 return TAG_DT;
  793.             }
  794.             if (strncasecmp(s, "dd", len) == 0)
  795.             {
  796.                 *token_class_p = EL_DEFLIST;
  797.                 return TAG_DD;
  798.             }
  799.         }
  800.         else if (c == 'e')
  801.         {
  802.             if (len == 2 && strncasecmp(s, "em", len) == 0)
  803.             {
  804.                 *token_class_p = EN_TEXT;
  805.                 return TAG_EM;
  806.             }
  807.         }
  808.         else if (c == 'f')
  809.         {
  810.             if (len == 3 && strncasecmp(s, "fig", len) == 0)
  811.             {
  812.                 *token_class_p = EN_BLOCK;
  813.                 return TAG_FIG;
  814.             }
  815.         }
  816.         else if (c == 'h')
  817.         {
  818.             if (len == 4) {
  819. if (strncasecmp(s, "head", len) == 0)
  820. {
  821.     *token_class_p = EN_SETUP;
  822.     return TAG_HEAD;
  823. /* added by howcome 27/8/95 */
  824. else if (strncasecmp(s, "html", len) == 0)
  825. {
  826.     *token_class_p = EN_SETUP;
  827.     return TAG_HTML;
  828. }
  829.     }
  830.             if (len != 2)
  831.                 return 0;
  832.             *token_class_p = EN_HEADER;
  833.             c = TOLOWER(s[1]);
  834.             switch (c)
  835.             {
  836.                 case '1':
  837.                     return TAG_H1;
  838.                 case '2':
  839.                     return TAG_H2;
  840.                 case '3':
  841.                     return TAG_H3;
  842.                 case '4':
  843.                     return TAG_H4;
  844.                 case '5':
  845.                     return TAG_H5;
  846.                 case '6':
  847.                     return TAG_H6;
  848.                 case 'r':
  849.                     *token_class_p = EN_BLOCK;
  850.                     return TAG_HR;
  851.             }
  852.         }
  853.         else if (c == 'i')
  854.         {
  855.             if (len == 1)
  856.             {
  857.                 *token_class_p = EN_TEXT;
  858.                 return TAG_ITALIC;
  859.             }
  860.             if (len == 3 && strncasecmp(s, "img", len) == 0)
  861.             {
  862.                 *token_class_p = EN_TEXT;
  863.                 return TAG_IMG;
  864.             }
  865.             if (len == 5 && strncasecmp(s, "input", len) == 0)
  866.             {
  867.                 *token_class_p = EN_TEXT;
  868.                 return TAG_INPUT;
  869.             }
  870.             if (len == 7 && strncasecmp(s, "isindex", len) == 0)
  871.             {
  872.                 *token_class_p = EN_SETUP;
  873.                 return TAG_ISINDEX;
  874.             }
  875.         }
  876.         else if (c == 'k')
  877.         {
  878.             if (len == 3 && strncasecmp(s, "kbd", len) == 0)
  879.             {
  880.                 *token_class_p = EN_TEXT;
  881.                 return TAG_KBD;
  882.             }
  883.         }
  884.         else if (c == 'l')
  885.         {
  886.             if (len == 2 && strncasecmp(s, "li", len) == 0)
  887.             {
  888.                 *token_class_p = EN_LIST;
  889.                 return TAG_LI;
  890.             }
  891.             if (len == 4 && strncasecmp(s, "link", len) == 0)
  892.             {
  893.                 *token_class_p = EN_SETUP;
  894.                 return TAG_LINK;
  895.             }
  896.         }
  897.         else if (c == 'm')
  898.         {
  899.             if (len == 4 && strncasecmp(s, "math", len) == 0)
  900.             {
  901.                 *token_class_p = EN_TEXT;
  902.                 return TAG_MATH;
  903.             }
  904.             if (len == 6 && strncasecmp(s, "margin", len) == 0)
  905.             {
  906.                 *token_class_p = EN_TEXT;
  907.                 return TAG_MARGIN;
  908.             }
  909.     /* howcome 11/8/95: added MENU to be compatible with HTML2 */
  910.             if (len == 4 && strncasecmp(s, "menu", len) == 0)
  911.             {
  912.                 *token_class_p = EN_LIST;
  913.                 return TAG_UL;
  914.             }
  915.         }
  916.         else if (c == 'n')
  917.         {
  918.             if (len == 4 && strncasecmp(s, "note", len) == 0)
  919.             {
  920.                 *token_class_p = EN_BLOCK;
  921.                 return TAG_NOTE;
  922.             }
  923.         }
  924.         else if (c == 'o')
  925.         {
  926.             if (len == 2 && strncasecmp(s, "ol", len) == 0)
  927.             {
  928.                 *token_class_p = EN_LIST;
  929.                 return TAG_OL;
  930.             }
  931.             if (len == 6 && strncasecmp(s, "option", len) == 0)
  932.             {
  933.                 *token_class_p = EN_TEXT;  /* kludge for error recovery */
  934.                 return TAG_OPTION;
  935.             }
  936.         }
  937.         else if (c == 'p')
  938.         {
  939.             if (len == 1)
  940.             {
  941.                 *token_class_p = EN_BLOCK;
  942.                 return TAG_P;
  943.             }
  944.             if (len == 3 && strncasecmp(s, "pre", len) == 0)
  945.             {
  946.                 *token_class_p = EN_BLOCK;
  947.                 return TAG_PRE;
  948.             }
  949.         }
  950.         else if (c == 'q')
  951.         {
  952.             if (len == 1)
  953.             {
  954.                 *token_class_p = EN_TEXT;
  955.                 return TAG_Q;
  956.             }
  957.             if (len == 5 && strncasecmp(s, "quote", len) == 0)
  958.             {
  959.                 *token_class_p = EN_BLOCK;
  960.                 return TAG_QUOTE;
  961.             }
  962.         }
  963.         else if (c == 'r')
  964.         {
  965.             if (len == 7 && strncasecmp(s, "removed", len) == 0)
  966.             {
  967.                 *token_class_p = EN_TEXT;
  968.                 return TAG_REMOVED;
  969.             }
  970.         }
  971.         else if (c == 's')
  972.         {
  973.             if (len == 1)
  974.             {
  975.                 *token_class_p = EN_TEXT;
  976.                 return TAG_STRIKE;
  977.             }
  978.             if (len == 3 && strncasecmp(s, "sup", len) == 0)
  979.             {
  980.                 *token_class_p = EN_TEXT;
  981.                 return TAG_SUP;
  982.             }
  983.             if (len == 3 && strncasecmp(s, "sub", len) == 0)
  984.             {
  985.                 *token_class_p = EN_TEXT;
  986.                 return TAG_SUB;
  987.             }
  988.             if (len == 4 && strncasecmp(s, "samp", len) == 0)
  989.             {
  990.                 *token_class_p = EN_TEXT;
  991.                 return TAG_SAMP;
  992.             }
  993.             if (len == 5 && strncasecmp(s, "small", len) == 0)
  994.             {
  995.                 *token_class_p = EN_TEXT;
  996.                 return TAG_SMALL;
  997.             }
  998.             if (len == 6 && strncasecmp(s, "strong", len) == 0)
  999.             {
  1000.                 *token_class_p = EN_TEXT;
  1001.                 return TAG_STRONG;
  1002.             }
  1003.             if (len == 6 && strncasecmp(s, "select", len) == 0)
  1004.             {
  1005.                 *token_class_p = EN_TEXT;
  1006.                 return TAG_SELECT;
  1007.             }
  1008.             if (len == 6 && strncasecmp(s, "strike", len) == 0)
  1009.             {
  1010.                 *token_class_p = EN_TEXT;
  1011.                 return TAG_STRIKE;
  1012.             }
  1013.     /* howcome 26/2/95 */
  1014.             if (len == 5 && strncasecmp(s, "style", len) == 0)
  1015.             {
  1016.                 *token_class_p = EN_SETUP;
  1017.                 return TAG_STYLE;
  1018.             }
  1019.         }
  1020.         else if (c == 't')
  1021.         {
  1022.             if (len == 5 && strncasecmp(s, "title", len) == 0)
  1023.             {
  1024.                 *token_class_p = EN_SETUP;
  1025.                 return TAG_TITLE;
  1026.             }
  1027.             if (len == 2 && strncasecmp(s, "tt", len) == 0)
  1028.             {
  1029.                 *token_class_p = EN_TEXT;
  1030.                 return TAG_TT;
  1031.             }
  1032.             if (len == 2 && strncasecmp(s, "tr", len) == 0)
  1033.             {
  1034.                 *token_class_p = EN_TABLE;
  1035.                 return TAG_TR;
  1036.             }
  1037.             if (len == 2 && strncasecmp(s, "th", len) == 0)
  1038.             {
  1039.                 *token_class_p = EN_TABLE;
  1040.                 return TAG_TH;
  1041.             }
  1042.             if (len == 2 && strncasecmp(s, "td", len) == 0)
  1043.             {
  1044.                 *token_class_p = EN_TABLE;
  1045.                 return TAG_TD;
  1046.             }
  1047.             if (len == 5 && strncasecmp(s, "table", len) == 0)
  1048.             {
  1049.                 *token_class_p = EN_BLOCK;
  1050.                 return TAG_TABLE;
  1051.             }
  1052.             if (len == 8 && strncasecmp(s, "textarea", len) == 0)
  1053.             {
  1054.                 *token_class_p = EN_TEXT;
  1055.                 return TAG_TEXTAREA;
  1056.             }
  1057.         }
  1058.         else if (c == 'u')
  1059.         {
  1060.             if (len == 1)
  1061.             {
  1062.                 *token_class_p = EN_TEXT;
  1063.                 return TAG_UNDERLINE;
  1064.             }
  1065.             if (len == 2 && strncasecmp(s, "ul", len) == 0)
  1066.             {
  1067.                 *token_class_p = EN_LIST;
  1068.                 return TAG_UL;
  1069.             }
  1070.         }
  1071.         else if (c == 'v')
  1072.         {
  1073.             if (len == 3 && strncasecmp(s, "var", len) == 0)
  1074.             {
  1075.                 *token_class_p = EN_TEXT;
  1076.                 return TAG_VAR;
  1077.             }
  1078.         }
  1079.         else if (c == 'x')
  1080.         {
  1081.             if (len == 3 && strncasecmp(s, "xmp", len) == 0)
  1082.             {
  1083.                 *token_class_p = EN_BLOCK;
  1084.                 return TAG_PRE;
  1085.             }
  1086.         }
  1087.     }
  1088.     *token_class_p = EN_UNKNOWN;
  1089.     return UNKNOWN; /* unknown tag */
  1090. }
  1091. StyleSelector *ParseSelector(char *str)
  1092. {
  1093.     char *p;
  1094.     char *elem_marker, *subelem_marker;
  1095.     StyleSelector *selector = NULL, *prev_selector = NULL;
  1096.     int token_class;
  1097.     p = str_tok(str,"/() t",&elem_marker);
  1098.     do {
  1099. int element;
  1100. char *class;
  1101. p = str_tok(p, ".",&subelem_marker);
  1102. element = element_enum(p, &token_class);
  1103. if (strcmp(p, "*") == 0) {
  1104.     element = TAG_HTML;
  1105. } else if (strcasecmp(p, "$HTML-SOURCE") == 0) {
  1106.     element = TAG_HTML_SOURCE;
  1107. }
  1108. if (strcmp(p, "HTML") == 0) {
  1109.     element = TAG_HTML;
  1110. } else if (strcasecmp(p, "$HTML-SOURCE") == 0) {
  1111.     element = TAG_HTML_SOURCE;
  1112. }
  1113. if (element == UNKNOWN) {
  1114.     return NULL;
  1115. }
  1116. class = str_tok(NULL," t",&subelem_marker);
  1117. selector = NewStyleSelector();
  1118. selector->unit.element = element;
  1119. if (class && *class)
  1120.     selector->unit.class = strdup(class);
  1121. selector->ancestor = prev_selector;
  1122. prev_selector = selector;
  1123.     } while ( (p = str_tok(NULL, "() t",&elem_marker)) );
  1124.     return selector;
  1125. }
  1126. BG_Style *StyleGetBackground(void *value_p, char *str)
  1127. {
  1128.     BG_Style *bg_style;
  1129.     Image *image;
  1130.     char *tmp;
  1131.     int is_numeric;
  1132.     if (value_p) {
  1133. bg_style = (BG_Style *) value_p;
  1134.     } else  { 
  1135. bg_style = (BG_Style *) calloc(1, sizeof(BG_Style));
  1136. bg_style->flag = S_BACKGROUND_X_REPEAT | S_BACKGROUND_Y_REPEAT;
  1137. bg_style->x_pos = 50;
  1138. bg_style->y_pos = 50;
  1139.     } 
  1140.     if(!strcmp(str,":"))
  1141. return (bg_style);
  1142.     
  1143.     if (str[0] == '#') {
  1144. if (strlen(str) == 4) {
  1145.     bg_style->r = hex2byte(str[1]) * 17;
  1146.     bg_style->g = hex2byte(str[2]) * 17;
  1147.     bg_style->b = hex2byte(str[3]) * 17;
  1148.     bg_style->flag |= S_BACKGROUND_COLOR;
  1149.     /*     fprintf(stderr,"%x %x %x -> %dn", r, g, b, *value_p);*/
  1150. } else if (strlen(str) == 7) {
  1151.     bg_style->r = hex2byte(str[1]) * 16 + hex2byte(str[2]);
  1152.     bg_style->g = hex2byte(str[3]) * 16 + hex2byte(str[4]);
  1153.     bg_style->b = hex2byte(str[5]) * 16 + hex2byte(str[6]);
  1154.     bg_style->flag |= S_BACKGROUND_COLOR;
  1155.     /*     fprintf(stderr,"%x %x %x -> %dn", r, g, b, *value_p);*/
  1156. }
  1157.     } else if (str[0] == '"')
  1158.     {
  1159. if ((image = GetImage(str+1, strlen(str)-2, CurrentDoc->pending_reload))) {
  1160.     bg_style->image = image;
  1161.     bg_style->flag |= S_BACKGROUND_IMAGE;
  1162. }
  1163.     } else { /* try looking up the name */
  1164. if (!strcasecmp(str,"fixed"))
  1165.     bg_style->flag |= S_BACKGROUND_FIXED;
  1166. else {
  1167.     if (!strcasecmp(str,"repeat-x"))
  1168. bg_style->flag &= ~S_BACKGROUND_Y_REPEAT;
  1169.     else {
  1170. if (!strcasecmp(str,"repeat-y"))
  1171.     bg_style->flag &= ~S_BACKGROUND_X_REPEAT;
  1172. else {
  1173.     if (!strcasecmp(str,"no-repeat"))
  1174. bg_style->flag &= ~(S_BACKGROUND_X_REPEAT|S_BACKGROUND_Y_REPEAT);
  1175.     else
  1176.     {
  1177. is_numeric = TRUE;
  1178. tmp = str;
  1179. while(*tmp&&is_numeric)
  1180. {
  1181.     is_numeric = ((*tmp>='0') && (*tmp <= '9')) || (*tmp=='%');
  1182.     tmp++;
  1183. };
  1184. if(is_numeric)
  1185. {
  1186.     if(bg_style->flag & S_BACKGROUND_ORIGIN)
  1187. bg_style->y_pos = atoi(str);
  1188.     else
  1189.     {
  1190. bg_style->flag |= S_BACKGROUND_ORIGIN;
  1191. bg_style->x_pos = atoi(str);
  1192. bg_style->y_pos = bg_style->x_pos;
  1193.     }
  1194. }
  1195. else
  1196. {
  1197.     long color = ParseColor(str);
  1198.     bg_style->r = (color >> 16) & 0xFF;
  1199.     bg_style->g = (color >>  8) & 0xFF;
  1200.     bg_style->b = color & 0xFF;
  1201.     bg_style->flag |= S_BACKGROUND_COLOR;
  1202. }
  1203.     }
  1204. }
  1205.     }
  1206. }
  1207.     }
  1208.     return (bg_style);
  1209. }
  1210. /* ?? */
  1211. static Bool ParseAssignment(char *s, StyleProperty *prop_p, long *value_p, int *level_p, char delimiter)
  1212. {
  1213.     char *str;
  1214.     char *elem, *value;
  1215.     char first_str_tok[8], second_str_tok[8];
  1216.     if (!s)
  1217. return False;
  1218.     sprintf(first_str_tok,"%c t", delimiter);
  1219.     str = str_tok(s,first_str_tok,&elem);
  1220.     if (!str)
  1221. return False;
  1222.     
  1223.     *prop_p = Property2enum(str);
  1224.     if (*prop_p == S_UNKNOWN)
  1225. return False;
  1226.     
  1227.     if (STYLE_TRACE & VERBOSE_TRACE)
  1228. fprintf(stderr,"StyleChew: *prop_p = %dn",*prop_p);
  1229.     
  1230.     /* get everything up to '!' */
  1231.     
  1232.     str = str_tok(NULL,"!",&elem);
  1233.     if (!str)
  1234. return False;
  1235.     sprintf(first_str_tok,"%c,;& t",delimiter);
  1236.     str = str_tok(str,first_str_tok,&value);
  1237.     
  1238.     while (str) {
  1239. switch (*prop_p) {
  1240.   case S_FONT_FAMILY:
  1241.   case S_ALT_FONT_FAMILY:
  1242.     if (! *value_p)
  1243. *value_p = (long) HTList_new();
  1244.     HTList_addObjectFirst((HTList *)*value_p, (void *)strdup(str)); /* ughh */
  1245.     break;
  1246.   case S_FONT_SIZE:
  1247.   case S_ALT_FONT_SIZE:
  1248.   case S_FONT_LEADING:
  1249.   case S_ALT_FONT_LEADING:
  1250.     if (strcasecmp(str,"xx-large") == 0)
  1251. *value_p = (long)21;
  1252.     else if (strcasecmp(str,"x-large") == 0)
  1253. *value_p = (long)17;
  1254.     else if (strcasecmp(str,"large") == 0)
  1255. *value_p = (long)14;
  1256.     else if (strcasecmp(str,"medium") == 0)
  1257. *value_p = (long)12;
  1258.     else if (strcasecmp(str,"small") == 0)
  1259. *value_p = (long)10;
  1260.     else if (strcasecmp(str,"x-small") == 0)
  1261. *value_p = (long)9;
  1262.     else if (strcasecmp(str,"xx-small") == 0)
  1263. *value_p = (long)8;
  1264.     else if (strstr(str,"px")) {
  1265. *value_p = (long)atoi(str);
  1266.     } else { /* pt being the default sixe unit */
  1267. *value_p = (long)pt2px((double)atof(str));
  1268.     }
  1269.     break;
  1270.   case S_FONT_WEIGHT:
  1271.   case S_ALT_FONT_WEIGHT:
  1272.     if (strcasecmp(str,"light") == 0)
  1273. *value_p = (long)FONT_WEIGHT_LIGHT;
  1274.     else if (strcasecmp(str,"medium") == 0)
  1275. *value_p = (long)FONT_WEIGHT_MEDIUM;
  1276.     else if (strcasecmp(str,"demibold") == 0)
  1277. *value_p = (long)FONT_WEIGHT_DEMIBOLD;
  1278.     else if (strcasecmp(str,"bold") == 0)
  1279. *value_p = (long)FONT_WEIGHT_BOLD;
  1280.     break;
  1281.   case S_FONT_STYLE:
  1282.   case S_ALT_FONT_STYLE:
  1283.     if (strncasecmp(str,"italic", 6) == 0) /* italics */
  1284. *value_p = (long)FONT_STYLE_ITALIC;
  1285.     else if (strcasecmp(str,"roman") == 0)
  1286. *value_p = (long)FONT_STYLE_ROMAN;
  1287.     else if (strcasecmp(str,"small-caps") == 0)
  1288. *value_p = (long)FONT_STYLE_SMALL_CAPS;
  1289.     break;
  1290.   case S_TEXT_EFFECT:
  1291.     if (strcasecmp(str,"initial-cap") == 0)
  1292. *value_p = (long)TEXT_EFFECT_INITIAL_CAP;
  1293.     else if (strcasecmp(str,"drop-cap") == 0)
  1294. *value_p = (long)TEXT_EFFECT_DROP_CAP;
  1295.     else if (strcasecmp(str,"alt-firstline") == 0)
  1296. *value_p = (long)TEXT_EFFECT_ALT_FIRSTLINE;
  1297.     break;
  1298.   case S_TEXT_DECORATION:
  1299.     if (strcasecmp(str,"blink") == 0)
  1300. *value_p = (long)TEXT_LINE_BLINK;
  1301.     break;
  1302.   case S_MARGIN_LEFT:
  1303.   case S_MARGIN_RIGHT:
  1304.   case S_MARGIN_TOP:
  1305.       case S_MARGIN_BOTTOM:
  1306.     case S_INDENT:
  1307.   case S_TEXT_SPACING:
  1308.       *value_p = (long)(atoi(str));
  1309.       break;
  1310.  
  1311.   case S_ALIGN:
  1312.     if (strcasecmp(str,"left") == 0) {
  1313. *value_p = (long)ALIGN_LEFT;
  1314.     } else if (strcasecmp(str,"center") == 0) {
  1315. *value_p = (long)ALIGN_CENTER;
  1316.     } else if (strcasecmp(str,"right") == 0) {
  1317. *value_p = (long)ALIGN_RIGHT;
  1318.     } else if (strcasecmp(str,"justify") == 0) {
  1319. *value_p = (long)ALIGN_JUSTIFY;
  1320.     } else
  1321. return False;
  1322.     break;
  1323.   case S_COLOR:
  1324.   case S_ALT_COLOR:
  1325.     if (str[0] == '#') {
  1326. Byte r, g, b;
  1327. if (strlen(str) == 4) {
  1328.     r = hex2byte(str[1]) * 17;
  1329.     g = hex2byte(str[2]) * 17;
  1330.     b = hex2byte(str[3]) * 17;
  1331.     *value_p = ((r<<16) | (g<<8) | b);
  1332. /*     fprbytef(stderr,"%x %x %x -> %dn", r, g, b, *value_p);*/
  1333. } else if (strlen(str) == 7) {
  1334.     r = hex2byte(str[1]) * 16 + hex2byte(str[2]);
  1335.     g = hex2byte(str[3]) * 16 + hex2byte(str[4]);
  1336.     b = hex2byte(str[5]) * 16 + hex2byte(str[6]);
  1337.     *value_p = ((r<<16) | (g<<8) | b);
  1338. /*     fprintf(stderr,"%x %x %x -> %dn", r, g, b, *value_p);*/
  1339. }
  1340.     } else { /* try looking up the name */
  1341. *value_p = (long)ParseColor(str);
  1342.     }
  1343.     break;     
  1344.      case S_PADDING:
  1345.       *value_p = (long)atoi(str); /* only x & y & i & j */
  1346.       break;
  1347.   case S_BACKGROUND:
  1348.   case S_ALT_BACKGROUND:
  1349.       *value_p = (long) StyleGetBackground(*value_p, str);
  1350.       break;
  1351.   default:
  1352.     if (STYLE_TRACE & VERBOSE_TRACE)
  1353. fprintf(stderr,"can't chew value: %sn", str);
  1354.     return False;
  1355.     break;
  1356. }
  1357. sprintf(second_str_tok,"%c,& t",delimiter);
  1358. str = str_tok(NULL,second_str_tok,&value);
  1359.     }
  1360.     /*  level_declaration: */
  1361.     *level_p = I_NORMAL;
  1362.     str = str_tok(NULL,"! t;",&elem);
  1363.     if (str) {
  1364. if (strcasecmp(str,"important") == 0) {
  1365.     *level_p = I_IMPORTANT;
  1366. }
  1367. else if (strcasecmp(str,"insist") == 0) {
  1368.     *level_p = I_INSIST;
  1369. }
  1370. else if (strcasecmp(str,"legal") == 0) {
  1371.     *level_p = I_LEGAL;
  1372. }
  1373.     }
  1374.     return True;
  1375. }
  1376. /*
  1377.   StyleChew is the main entry point to the CSS parser. 
  1378.   *sheet is a pointer to a StyleSheet structure into which the
  1379.   assignments will be added
  1380.   *str is a pointer to a string containing CSS syntax. Th pointer wil
  1381.   not be freed,a dn the content will remain unchanged.
  1382.   base_weight identifies the source of the style sheet, author or
  1383.   reader
  1384. */
  1385. void StyleChew(StyleSheet *sheet, char *str, int base_weight)
  1386. {
  1387.     char *sheet_marker, *address_marker, *assignment_marker;
  1388.     char *p, *q, *r, *s;
  1389.     StyleProperty property;
  1390.     int level;
  1391.     int weight;
  1392.     long value;
  1393.     void *bg_save;
  1394.     int bg_weight=0;
  1395.     HTList *l, *selectors;
  1396.     StyleSelector *selector;
  1397.     char begin_char,end_char,set_char,*tmp_char; /* used for backward compatibility --Spif 23-Nov-95 */
  1398.     char delim_char;
  1399.     char str_tok_begin[2], str_tok_set[2], str_tok_end[2];
  1400.     if (STYLE_TRACE & VERBOSE_TRACE)
  1401. fprintf(stderr,"nStyleChewn");
  1402.     /* h1, p: font-family = helvetica times, font-size = 12pt; */
  1403.     if (!str)
  1404. return;
  1405.     begin_char = ':' ; 
  1406.     set_char   = '=' ;
  1407.     delim_char = ',';
  1408.     end_char   = 'n';
  1409.     for(tmp_char = str; *tmp_char ; tmp_char++)  /* figure out what kind of notation, old or new one --Spif 23-Nov-95 */
  1410. if(*tmp_char == '{')
  1411. {
  1412.     begin_char = '{';
  1413.     set_char   = ':';
  1414.     delim_char = ';';
  1415.     end_char   = '}';
  1416. };
  1417.     *str_tok_end = end_char;
  1418.     *str_tok_begin = begin_char;
  1419.     *str_tok_set = set_char;
  1420.     str_tok_begin[1] = 0;
  1421.     str_tok_set[1] = 0;
  1422.     str_tok_end[1] = 0;
  1423.     s = strdup(str);  /* we will modify the string so we make a copy */
  1424.     
  1425.     while(tmp_char = strstr(s, "--"))
  1426.     {
  1427. while(*tmp_char && (*tmp_char!='n'))
  1428.     *tmp_char++=' ';
  1429.     };
  1430.     if(begin_char=='{')
  1431. for(tmp_char = s; *tmp_char ;tmp_char++)
  1432.     if(*tmp_char=='n')
  1433. *tmp_char = ' ';
  1434.     p = str_tok(s,str_tok_end ,&sheet_marker);
  1435.     if (!p)
  1436. return;
  1437.     do {
  1438. /* first screen out the comments */
  1439. if (p[0] == '#')
  1440.     continue;
  1441. if ((q = strstr(p, "--")))
  1442.     *q = 0;
  1443. /* then see if the "left side" (before ':') is specified */
  1444. if ((q = strchr(p, begin_char)) && (r = strchr(p,set_char)) && (q < r)) {
  1445.     /* yes, the left side is specified, nail it */
  1446.     p = str_tok(p, str_tok_begin, &address_marker);
  1447.     if (strchr(p, '/'))
  1448. continue;
  1449.     if (STYLE_TRACE)
  1450. fprintf(stderr,"(address) %s -> ", p);
  1451.     selectors = HTList_new();
  1452.     p = str_tok(p, ",;", &address_marker);
  1453.     do {
  1454. StyleSelector *s;
  1455. if ((s = ParseSelector(p))) {
  1456.     if (STYLE_TRACE) {
  1457. StyleSelector *sc = s;
  1458. do {
  1459.     fprintf(stderr,"%d-",sc->unit.element);
  1460. } while((sc = sc->ancestor));
  1461.     }
  1462.     HTList_addObject(selectors, (void *) s);
  1463. }
  1464.     } while ((p = str_tok(NULL,",;",&address_marker)));
  1465.     p = q + 1;
  1466. } else {
  1467.     if (STYLE_TRACE)
  1468. fprintf(stderr,"StyleChew, left side not specified..n");
  1469.     continue;
  1470. }
  1471. /* now we know what elements we are addressing */
  1472. p = str_tok(p, ";,", &assignment_marker);
  1473. bg_save = NULL;
  1474. do {
  1475.     if (STYLE_TRACE)
  1476. fprintf(stderr,"(assignment) %s ", p);
  1477.    
  1478.     value = (long)bg_save;  /* this hack is only for keeping bg_style during the parsing of one element --Spif 23-Nov-95 */
  1479.     if (ParseAssignment(p, &property, &value, &level, set_char)) 
  1480.     {
  1481. if (base_weight == S_USER)
  1482.     weight = base_weight + S_USER_DELTA * level;
  1483. else
  1484.     weight = base_weight + S_DOC_DELTA * level;
  1485. if(property == S_BACKGROUND)
  1486. {
  1487.     bg_save = (void *)value;
  1488.     bg_weight = weight;
  1489. }
  1490. else
  1491. {
  1492.     l = selectors;
  1493.     while ((selector = (StyleSelector *)HTList_nextObject(l)) ) 
  1494.     {
  1495. if (STYLE_TRACE) 
  1496. {
  1497.     StyleSelector *sc = selector;
  1498.     fprintf(stderr,"nnext selector ");
  1499.     do 
  1500.     {
  1501. fprintf(stderr,"%d-",sc->unit.element);
  1502.     } while((sc = sc->ancestor));
  1503.     fprintf(stderr,"n");
  1504. }
  1505. StyleAddRule(sheet, selector, property, value, weight);
  1506.     }
  1507. }
  1508.     }
  1509. } while ( (p = str_tok(NULL,";,",&assignment_marker)) ); 
  1510. if(bg_save)
  1511. {
  1512.     l = selectors;
  1513.     while ((selector = (StyleSelector *)HTList_nextObject(l)) ) 
  1514.     {
  1515. if (STYLE_TRACE) 
  1516. {
  1517.     StyleSelector *sc = selector;
  1518.     fprintf(stderr,"nnext selector ");
  1519.     do 
  1520.     {
  1521. fprintf(stderr,"%d-",sc->unit.element);
  1522.     } while((sc = sc->ancestor));
  1523.     fprintf(stderr,"n");
  1524. }
  1525. StyleAddRule(sheet, selector, S_BACKGROUND,(long)bg_save, bg_weight);
  1526.     }
  1527. };
  1528. if (STYLE_TRACE)
  1529.     fprintf(stderr,"n");
  1530. /*
  1531. l = selectors;
  1532. while ( (selector = (StyleSelector *)HTList_nextObject(l)) ) {
  1533.     if (STYLE_TRACE && VERBOSE_TRACE)
  1534. fprintf(stderr,"freeing selectorn");
  1535.     FreeStyleSelector(selector);
  1536. }
  1537. HTList_delete(selectors);
  1538. */
  1539.     } while ( (p = str_tok(NULL, str_tok_end, &sheet_marker)) ); 
  1540.     Free(s);
  1541. }
  1542. /*
  1543.   StyleGetInit returns an initialized style sheet, typically the application's default 
  1544. */
  1545. StyleSheet *StyleGetInit()
  1546. {
  1547.     StyleSheet *sheet = NewStyleSheet();
  1548.     /* set toplevel fallback values */
  1549.     StyleAddSimpleRule(sheet, TAG_HTML, S_FONT_FAMILY, (long)str2list("helvetica", "charter"), S_FALLBACK - S_ANY);
  1550.     StyleAddSimpleRule(sheet, TAG_HTML, S_FONT_SIZE,  12, S_FALLBACK - S_ANY);
  1551.     StyleAddSimpleRule(sheet, TAG_HTML, S_FONT_WEIGHT,  FONT_WEIGHT_MEDIUM,         S_FALLBACK - S_ANY);
  1552.     StyleAddSimpleRule(sheet, TAG_HTML, S_FONT_STYLE,  0, S_FALLBACK - S_ANY);
  1553.     StyleAddSimpleRule(sheet, TAG_HTML, S_FONT_LEADING,  0, S_FALLBACK - S_ANY);
  1554.     StyleAddSimpleRule(sheet, TAG_HTML, S_COLOR,  (100 << 0), S_FALLBACK - S_ANY);  /* i.e. a dark blue */
  1555.     StyleAddSimpleRule(sheet, TAG_HTML, S_ALT_COLOR,  (100 << 0), S_FALLBACK - S_ANY);  /* i.e. a dark blue */
  1556.     StyleAddSimpleRule(sheet, TAG_HTML, S_ALT_BACKGROUND, (long)StyleGetBackground(NULL, "#AAA"), S_FALLBACK - S_ANY); /* i.e. transparent */
  1557.     
  1558.     StyleAddSimpleRule(sheet, TAG_HTML, S_TEXT_SPACING,  0,  S_FALLBACK - S_ANY);
  1559.     StyleAddSimpleRule(sheet, TAG_HTML, S_MARGIN_LEFT,   4, S_FALLBACK - S_ANY);
  1560.     StyleAddSimpleRule(sheet, TAG_HTML, S_MARGIN_RIGHT,   4, S_FALLBACK - S_ANY);
  1561.     StyleAddSimpleRule(sheet, TAG_HTML, S_MARGIN_TOP,   4, S_FALLBACK - S_ANY);
  1562.     StyleAddSimpleRule(sheet, TAG_HTML, S_ALIGN,   ALIGN_LEFT,     S_FALLBACK - S_ANY);
  1563.     /* set per-tag fallback values -- exception to the normal fallback values */
  1564.     StyleAddSimpleRule(sheet, TAG_H1, S_FONT_FAMILY,  (long)str2list("charter", "times"),  S_FALLBACK); 
  1565.     StyleAddSimpleRule(sheet, TAG_H1, S_FONT_SIZE,  24,  S_FALLBACK);
  1566.     StyleAddSimpleRule(sheet, TAG_H1, S_FONT_WEIGHT,  FONT_WEIGHT_BOLD, S_FALLBACK);
  1567.     StyleAddSimpleRule(sheet, TAG_H1, S_MARGIN_LEFT,   5,  S_FALLBACK);
  1568.     StyleAddSimpleRule(sheet, TAG_H2, S_FONT_FAMILY,  (long)str2list("charter", "times"),  S_FALLBACK); 
  1569.     StyleAddSimpleRule(sheet, TAG_H2, S_FONT_SIZE,  18,  S_FALLBACK);
  1570.     StyleAddSimpleRule(sheet, TAG_H2, S_FONT_WEIGHT,  FONT_WEIGHT_BOLD,  S_FALLBACK);
  1571.     StyleAddSimpleRule(sheet, TAG_H2, S_MARGIN_LEFT,   5,  S_FALLBACK);
  1572.     
  1573.     StyleAddSimpleRule(sheet, TAG_H3, S_FONT_FAMILY,  (long)str2list("times", "charter"),  S_FALLBACK); 
  1574.     StyleAddSimpleRule(sheet, TAG_H3, S_FONT_SIZE,  14,  S_FALLBACK);
  1575.     StyleAddSimpleRule(sheet, TAG_H2, S_FONT_WEIGHT,  FONT_WEIGHT_BOLD,  S_FALLBACK);
  1576.     StyleAddSimpleRule(sheet, TAG_H3, S_MARGIN_LEFT,  5,  S_FALLBACK);
  1577.     StyleAddSimpleRule(sheet, TAG_H4, S_FONT_FAMILY,  (long)str2list("charter","times"),  S_FALLBACK);
  1578.     StyleAddSimpleRule(sheet, TAG_H4, S_FONT_SIZE,  12,  S_FALLBACK);
  1579.     StyleAddSimpleRule(sheet, TAG_H4, S_FONT_WEIGHT,    FONT_WEIGHT_BOLD,  S_FALLBACK);
  1580.     StyleAddSimpleRule(sheet, TAG_H4, S_MARGIN_LEFT,  5,  S_FALLBACK);
  1581.     StyleAddSimpleRule(sheet, TAG_H5, S_FONT_FAMILY,  (long)str2list("charter","times"),  S_FALLBACK);
  1582.     StyleAddSimpleRule(sheet, TAG_H5, S_FONT_SIZE,  12,  S_FALLBACK);
  1583.     StyleAddSimpleRule(sheet, TAG_H5, S_FONT_WEIGHT,    FONT_WEIGHT_BOLD,  S_FALLBACK);
  1584.     StyleAddSimpleRule(sheet, TAG_H5, S_MARGIN_LEFT,  5,  S_FALLBACK);
  1585.     StyleAddSimpleRule(sheet, TAG_H6, S_FONT_FAMILY,  (long)str2list("charter","times"),  S_FALLBACK);
  1586.     StyleAddSimpleRule(sheet, TAG_H6, S_FONT_SIZE,  12,  S_FALLBACK);
  1587.     StyleAddSimpleRule(sheet, TAG_H6, S_FONT_WEIGHT,    FONT_WEIGHT_BOLD,  S_FALLBACK);
  1588.     StyleAddSimpleRule(sheet, TAG_H6, S_MARGIN_LEFT,  5,  S_FALLBACK);
  1589.     /*    StyleAddSimpleRule(sheet, TAG_LI, S_MARGIN_LEFT,  15,  S_FALLBACK);*/
  1590.     StyleAddSimpleRule(sheet, TAG_DL, S_MARGIN_LEFT,  15,   S_FALLBACK);
  1591.     StyleAddSimpleRule(sheet, TAG_UL, S_MARGIN_LEFT,  15,  S_FALLBACK);
  1592.     StyleAddSimpleRule(sheet, TAG_OL, S_MARGIN_LEFT,  15,  S_FALLBACK);
  1593.     StyleAddSimpleRule(sheet, TAG_DT, S_FONT_WEIGHT,  FONT_WEIGHT_BOLD,  S_FALLBACK);
  1594.     StyleAddSimpleRule(sheet, TAG_DD, S_FONT_WEIGHT,  FONT_WEIGHT_MEDIUM,  S_FALLBACK);
  1595.  
  1596.     StyleAddSimpleRule(sheet, TAG_ADDRESS,  S_ALIGN, ALIGN_RIGHT, S_FALLBACK);
  1597.     StyleAddSimpleRule(sheet, TAG_MATH,  S_FONT_SIZE,  14,   S_FALLBACK);
  1598.     StyleAddSimpleRule(sheet, TAG_SMALL,  S_FONT_SIZE,  8,  S_FALLBACK);
  1599.     StyleAddSimpleRule(sheet, TAG_SUB,  S_FONT_SIZE,  8,  S_FALLBACK);
  1600.     StyleAddSimpleRule(sheet, TAG_SUP,  S_FONT_SIZE,  8,  S_FALLBACK);
  1601.     StyleAddSimpleRule(sheet, TAG_STRONG,  S_FONT_WEIGHT, FONT_WEIGHT_BOLD, S_FALLBACK);
  1602.     StyleAddSimpleRule(sheet, TAG_BOLD,  S_FONT_WEIGHT,  FONT_WEIGHT_BOLD, S_FALLBACK);
  1603.     StyleAddSimpleRule(sheet, TAG_EM,  S_FONT_STYLE, FONT_STYLE_ITALIC, S_FALLBACK);
  1604.     StyleAddSimpleRule(sheet, TAG_ITALIC,  S_FONT_STYLE, FONT_STYLE_ITALIC, S_FALLBACK);
  1605.     StyleAddSimpleRule(sheet, TAG_PRE,  S_FONT_FAMILY, (long)str2list("lucidasanstypewriter", "courier"), S_FALLBACK);
  1606.     StyleAddSimpleRule(sheet, TAG_TT,  S_FONT_FAMILY, (long)str2list("lucidasanstypewriter", "courier"), S_FALLBACK);
  1607.     StyleAddSimpleRule(sheet, TAG_CODE,  S_FONT_FAMILY, (long)str2list("lucidasanstypewriter", "courier"), S_FALLBACK);
  1608.     /* set default style for TAG_ABSTRACT */
  1609.     StyleAddSimpleRule(sheet, TAG_ABSTRACT, S_FONT_STYLE,  FONT_STYLE_ITALIC, S_FALLBACK);
  1610.     StyleAddSimpleRule(sheet, TAG_ABSTRACT, S_FONT_WEIGHT,  FONT_WEIGHT_BOLD, S_FALLBACK);
  1611.     StyleAddSimpleRule(sheet, TAG_ABSTRACT, S_MARGIN_RIGHT,  40, S_FALLBACK);
  1612.     StyleAddSimpleRule(sheet, TAG_ABSTRACT, S_MARGIN_LEFT, 40,  S_FALLBACK);
  1613.     /* set default style for TAG_QUOTE */
  1614.     StyleAddSimpleRule(sheet, TAG_QUOTE, S_FONT_STYLE,  FONT_STYLE_ITALIC, S_FALLBACK);
  1615.     StyleAddSimpleRule(sheet, TAG_QUOTE, S_MARGIN_RIGHT,  30,  S_FALLBACK);
  1616.     StyleAddSimpleRule(sheet, TAG_QUOTE, S_MARGIN_LEFT,  50,  S_FALLBACK);
  1617.     /* set style for tables */
  1618.     StyleAddSimpleRule(sheet, TAG_TH,  S_FONT_WEIGHT,  FONT_WEIGHT_BOLD,  S_FALLBACK);
  1619. /*
  1620.     StyleAddSimpleRule(sheet, TAG_TH,  S_ALIGN,  ALIGN_CENTER,  S_FALLBACK);
  1621.     StyleAddSimpleRule(sheet, TAG_TD,  S_ALIGN,  ALIGN_CENTER,  S_FALLBACK);
  1622. */
  1623.     /* set style for HR */
  1624.     StyleAddSimpleRule(sheet, TAG_HR,  S_COLOR,  (255 << 24), S_FALLBACK);
  1625.     return sheet;
  1626. }
  1627. void StyleParse()
  1628. {
  1629.     if (STYLE_TRACE)
  1630. fprintf(stderr,"StyleParsen");
  1631.     if (!CurrentDoc->head_style && !CurrentDoc->link_style) {
  1632. CurrentDoc->style = NULL; /* i.e. style->default */
  1633. return;
  1634.     }
  1635.     if (CurrentDoc->user_style) {
  1636. /* this document contains the user's style sheet if it exists */
  1637. Announce("applying personal style sheet.. ");
  1638. /* rgbClear();*/
  1639. if (context->style) {
  1640.     FreeStyleSheet(context->style);
  1641.     context->style = StyleGetInit();
  1642. }
  1643. StyleChew(context->style, CurrentDoc->head_style, S_USER);
  1644. StyleChew(context->style, CurrentDoc->link_style, S_USER);
  1645. CurrentDoc->style = context->style;
  1646. if (STYLE_TRACE) {
  1647.     fprintf(stderr,"Stylesane: context->stylen");
  1648.     StyleSane(context->style);
  1649. }
  1650. return;
  1651.     }
  1652.     /* this is a normal incoming document with style sheet attached */
  1653.     Announce("applying document's style sheet.. ");
  1654.     rgbClear();
  1655.     CurrentDoc->style = StyleCopy(context->style);
  1656.     StyleChew(CurrentDoc->style, CurrentDoc->head_style, S_USER);
  1657.     StyleChew(CurrentDoc->style, CurrentDoc->link_style, S_USER);
  1658.     if (STYLE_TRACE) {
  1659. fprintf(stderr,"Stylesane: CurrentDoc->stylen");
  1660. StyleSane(context->style);
  1661.     }
  1662.     Announce("applying document's style sheet.. done");
  1663. }
  1664. /*
  1665. void StyleWindowChange()
  1666. {
  1667.     fprintf(stderr,"StyleWindowChange w %d h %dn", win_width, win_height);
  1668. }
  1669. */
  1670. /* StyleZoom is a bit too Arena-specific */
  1671. void StyleZoomChange(double f)
  1672. {
  1673.     Announce("loading fonts..");
  1674.     ShowBusy();
  1675.     lens_factor *= f;
  1676.     DisplaySizeChanged(1);
  1677.     Redraw(0,0,WinWidth,WinHeight + WinTop); 
  1678.     Announce("%s",CurrentDoc->url);
  1679.     HideBusy();
  1680. }
  1681. char *StyleLoad(char *href, int hreflen, BOOL reload)
  1682. {
  1683.     Doc *doc = NULL;
  1684.     /* check for null name */
  1685.     doc = GetInline(href, hreflen, reload);
  1686.     if (doc) {
  1687. /* fprintf(stderr,"StyleLoad succedded ??n");*/
  1688. return(doc->content_buffer);
  1689.     }
  1690.     return NULL;
  1691. }
  1692. /* 
  1693.   StyleGet is used by the UA to pull values out of a flattened stylesheet
  1694. */
  1695. long StyleGet(StyleProperty property)
  1696. {
  1697.     if (REGISTER_TRACE && VERBOSE_TRACE)
  1698. fprintf(stderr,"StyleGet: property %dn", property);
  1699.     if ((REGISTER_TRACE) && (current_flat->status[property] == S_UNSET))
  1700. fprintf(stderr, "StyleGet, property not set %dn", property);
  1701.     switch (property) {
  1702.        case S_SMALL_CAPS_FONT: /* this one is expensive and not often used */
  1703. if (current_flat->status[S_SMALL_CAPS_FONT] != S_INFERRED) {
  1704.     current_flat->value[S_SMALL_CAPS_FONT] = (void *)
  1705. GetFont((HTList *)current_flat->value[S_FONT_FAMILY], 
  1706. (int)current_flat->value[S_FONT_SIZE] * 4 / 5,
  1707. (int)current_flat->value[S_FONT_WEIGHT], 
  1708. (int)current_flat->value[S_FONT_STYLE], True);
  1709.     current_flat->status[S_FONT] = S_INFERRED;
  1710.     current_flat->weight[S_SMALL_CAPS_FONT] = current_flat->weight[S_FONT];
  1711. }
  1712. return(current_flat->value[S_SMALL_CAPS_FONT]);
  1713. break;
  1714.       default:
  1715. return (current_flat->value[property]);
  1716.     }
  1717.     return 0;
  1718. }
  1719. void StyleClearDoc()
  1720. {
  1721.     HTList *l = style_stack;
  1722.     StyleStackElement *sel;
  1723.     while ( (sel = (StyleStackElement *) HTList_nextObject(l) )) {
  1724. Free(sel->flat);
  1725.     }
  1726.     HTList_destroy(style_stack);
  1727.     style_stack = NULL;
  1728.     current_flat = NULL;
  1729. }
  1730. /* formatting functions, here starts what should become format.c */
  1731. StyleStackElement *NewStackElement()
  1732. {
  1733.     return (StyleStackElement *)calloc(1,sizeof(StyleStackElement));
  1734. }
  1735. /* 
  1736.   FormatElementStart is called when a new element (implied or not) is
  1737.   started. It will call StyleEval to flatten a set of properties (called
  1738.   a stack element) to be returned by StyleGet. The stack element is then 
  1739.   pushed onto the stack.
  1740. */
  1741. extern void Push(void *);
  1742. extern void *Pop();
  1743. void FormatElementStart(int element, char *class, int class_len)
  1744. {
  1745.     Frame *new_frame, *old_frame;
  1746.     
  1747.     StyleStackElement *stack_el = NewStackElement();
  1748.     StyleSheet *sheet = (CurrentDoc->style ? CurrentDoc->style : context->style);
  1749.     if ((element < 0) || (element >= TAG_LAST)) {
  1750.       fprintf(stderr,"FormatElementStart: element = %dn",element);
  1751.       element = TAG_P; /* ugly */
  1752.     }
  1753.     current_sheet = sheet;
  1754.     if (REGISTER_TRACE)
  1755. fprintf(stderr,"nFormatElementStart: %dn",element);
  1756.     if (!style_stack)
  1757. style_stack = HTList_new();
  1758.     stack_el->unit.element = element;
  1759.     if (class)
  1760. stack_el->unit.class = strndup(class, class_len);
  1761.     stack_el->flat = StyleEval(sheet, &stack_el->unit, style_stack);
  1762.     if (REGISTER_TRACE) {
  1763. StyleProperty i;
  1764. for (i=S_UNKNOWN; i<S_NPROPERTY; i++) 
  1765.     switch (i) {
  1766.       case S_FONT_FAMILY:
  1767. {
  1768.     char *fn;
  1769.     HTList *l = (HTList *)stack_el->flat->value[i];
  1770.     fprintf(stderr,"(%d ",i);
  1771.     while ((fn = (char *)HTList_nextObject(l))) {
  1772. fprintf(stderr,"%s ",fn);
  1773.     }
  1774.     fprintf(stderr,")");
  1775. }
  1776. break;
  1777.       default:
  1778. fprintf(stderr,"(%d %ld)",i, stack_el->flat->value[i]);
  1779.     }
  1780. fprintf(stderr,"n");
  1781.     }
  1782.     HTList_addObject(style_stack, (void *)stack_el); 
  1783.     current_flat = stack_el->flat;
  1784.     StyleSetFlag(S_MARGIN_TOP_FLAG, (int)StyleGet(S_MARGIN_TOP));
  1785.     if(element == TAG_P)
  1786.     { 
  1787. StyleSetFlag(S_INDENT_FLAG, (int)StyleGet(S_INDENT));
  1788. StyleSetFlag(S_LEADING_FLAG, TRUE);
  1789.     };
  1790.     if(element == TAG_HTML || element == TAG_HTML_SOURCE || 
  1791. (/*element != TAG_TABLE && */
  1792.  element != TAG_ABSTRACT &&
  1793.  element != TAG_BLOCKQUOTE && element != TAG_CAPTION &&
  1794.  element != TAG_NOTE && element != TAG_PRE &&
  1795.  element != TAG_QUOTE))  
  1796. return;
  1797.     if(prepass||damn_table)
  1798. return;
  1799.     old_frame = (Frame *)Pop();
  1800.     Push(old_frame);
  1801.     if(paintStartLine>0)
  1802. Push((Frame *)1);
  1803.     else
  1804.     {
  1805. new_frame = (Frame *)calloc(1, sizeof(Frame));
  1806. PixOffset += StyleGet(S_PADDING)+ StyleGet(S_MARGIN_TOP); /* must be S_PADDING_TOP */
  1807. new_frame->offset = PixOffset;
  1808. new_frame->leftmargin = StyleGet(S_PADDING);
  1809. new_frame->rightmargin = StyleGet(S_PADDING);
  1810. new_frame->indent = old_frame->indent + StyleGet(S_MARGIN_LEFT);
  1811. new_frame->width = old_frame->width - StyleGet(S_MARGIN_LEFT) - StyleGet(S_MARGIN_RIGHT);
  1812. new_frame->style = 0;
  1813. new_frame->border = 0;
  1814. #ifdef STYLE_COLOR_BORDER
  1815. new_frame->cb_ix = 0;
  1816. #else
  1817. new_frame->cb_ix = 0;
  1818. #endif
  1819. new_frame->flow = old_frame->flow; /* StyleGet(S_ALIGN) */
  1820. new_frame->next = new_frame->child = NULL;
  1821. new_frame->box_list = NULL;
  1822. PrintBeginFrame(new_frame);
  1823. Push(new_frame);
  1824.     }
  1825. #if 0
  1826.     new_frame->offset = PixOffset;
  1827.     new_frame->indent = (old_frame ?  old_frame->leftmargin + StyleGet(S_MARGIN_LEFT) : StyleGet(S_MARGIN_LEFT));
  1828.     new_frame->width = (old_frame ?  old_frame->width - StyleGet(S_MARGIN_LEFT) - StyleGet(S_MARGIN_RIGHT) : 12);
  1829.     new_frame->style = 0;
  1830.     new_frame->border = 0;
  1831. #ifdef STYLE_COLOR_BORDER
  1832.     new_frame->cb_ix = 0;
  1833. #else
  1834.     new_frame->cb_ix = 0;
  1835. #endif
  1836.     new_frame->flow = ALIGN_CENTER;
  1837.     new_frame->next = new_frame->child = NULL;
  1838.     new_frame->box_list = NULL;
  1839.     new_frame->leftcount = old_frame->leftcount;
  1840.     new_frame->pushcount = old_frame->pushcount;
  1841.     new_frame->oldmargin = old_frame->oldmargin;
  1842.     PrintBeginFrame(new_frame);
  1843.     Push(new_frame);
  1844. #endif
  1845. }
  1846. /*
  1847.   FormatElementEnd pops a set of flattened style properties from the
  1848.   stack. Note that calls to FormatElementStart and FormatElementEnd must
  1849.   always match each other. I.e. your SGML/HTML parser must add any
  1850.   implied/omitted tags.
  1851. */
  1852. void FormatElementEnd()
  1853. {
  1854.     Frame *old_frame;
  1855.     int element;
  1856.     StyleStackElement *stack_el = (StyleStackElement *) HTList_removeLastObject(style_stack);
  1857.     element = stack_el->unit.element;
  1858.     if (REGISTER_TRACE) 
  1859. fprintf(stderr,"FormatElementEnd:   %d, %d elements leftn", stack_el->unit.element, HTList_count(style_stack));
  1860.     
  1861.     Free(stack_el->flat);
  1862.     Free(stack_el->unit.class);
  1863.     Free(stack_el);
  1864.     stack_el = (StyleStackElement *) HTList_lastObject (style_stack);
  1865.     if (!stack_el) {
  1866. if (REGISTER_TRACE)
  1867.     fprintf(stderr,"stack empty!! n");
  1868. HTList_destroy(style_stack);
  1869. style_stack = NULL;
  1870. current_flat = NULL;
  1871.     } else {
  1872. current_flat = stack_el->flat;
  1873.     }
  1874.     if(element == TAG_HTML || element == TAG_HTML_SOURCE || 
  1875. (/*element != TAG_TABLE && */
  1876.         element != TAG_ABSTRACT &&
  1877. element != TAG_BLOCKQUOTE && element != TAG_CAPTION &&
  1878. element != TAG_NOTE && element != TAG_PRE &&
  1879. element != TAG_QUOTE))
  1880. return;
  1881.     if(prepass||damn_table) 
  1882. return;
  1883.     old_frame = (Frame *)Pop();
  1884.     if(old_frame)
  1885.     {
  1886. Frame *parent_frame;
  1887. char *p;
  1888. #define PushValue(p, value) ui_n = (unsigned int)value; *p++ = ui_n & 0xFF; *p++ = (ui_n >> 8) & 0xFF
  1889. if(old_frame != (Frame *)1)
  1890. {
  1891.     parent_frame = (Frame *)Pop();
  1892.     if(parent_frame)
  1893. Push(parent_frame);
  1894.     old_frame->length = paintlen - old_frame->info - FRAMESTLEN;
  1895.     old_frame->height = PixOffset - old_frame->offset + 2*StyleGet(S_PADDING);;
  1896.     old_frame->offset -= StyleGet(S_PADDING);
  1897.     PixOffset += StyleGet(S_PADDING);
  1898.     p = paint + old_frame->info + 9;
  1899.     PushValue(p, old_frame->height & 0xFFFF);
  1900.     PushValue(p, (old_frame->height >> 16) & 0xFFFF);
  1901.     PrintFrameLength(old_frame);
  1902.     if(parent_frame == (Frame *)1)  
  1903. PrintEndFrame(NULL, old_frame);
  1904.     else
  1905. PrintEndFrame(parent_frame, old_frame);
  1906.     FreeFrames(old_frame); 
  1907. };
  1908.     }; 
  1909. }