1 #ifndef __CSS_HH__
2 #define __CSS_HH__
3 
4 #include "dw/core.hh"
5 #include "doctree.hh"
6 
7 /* Origin and weight. Used only internally.*/
8 typedef enum {
9    CSS_PRIMARY_USER_AGENT,
10    CSS_PRIMARY_USER,
11    CSS_PRIMARY_AUTHOR,
12    CSS_PRIMARY_AUTHOR_IMPORTANT,
13    CSS_PRIMARY_USER_IMPORTANT,
14    CSS_PRIMARY_LAST,
15 } CssPrimaryOrder;
16 
17 typedef enum {
18    CSS_ORIGIN_USER_AGENT,
19    CSS_ORIGIN_USER,
20    CSS_ORIGIN_AUTHOR,
21 } CssOrigin;
22 
23 typedef enum {
24    CSS_TYPE_INTEGER,            /* This type is only used internally, for x-*
25                                    properties. */
26    CSS_TYPE_ENUM,               /* Value is i, if represented by
27                                    enum_symbols[i]. */
28    CSS_TYPE_MULTI_ENUM,         /* For all enum_symbols[i], 1 << i are
29                                    combined. */
30    CSS_TYPE_LENGTH_PERCENTAGE,  /* <length> or <percentage>. Represented by
31                                    CssLength. */
32    CSS_TYPE_LENGTH,             /* <length>, represented as CssLength.
33                                    Note: In some cases, CSS_TYPE_LENGTH is used
34                                    instead of CSS_TYPE_LENGTH_PERCENTAGE,
35                                    only because Dw cannot handle percentages
36                                    in this particular case (e.g.
37                                    'margin-*-width'). */
38    CSS_TYPE_SIGNED_LENGTH,      /* As CSS_TYPE_LENGTH but may be negative. */
39    CSS_TYPE_LENGTH_PERCENTAGE_NUMBER,  /* <length> or <percentage>, or <number> */
40    CSS_TYPE_AUTO,               /* Represented as CssLength of type
41                                    CSS_LENGTH_TYPE_AUTO */
42    CSS_TYPE_COLOR,              /* Represented as integer. */
43    CSS_TYPE_FONT_WEIGHT,        /* this very special and only used by
44                                    'font-weight' */
45    CSS_TYPE_STRING,             /* <string> */
46    CSS_TYPE_SYMBOL,             /* Symbols, which are directly copied (as
47                                    opposed to CSS_TYPE_ENUM and
48                                    CSS_TYPE_MULTI_ENUM). Used for
49                                    'font-family'. */
50    CSS_TYPE_URI,                /* <uri> */
51    CSS_TYPE_BACKGROUND_POSITION,
52    CSS_TYPE_UNUSED              /* Not yet used. Will itself get unused some
53                                    day. */
54 } CssValueType;
55 
56 /*
57  * Lengths are represented as int in the following way:
58  *
59  *    | <------   integer value   ------> |
60  *
61  *    +---+ - - - +---+---+- - - - - -+---+---+---+---+
62  *    |          integer part             |   type    |
63  *    +---+ - - - +---+---+- - - - - -+---+---+---+---+
64  *    | integer part  | decimal fraction  |   type    |
65  *    +---+ - - - +---+---+- - - - - -+---+---+---+---+
66  *     n-1          15  14              3   2  1   0
67  *
68  *    | <------ fixed point value ------> |
69  *
70  * where type is one of the CSS_LENGTH_TYPE_* values.
71  * CSS_LENGTH_TYPE_PX values are stored as
72  * 29 bit signed integer, all other types as fixed point values.
73  */
74 
75 typedef int CssLength;
76 
77 typedef enum {
78    CSS_LENGTH_TYPE_NONE,
79    CSS_LENGTH_TYPE_PX,
80    CSS_LENGTH_TYPE_MM,         /* "cm", "in", "pt" and "pc" are converted into
81                                   millimeters. */
82    CSS_LENGTH_TYPE_EM,
83    CSS_LENGTH_TYPE_EX,
84    CSS_LENGTH_TYPE_PERCENTAGE,
85    CSS_LENGTH_TYPE_RELATIVE,   /* This does not exist in CSS but
86                                   is used in HTML */
87    CSS_LENGTH_TYPE_AUTO        /* This can be used as a simple value. */
88 } CssLengthType;
89 
CSS_CREATE_LENGTH(float v,CssLengthType t)90 inline CssLength CSS_CREATE_LENGTH (float v, CssLengthType t) {
91    static const int CSS_LENGTH_FRAC_MAX = (1 << (32 - 15 - 1)) - 1;
92    static const int CSS_LENGTH_INT_MAX = (1 << (32 - 4)) - 1;
93    int iv;
94 
95    switch (t) {
96    case CSS_LENGTH_TYPE_PX:
97       iv = lout::misc::roundInt(v);
98       if (iv > CSS_LENGTH_INT_MAX)
99          iv = CSS_LENGTH_INT_MAX;
100       else if (iv < -CSS_LENGTH_INT_MAX)
101          iv = -CSS_LENGTH_INT_MAX;
102       return iv << 3 | t;
103    case CSS_LENGTH_TYPE_NONE:
104    case CSS_LENGTH_TYPE_MM:
105    case CSS_LENGTH_TYPE_EM:
106    case CSS_LENGTH_TYPE_EX:
107    case CSS_LENGTH_TYPE_PERCENTAGE:
108    case CSS_LENGTH_TYPE_RELATIVE:
109       if (v > CSS_LENGTH_FRAC_MAX)
110          v = CSS_LENGTH_FRAC_MAX;
111       else if (v < -CSS_LENGTH_FRAC_MAX)
112          v = -CSS_LENGTH_FRAC_MAX;
113       return ((int) (v * (1 << 15)) & ~7 ) | t;
114    case CSS_LENGTH_TYPE_AUTO:
115       return t;
116    default:
117       assert(false);
118       return CSS_LENGTH_TYPE_AUTO;
119    }
120 }
121 
CSS_LENGTH_TYPE(CssLength l)122 inline CssLengthType CSS_LENGTH_TYPE (CssLength l) {
123    return (CssLengthType) (l & 7);
124 }
125 
CSS_LENGTH_VALUE(CssLength l)126 inline float CSS_LENGTH_VALUE (CssLength l) {
127    switch (CSS_LENGTH_TYPE(l)) {
128    case CSS_LENGTH_TYPE_PX:
129       return (float) (l >> 3);
130    case CSS_LENGTH_TYPE_NONE:
131    case CSS_LENGTH_TYPE_MM:
132    case CSS_LENGTH_TYPE_EM:
133    case CSS_LENGTH_TYPE_EX:
134    case CSS_LENGTH_TYPE_PERCENTAGE:
135    case CSS_LENGTH_TYPE_RELATIVE:
136       return  ((float)(l & ~7)) / (1 << 15);
137    case CSS_LENGTH_TYPE_AUTO:
138       return 0.0;
139    default:
140       assert(false);
141       return 0.0;
142    }
143 }
144 
145 typedef enum {
146    CSS_PROPERTY_END = -1, // used as terminator in CssShorthandInfo
147    CSS_PROPERTY_BACKGROUND_ATTACHMENT,
148    CSS_PROPERTY_BACKGROUND_COLOR,
149    CSS_PROPERTY_BACKGROUND_IMAGE,
150    CSS_PROPERTY_BACKGROUND_POSITION,
151    CSS_PROPERTY_BACKGROUND_REPEAT,
152    CSS_PROPERTY_BORDER_BOTTOM_COLOR,
153    CSS_PROPERTY_BORDER_BOTTOM_STYLE,
154    CSS_PROPERTY_BORDER_BOTTOM_WIDTH,
155    CSS_PROPERTY_BORDER_COLLAPSE,
156    CSS_PROPERTY_BORDER_LEFT_COLOR,
157    CSS_PROPERTY_BORDER_LEFT_STYLE,
158    CSS_PROPERTY_BORDER_LEFT_WIDTH,
159    CSS_PROPERTY_BORDER_RIGHT_COLOR,
160    CSS_PROPERTY_BORDER_RIGHT_STYLE,
161    CSS_PROPERTY_BORDER_RIGHT_WIDTH,
162    CSS_PROPERTY_BORDER_SPACING,
163    CSS_PROPERTY_BORDER_TOP_COLOR,
164    CSS_PROPERTY_BORDER_TOP_STYLE,
165    CSS_PROPERTY_BORDER_TOP_WIDTH,
166    CSS_PROPERTY_BOTTOM,
167    CSS_PROPERTY_CAPTION_SIDE,
168    CSS_PROPERTY_CLEAR,
169    CSS_PROPERTY_CLIP,
170    CSS_PROPERTY_COLOR,
171    CSS_PROPERTY_CONTENT,
172    CSS_PROPERTY_COUNTER_INCREMENT,
173    CSS_PROPERTY_COUNTER_RESET,
174    CSS_PROPERTY_CURSOR,
175    CSS_PROPERTY_DIRECTION,
176    CSS_PROPERTY_DISPLAY,
177    CSS_PROPERTY_EMPTY_CELLS,
178    CSS_PROPERTY_FLOAT,
179    CSS_PROPERTY_FONT_FAMILY,
180    CSS_PROPERTY_FONT_SIZE,
181    CSS_PROPERTY_FONT_SIZE_ADJUST,
182    CSS_PROPERTY_FONT_STRETCH,
183    CSS_PROPERTY_FONT_STYLE,
184    CSS_PROPERTY_FONT_VARIANT,
185    CSS_PROPERTY_FONT_WEIGHT,
186    CSS_PROPERTY_HEIGHT,
187    CSS_PROPERTY_LEFT,
188    CSS_PROPERTY_LETTER_SPACING,
189    CSS_PROPERTY_LINE_HEIGHT,
190    CSS_PROPERTY_LIST_STYLE_IMAGE,
191    CSS_PROPERTY_LIST_STYLE_POSITION,
192    CSS_PROPERTY_LIST_STYLE_TYPE,
193    CSS_PROPERTY_MARGIN_BOTTOM,
194    CSS_PROPERTY_MARGIN_LEFT,
195    CSS_PROPERTY_MARGIN_RIGHT,
196    CSS_PROPERTY_MARGIN_TOP,
197    CSS_PROPERTY_MARKER_OFFSET,
198    CSS_PROPERTY_MARKS,
199    CSS_PROPERTY_MAX_HEIGHT,
200    CSS_PROPERTY_MAX_WIDTH,
201    CSS_PROPERTY_MIN_HEIGHT,
202    CSS_PROPERTY_MIN_WIDTH,
203    CSS_PROPERTY_OUTLINE_COLOR,
204    CSS_PROPERTY_OUTLINE_STYLE,
205    CSS_PROPERTY_OUTLINE_WIDTH,
206    CSS_PROPERTY_OVERFLOW,
207    CSS_PROPERTY_PADDING_BOTTOM,
208    CSS_PROPERTY_PADDING_LEFT,
209    CSS_PROPERTY_PADDING_RIGHT,
210    CSS_PROPERTY_PADDING_TOP,
211    CSS_PROPERTY_POSITION,
212    CSS_PROPERTY_QUOTES,
213    CSS_PROPERTY_RIGHT,
214    CSS_PROPERTY_TEXT_ALIGN,
215    CSS_PROPERTY_TEXT_DECORATION,
216    CSS_PROPERTY_TEXT_INDENT,
217    CSS_PROPERTY_TEXT_SHADOW,
218    CSS_PROPERTY_TEXT_TRANSFORM,
219    CSS_PROPERTY_TOP,
220    CSS_PROPERTY_UNICODE_BIDI,
221    CSS_PROPERTY_VERTICAL_ALIGN,
222    CSS_PROPERTY_VISIBILITY,
223    CSS_PROPERTY_WHITE_SPACE,
224    CSS_PROPERTY_WIDTH,
225    CSS_PROPERTY_WORD_SPACING,
226    CSS_PROPERTY_Z_INDEX,
227    CSS_PROPERTY_X_LINK,
228    CSS_PROPERTY_X_COLSPAN,
229    CSS_PROPERTY_X_ROWSPAN,
230    PROPERTY_X_LINK,
231    PROPERTY_X_LANG,
232    PROPERTY_X_IMG,
233    PROPERTY_X_TOOLTIP,
234    CSS_PROPERTY_LAST
235 } CssPropertyName;
236 
237 typedef struct {
238    int32_t posX;
239    int32_t posY;
240 } CssBackgroundPosition;
241 
242 typedef union {
243    int32_t intVal;
244    char *strVal;
245    CssBackgroundPosition *posVal;
246 } CssPropertyValue;
247 
248 typedef enum {
249    CSS_BORDER_WIDTH_THIN,
250    CSS_BORDER_WIDTH_MEDIUM,
251    CSS_BORDER_WIDTH_THICK,
252 } CssBorderWidthExtensions;
253 
254 typedef enum {
255    CSS_FONT_WEIGHT_BOLD,
256    CSS_FONT_WEIGHT_BOLDER,
257    CSS_FONT_WEIGHT_LIGHT,
258    CSS_FONT_WEIGHT_LIGHTER,
259    CSS_FONT_WEIGHT_NORMAL,
260 } CssFontWeightExtensions;
261 
262 typedef enum {
263    CSS_FONT_SIZE_LARGE,
264    CSS_FONT_SIZE_LARGER,
265    CSS_FONT_SIZE_MEDIUM,
266    CSS_FONT_SIZE_SMALL,
267    CSS_FONT_SIZE_SMALLER,
268    CSS_FONT_SIZE_XX_LARGE,
269    CSS_FONT_SIZE_XX_SMALL,
270    CSS_FONT_SIZE_X_LARGE,
271    CSS_FONT_SIZE_X_SMALL,
272 } CssFontSizeExtensions;
273 
274 typedef enum {
275    CSS_LETTER_SPACING_NORMAL
276 } CssLetterSpacingExtensions;
277 
278 typedef enum {
279    CSS_WORD_SPACING_NORMAL
280 } CssWordSpacingExtensions;
281 
282 
283 /**
284  * \brief This class holds a CSS property and value pair.
285  */
286 class CssProperty {
287    public:
288 
289       short name;
290       short type;
291       CssPropertyValue value;
292 
free()293       inline void free () {
294          switch (type) {
295             case CSS_TYPE_STRING:
296             case CSS_TYPE_SYMBOL:
297             case CSS_TYPE_URI:
298                dFree (value.strVal);
299                break;
300             case CSS_TYPE_BACKGROUND_POSITION:
301                dFree (value.posVal);
302             default:
303                break;
304          }
305       }
306       void print ();
307 };
308 
309 /**
310  * \brief A list of CssProperty objects.
311  */
312 class CssPropertyList : public lout::misc::SimpleVector <CssProperty> {
313    int refCount;
314    bool ownerOfStrings;
315    bool safe;
316 
317    public:
CssPropertyList(bool ownerOfStrings=false)318       inline CssPropertyList(bool ownerOfStrings = false) :
319                   lout::misc::SimpleVector <CssProperty> (1) {
320          refCount = 0;
321          safe = true;
322          this->ownerOfStrings = ownerOfStrings;
323       };
324       CssPropertyList(const CssPropertyList &p, bool deep = false);
325       ~CssPropertyList ();
326 
327       void set (CssPropertyName name, CssValueType type,
328                 CssPropertyValue value);
329       void apply (CssPropertyList *props);
isSafe()330       bool isSafe () { return safe; };
331       void print ();
ref()332       inline void ref () { refCount++; }
unref()333       inline void unref () { if (--refCount == 0) delete this; }
334 };
335 
336 class CssSimpleSelector {
337    private:
338       int element;
339       char *pseudo, *id;
340       lout::misc::SimpleVector <char *> klass;
341 
342    public:
343       enum {
344          ELEMENT_NONE = -1,
345          ELEMENT_ANY = -2,
346       };
347 
348       typedef enum {
349          SELECT_NONE,
350          SELECT_CLASS,
351          SELECT_PSEUDO_CLASS,
352          SELECT_ID,
353       } SelectType;
354 
355       CssSimpleSelector ();
356       ~CssSimpleSelector ();
setElement(int e)357       inline void setElement (int e) { element = e; };
358       void setSelect (SelectType t, const char *v);
getClass()359       inline lout::misc::SimpleVector <char *> *getClass () { return &klass; };
getPseudoClass()360       inline const char *getPseudoClass () { return pseudo; };
getId()361       inline const char *getId () { return id; };
getElement()362       inline int getElement () { return element; };
363       bool match (const DoctreeNode *node);
364       int specificity ();
365       void print ();
366 };
367 
368 class MatchCache : public lout::misc::SimpleVector <int> {
369    public:
MatchCache()370       MatchCache() : lout::misc::SimpleVector <int> (0) {};
371 };
372 
373 /**
374  * \brief CSS selector class.
375  *
376  * \todo Implement missing selector options.
377  */
378 class CssSelector {
379    public:
380       typedef enum {
381          COMB_NONE,
382          COMB_DESCENDANT,
383          COMB_CHILD,
384          COMB_ADJACENT_SIBLING,
385       } Combinator;
386 
387    private:
388       struct CombinatorAndSelector {
389          Combinator combinator;
390          CssSimpleSelector *selector;
391       };
392 
393       int refCount, matchCacheOffset;
394       lout::misc::SimpleVector <struct CombinatorAndSelector> selectorList;
395 
396       bool match (Doctree *dt, const DoctreeNode *node, int i, Combinator comb,
397                   MatchCache *matchCache);
398 
399    public:
400       CssSelector ();
401       ~CssSelector ();
402       void addSimpleSelector (Combinator c);
top()403       inline CssSimpleSelector *top () {
404          return selectorList.getRef (selectorList.size () - 1)->selector;
405       }
size()406       inline int size () { return selectorList.size (); };
match(Doctree * dt,const DoctreeNode * node,MatchCache * matchCache)407       inline bool match (Doctree *dt, const DoctreeNode *node,
408                          MatchCache *matchCache) {
409          return match (dt, node, selectorList.size () - 1, COMB_NONE,
410                        matchCache);
411       }
setMatchCacheOffset(int mo)412       inline void setMatchCacheOffset (int mo) {
413          if (matchCacheOffset == -1)
414             matchCacheOffset = mo;
415       }
getRequiredMatchCache()416       inline int getRequiredMatchCache () {
417          return matchCacheOffset + size ();
418       }
419       int specificity ();
420       bool checksPseudoClass ();
421       void print ();
ref()422       inline void ref () { refCount++; }
unref()423       inline void unref () { if (--refCount == 0) delete this; }
424 };
425 
426 /**
427  * \brief A CssSelector CssPropertyList pair.
428  *
429  *  The CssPropertyList is applied if the CssSelector matches.
430  */
431 class CssRule {
432    private:
433       CssPropertyList *props;
434       int spec, pos;
435 
436    public:
437       CssSelector *selector;
438 
439       CssRule (CssSelector *selector, CssPropertyList *props, int pos);
440       ~CssRule ();
441 
442       void apply (CssPropertyList *props, Doctree *docTree,
443                   const DoctreeNode *node, MatchCache *matchCache) const;
isSafe()444       inline bool isSafe () {
445          return !selector->checksPseudoClass () || props->isSafe ();
446       };
specificity()447       inline int specificity () { return spec; };
position()448       inline int position () { return pos; };
449       void print ();
450 };
451 
452 /**
453  * \brief A list of CssRules.
454  *
455  * In apply () all matching rules are applied.
456  */
457 class CssStyleSheet {
458    private:
459       class RuleList : public lout::misc::SimpleVector <CssRule*>,
460                        public lout::object::Object {
461          public:
RuleList()462             RuleList () : lout::misc::SimpleVector <CssRule*> (1) {};
~RuleList()463             ~RuleList () {
464                for (int i = 0; i < size (); i++)
465                   delete get (i);
466             };
467 
468             void insert (CssRule *rule);
equals(lout::object::Object * other)469             inline bool equals (lout::object::Object *other) {
470                return this == other;
471             };
hashValue()472             inline int hashValue () { return (intptr_t) this; };
473       };
474 
475       class RuleMap : public lout::container::typed::HashTable
476                              <lout::object::ConstString, RuleList > {
477          public:
RuleMap()478             RuleMap () : lout::container::typed::HashTable
479                <lout::object::ConstString, RuleList > (true, true, 256) {};
480       };
481 
482       static const int ntags = 90 + 14; // \todo don't hardcode
483       /* 90 is the full number of html4 elements, including those which we have
484        * implemented. From html5, let's add: article, header, footer, mark,
485        * nav, section, aside, figure, figcaption, wbr, audio, video, source,
486        * embed.
487        */
488 
489       RuleList elementTable[ntags], anyTable;
490       RuleMap idTable, classTable;
491       int requiredMatchCache;
492 
493    public:
CssStyleSheet()494       CssStyleSheet () { requiredMatchCache = 0; }
495       void addRule (CssRule *rule);
496       void apply (CssPropertyList *props, Doctree *docTree,
497                   const DoctreeNode *node, MatchCache *matchCache) const;
getRequiredMatchCache()498       int getRequiredMatchCache () { return requiredMatchCache; }
499 };
500 
501 /**
502  * \brief A set of CssStyleSheets.
503  */
504 class CssContext {
505    private:
506       static CssStyleSheet userAgentSheet;
507       CssStyleSheet sheet[CSS_PRIMARY_USER_IMPORTANT + 1];
508       MatchCache matchCache;
509       int pos;
510 
511    public:
512       CssContext ();
513 
514       void addRule (CssSelector *sel, CssPropertyList *props,
515                     CssPrimaryOrder order);
516       void apply (CssPropertyList *props,
517          Doctree *docTree, DoctreeNode *node,
518          CssPropertyList *tagStyle, CssPropertyList *tagStyleImportant,
519          CssPropertyList *nonCssHints);
520 };
521 
522 #endif
523