Dillo v3.1.1-46-g8a360e32
Loading...
Searching...
No Matches
css.cc
Go to the documentation of this file.
1/*
2 * File: css.cc
3 *
4 * Copyright 2008-2014 Johannes Hofmann <Johannes.Hofmann@gmx.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <stdio.h>
13#include "../dlib/dlib.h"
14#include "msg.h"
15#include "html_common.hh"
16#include "css.hh"
17
18using namespace dw::core::style;
19
21 fprintf (stderr, "%s - %d\n",
23 (int)value.intVal);
24}
25
27 lout::misc::SimpleVector <CssProperty> (p)
28{
29 refCount = 0;
30 safe = p.safe;
31 if (deep) {
32 for (int i = 0; i < size (); i++) {
33 CssProperty *p = getRef(i);
34 switch (p->type) {
35 case CSS_TYPE_STRING:
36 case CSS_TYPE_SYMBOL:
38 break;
39 default:
40 break;
41 }
42 }
43 ownerOfStrings = true;
44 } else {
45 ownerOfStrings = false;
46 }
47}
48
51 for (int i = 0; i < size (); i++)
52 getRef (i)->free ();
53}
54
59 CssPropertyValue value) {
60 CssProperty *prop;
61
63 safe = false;
64
65 for (int i = 0; i < size (); i++) {
66 prop = getRef (i);
67
68 if (prop->name == name) {
70 prop->free ();
71 prop->type = type;
72 prop->value = value;
73 return;
74 }
75 }
76
77 increase ();
78 prop = getRef (size () - 1);
79 prop->name = name;
80 prop->type = type;
81 prop->value = value;
82}
83
88 for (int i = 0; i < size (); i++) {
89 CssPropertyValue value = getRef (i)->value;
90
91 if (props->ownerOfStrings &&
92 (getRef (i)->type == CSS_TYPE_STRING ||
93 getRef (i)->type == CSS_TYPE_SYMBOL))
94 value.strVal = dStrdup(value.strVal);
95
96 props->set ((CssPropertyName) getRef (i)->name,
97 (CssValueType) getRef (i)->type,
98 value);
99 }
100}
101
103 for (int i = 0; i < size (); i++)
104 getRef (i)->print ();
105}
106
108 struct CombinatorAndSelector *cs;
109
110 refCount = 0;
111 matchCacheOffset = -1;
112 selectorList.increase ();
113 cs = selectorList.getRef (selectorList.size () - 1);
114
115 cs->combinator = COMB_NONE;
116 cs->selector = new CssSimpleSelector ();
117}
118
120 for (int i = selectorList.size () - 1; i >= 0; i--)
121 delete selectorList.getRef (i)->selector;
122}
123
127bool CssSelector::match (Doctree *docTree, const DoctreeNode *node,
128 int i, Combinator comb, MatchCache *matchCache) {
129 int *matchCacheEntry;
130 assert (node);
131
132 if (i < 0)
133 return true;
134
135 struct CombinatorAndSelector *cs = selectorList.getRef (i);
136 CssSimpleSelector *sel = cs->selector;
137
138 switch (comb) {
139 case COMB_NONE:
140 break;
141 case COMB_CHILD:
142 node = docTree->parent (node);
143 break;
145 node = docTree->sibling (node);
146 break;
147 case COMB_DESCENDANT:
148 node = docTree->parent (node);
149 matchCacheEntry = matchCache->getRef(matchCacheOffset + i);
150
151 for (const DoctreeNode *n = node;
152 n && n->num > *matchCacheEntry; n = docTree->parent (n))
153 if (sel->match (n) &&
154 match (docTree, n, i - 1, cs->combinator, matchCache))
155 return true;
156
157 if (node) // remember that it didn't match to avoid future tests
158 *matchCacheEntry = node->num;
159
160 return false;
161 break;
162 default:
163 return false; // \todo implement other combinators
164 }
165
166 if (!node || !sel->match (node))
167 return false;
168
169 // tail recursion should be optimized by the compiler
170 return match (docTree, node, i - 1, cs->combinator, matchCache);
171}
172
174 struct CombinatorAndSelector *cs;
175
176 assert (matchCacheOffset == -1);
177 selectorList.increase ();
178 cs = selectorList.getRef (selectorList.size () - 1);
179
180 cs->combinator = c;
181 cs->selector = new CssSimpleSelector ();
182}
183
185 for (int i = 0; i < selectorList.size (); i++)
186 if (selectorList.getRef (i)->selector->getPseudoClass ())
187 return true;
188 return false;
189}
190
198 int spec = 0;
199
200 for (int i = 0; i < selectorList.size (); i++)
201 spec += selectorList.getRef (i)->selector->specificity ();
202
203 return spec;
204}
205
207 for (int i = 0; i < selectorList.size (); i++) {
208 selectorList.getRef (i)->selector->print ();
209
210 if (i < selectorList.size () - 1) {
211 switch (selectorList.getRef (i + 1)->combinator) {
212 case COMB_CHILD:
213 fprintf (stderr, "> ");
214 break;
215 case COMB_DESCENDANT:
216 fprintf (stderr, "\" \" ");
217 break;
219 fprintf (stderr, "+ ");
220 break;
221 default:
222 fprintf (stderr, "? ");
223 break;
224 }
225 }
226 }
227
228 fprintf (stderr, "\n");
229}
230
233 id = NULL;
234 pseudo = NULL;
235}
236
238 for (int i = 0; i < klass.size (); i++)
239 dFree (klass.get (i));
240 dFree (id);
241 dFree (pseudo);
242}
243
245 switch (t) {
246 case SELECT_CLASS:
247 klass.increase ();
248 klass.set (klass.size () - 1, dStrdup (v));
249 break;
251 if (pseudo == NULL)
252 pseudo = dStrdup (v);
253 break;
254 case SELECT_ID:
255 if (id == NULL)
256 id = dStrdup (v);
257 break;
258 default:
259 break;
260 }
261}
262
268 assert (n);
269 if (element != ELEMENT_ANY && element != n->element)
270 return false;
271 if (pseudo != NULL &&
272 (n->pseudo == NULL || dStrAsciiCasecmp (pseudo, n->pseudo) != 0))
273 return false;
274 if (id != NULL && (n->id == NULL || dStrAsciiCasecmp (id, n->id) != 0))
275 return false;
276 for (int i = 0; i < klass.size (); i++) {
277 bool found = false;
278 if (n->klass != NULL) {
279 for (int j = 0; j < n->klass->size (); j++) {
280 if (dStrAsciiCasecmp (klass.get(i), n->klass->get(j)) == 0) {
281 found = true;
282 break;
283 }
284 }
285 }
286 if (! found)
287 return false;
288 }
289
290 return true;
291}
292
299 int spec = 0;
300
301 if (id)
302 spec += 1 << 20;
303 spec += klass.size() << 10;
304 if (pseudo)
305 spec += 1 << 10;
306 if (element != ELEMENT_ANY)
307 spec += 1;
308
309 return spec;
310}
311
313 fprintf (stderr, "Element %d, pseudo %s, id %s ",
314 element, pseudo, id);
315 fprintf (stderr, "class ");
316 for (int i = 0; i < klass.size (); i++)
317 fprintf (stderr, ".%s", klass.get (i));
318}
319
320CssRule::CssRule (CssSelector *selector, CssPropertyList *props, int pos) {
321 assert (selector->size () > 0);
322
323 this->selector = selector;
324 this->selector->ref ();
325 this->props = props;
326 this->props->ref ();
327 this->pos = pos;
329}
330
332 selector->unref ();
333 props->unref ();
334}
335
337 const DoctreeNode *node, MatchCache *matchCache) const {
338 if (selector->match (docTree, node, matchCache))
339 this->props->apply (props);
340}
341
343 selector->print ();
344 props->print ();
345}
346
347/*
348 * \brief Insert rule with increasing specificity.
349 *
350 * If two rules have the same specificity, the one that was added later
351 * will be added behind the others.
352 * This gives later added rules more weight.
353 */
355 increase ();
356 int i = size () - 1;
357
358 while (i > 0 && rule->specificity () < get (i - 1)->specificity ()) {
359 *getRef (i) = get (i - 1);
360 i--;
361 }
362
363 *getRef (i) = rule;
364}
365
373 CssSimpleSelector *top = rule->selector->top ();
374 RuleList *ruleList = NULL;
376
377 if (top->getId ()) {
378 string = new lout::object::ConstString (top->getId ());
379 ruleList = idTable.get (string);
380 if (ruleList == NULL) {
381 ruleList = new RuleList ();
382 idTable.put (string, ruleList);
383 } else {
384 delete string;
385 }
386 } else if (top->getClass () && top->getClass ()->size () > 0) {
387 string = new lout::object::ConstString (top->getClass ()->get (0));
388 ruleList = classTable.get (string);
389 if (ruleList == NULL) {
390 ruleList = new RuleList;
391 classTable.put (string, ruleList);
392 } else {
393 delete string;
394 }
395 } else if (top->getElement () >= 0 && top->getElement () < ntags) {
396 ruleList = &elementTable[top->getElement ()];
397 } else if (top->getElement () == CssSimpleSelector::ELEMENT_ANY) {
398 ruleList = &anyTable;
399 }
400
401 if (ruleList) {
402 ruleList->insert (rule);
405 } else {
407 delete rule;
408 }
409}
410
418 const DoctreeNode *node, MatchCache *matchCache) const {
419 static const int maxLists = 32;
420 const RuleList *ruleList[maxLists];
421 int numLists = 0, index[maxLists] = {0};
422
423 if (node->id) {
424 lout::object::ConstString idString (node->id);
425
426 ruleList[numLists] = idTable.get (&idString);
427 if (ruleList[numLists])
428 numLists++;
429 }
430
431 if (node->klass) {
432 for (int i = 0; i < node->klass->size (); i++) {
433 if (i >= maxLists - 4) {
434 MSG_WARN("Maximum number of classes per element exceeded.\n");
435 break;
436 }
437
438 lout::object::ConstString classString (node->klass->get (i));
439
440 ruleList[numLists] = classTable.get (&classString);
441 if (ruleList[numLists])
442 numLists++;
443 }
444 }
445
446 ruleList[numLists] = &elementTable[node->element];
447 if (ruleList[numLists])
448 numLists++;
449
450 ruleList[numLists] = &anyTable;
451 if (ruleList[numLists])
452 numLists++;
453
454 // Apply potentially matching rules from ruleList[0-numLists] with
455 // ascending specificity.
456 // If specificity is equal, rules are applied in order of appearance.
457 // Each ruleList is sorted already.
458 while (true) {
459 int minSpec = 1 << 30;
460 int minPos = 1 << 30;
461 int minSpecIndex = -1;
462
463 for (int i = 0; i < numLists; i++) {
464 const RuleList *rl = ruleList[i];
465
466 if (rl && rl->size () > index[i] &&
467 (rl->get(index[i])->specificity () < minSpec ||
468 (rl->get(index[i])->specificity () == minSpec &&
469 rl->get(index[i])->position () < minPos))) {
470
471 minSpec = rl->get(index[i])->specificity ();
472 minPos = rl->get(index[i])->position ();
473 minSpecIndex = i;
474 }
475 }
476
477 if (minSpecIndex >= 0) {
478 CssRule *rule = ruleList[minSpecIndex]->get (index[minSpecIndex]);
479 rule->apply(props, docTree, node, matchCache);
480 index[minSpecIndex]++;
481 } else {
482 break;
483 }
484 }
485}
486
488
490 pos = 0;
491 matchCache.setSize (userAgentSheet.getRequiredMatchCache (), -1);
492}
493
504 DoctreeNode *node,
505 CssPropertyList *tagStyle, CssPropertyList *tagStyleImportant,
506 CssPropertyList *nonCssHints) {
507
508 userAgentSheet.apply (props, docTree, node, &matchCache);
509
510 sheet[CSS_PRIMARY_USER].apply (props, docTree, node, &matchCache);
511
512 if (nonCssHints)
513 nonCssHints->apply (props);
514
515 sheet[CSS_PRIMARY_AUTHOR].apply (props, docTree, node, &matchCache);
516
517 if (tagStyle)
518 tagStyle->apply (props);
519
520 sheet[CSS_PRIMARY_AUTHOR_IMPORTANT].apply (props, docTree, node,
521 &matchCache);
522
523 if (tagStyleImportant)
524 tagStyleImportant->apply (props);
525
526 sheet[CSS_PRIMARY_USER_IMPORTANT].apply (props, docTree, node, &matchCache);
527}
528
530 CssPrimaryOrder order) {
531
532 if (props->size () > 0) {
533 CssRule *rule = new CssRule (sel, props, pos++);
534
535 if ((order == CSS_PRIMARY_AUTHOR ||
537 !rule->isSafe ()) {
538 _MSG_WARN ("Ignoring unsafe author style that might reveal browsing history\n");
539 delete rule;
540 } else {
541 rule->selector->setMatchCacheOffset(matchCache.size ());
542 if (rule->selector->getRequiredMatchCache () > matchCache.size ())
543 matchCache.setSize (rule->selector->getRequiredMatchCache (), -1);
544
545 if (order == CSS_PRIMARY_USER_AGENT) {
546 userAgentSheet.addRule (rule);
547 } else {
548 sheet[order].addRule (rule);
549 }
550 }
551 }
552}
void apply(CssPropertyList *props, Doctree *docTree, DoctreeNode *node, CssPropertyList *tagStyle, CssPropertyList *tagStyleImportant, CssPropertyList *nonCssHints)
Apply a CSS context to a property list.
Definition css.cc:503
CssContext()
Definition css.cc:489
void addRule(CssSelector *sel, CssPropertyList *props, CssPrimaryOrder order)
Definition css.cc:529
static CssStyleSheet userAgentSheet
Definition css.hh:517
static const char * propertyNameString(CssPropertyName name)
A list of CssProperty objects.
Definition css.hh:328
~CssPropertyList()
Definition css.cc:49
void print()
Definition css.cc:102
void set(CssPropertyName name, CssValueType type, CssPropertyValue value)
Set property to a given name and type.
Definition css.cc:58
void unref()
Definition css.hh:349
CssPropertyList(bool ownerOfStrings=false)
Definition css.hh:334
void apply(CssPropertyList *props)
Merge properties into argument property list.
Definition css.cc:87
void ref()
Definition css.hh:348
bool ownerOfStrings
Definition css.hh:330
This class holds a CSS property and value pair.
Definition css.hh:302
short type
Definition css.hh:306
void free()
Definition css.hh:309
void print()
Definition css.cc:20
short name
Definition css.hh:305
CssPropertyValue value
Definition css.hh:307
A CssSelector CssPropertyList pair.
Definition css.hh:447
~CssRule()
Definition css.cc:331
CssSelector * selector
Definition css.hh:453
void apply(CssPropertyList *props, Doctree *docTree, const DoctreeNode *node, MatchCache *matchCache) const
Definition css.cc:336
void print()
Definition css.cc:342
int pos
Definition css.hh:450
CssRule(CssSelector *selector, CssPropertyList *props, int pos)
Definition css.cc:320
CssPropertyList * props
Definition css.hh:449
int spec
Definition css.hh:450
int position()
Definition css.hh:464
int specificity()
Definition css.hh:463
bool isSafe()
Definition css.hh:460
CSS selector class.
Definition css.hh:394
CssSimpleSelector * top()
Definition css.hh:419
bool match(Doctree *dt, const DoctreeNode *node, int i, Combinator comb, MatchCache *matchCache)
Return whether selector matches at a given node in the document tree.
Definition css.cc:127
void print()
Definition css.cc:206
CssSelector()
Definition css.cc:107
void addSimpleSelector(Combinator c)
Definition css.cc:173
int refCount
Definition css.hh:409
lout::misc::SimpleVector< struct CombinatorAndSelector > selectorList
Definition css.hh:410
@ COMB_DESCENDANT
Definition css.hh:398
@ COMB_CHILD
Definition css.hh:399
@ COMB_ADJACENT_SIBLING
Definition css.hh:400
@ COMB_NONE
Definition css.hh:397
bool checksPseudoClass()
Definition css.cc:184
int getRequiredMatchCache()
Definition css.hh:432
~CssSelector()
Definition css.cc:119
void setMatchCacheOffset(int mo)
Definition css.hh:428
int specificity()
Return the specificity of the selector.
Definition css.cc:197
int size()
Definition css.hh:422
int matchCacheOffset
Definition css.hh:409
void ref()
Definition css.hh:438
void unref()
Definition css.hh:439
int getElement()
Definition css.hh:378
char * pseudo
Definition css.hh:355
const char * getId()
Definition css.hh:377
bool match(const DoctreeNode *node)
Return whether simple selector matches at a given node of the document tree.
Definition css.cc:267
int specificity()
Return the specificity of the simple selector.
Definition css.cc:298
void print()
Definition css.cc:312
@ SELECT_PSEUDO_CLASS
Definition css.hh:367
void setSelect(SelectType t, const char *v)
Definition css.cc:244
lout::misc::SimpleVector< char * > * getClass()
Definition css.hh:375
lout::misc::SimpleVector< char * > klass
Definition css.hh:356
void insert(CssRule *rule)
Definition css.cc:354
A list of CssRules.
Definition css.hh:473
void addRule(CssRule *rule)
Insert a rule into CssStyleSheet.
Definition css.cc:372
RuleMap idTable
Definition css.hh:501
RuleMap classTable
Definition css.hh:501
RuleList anyTable
Definition css.hh:500
RuleList elementTable[ntags]
Definition css.hh:500
int requiredMatchCache
Definition css.hh:502
static const int ntags
Definition css.hh:498
void apply(CssPropertyList *props, Doctree *docTree, const DoctreeNode *node, MatchCache *matchCache) const
Apply a stylesheet to a property list.
Definition css.cc:417
const char * pseudo
Definition doctree.hh:14
const char * id
Definition doctree.hh:15
lout::misc::SimpleVector< char * > * klass
Definition doctree.hh:13
int element
Definition doctree.hh:12
HTML document tree interface.
Definition doctree.hh:48
DoctreeNode * parent(const DoctreeNode *node)
Definition doctree.hh:87
DoctreeNode * sibling(const DoctreeNode *node)
Definition doctree.hh:94
void put(K *key, V *value)
Definition container.hh:542
Simple (simpler than container::untyped::Vector and container::typed::Vector) template based vector.
Definition misc.hh:95
void increase()
Increase the vector size by one.
Definition misc.hh:161
void set(int i, T t)
Store an object in the vector.
Definition misc.hh:247
T get(int i) const
Return the one element, explicitly.
Definition misc.hh:202
int size() const
Return the number of elements put into this vector.
Definition misc.hh:142
CssProperty * getRef(int i) const
Return the reference of one element.
Definition misc.hh:191
An object::Object wrapper for constant strings (char*).
Definition object.hh:163
CssPropertyName
Definition css.hh:161
@ CSS_PROPERTY_BACKGROUND_IMAGE
Definition css.hh:165
@ CSS_PROPERTY_DISPLAY
Definition css.hh:192
CssValueType
Definition css.hh:36
@ CSS_TYPE_STRING
<string>
Definition css.hh:58
@ CSS_TYPE_SYMBOL
Symbols, which are directly copied (as opposed to CSS_TYPE_ENUM and CSS_TYPE_MULTI_ENUM).
Definition css.hh:59
CssPrimaryOrder
Definition css.hh:21
@ CSS_PRIMARY_USER_IMPORTANT
Definition css.hh:26
@ CSS_PRIMARY_AUTHOR_IMPORTANT
Definition css.hh:25
@ CSS_PRIMARY_USER
Definition css.hh:23
@ CSS_PRIMARY_AUTHOR
Definition css.hh:24
@ CSS_PRIMARY_USER_AGENT
Definition css.hh:22
void dFree(void *mem)
Definition dlib.c:68
int dStrAsciiCasecmp(const char *s1, const char *s2)
Definition dlib.c:203
char * dStrdup(const char *s)
Definition dlib.c:77
#define _MSG_WARN(...)
Definition msg.h:15
#define MSG_WARN(...)
Definition msg.h:26
Anything related to Dillo Widget styles is defined here.
Definition style.cc:34
CssSimpleSelector * selector
Definition css.hh:406
char * strVal
Definition css.hh:260
int32_t intVal
Definition css.hh:259