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