KHtml

cssstyleselector.cpp
1 /**
2  * This file is part of the CSS implementation for KDE.
3  *
4  * Copyright 1999-2003 Lars Knoll ([email protected])
5  * Copyright 2003-2004 Apple Computer, Inc.
6  * Copyright 2004-2010 Allan Sandfeld Jensen ([email protected])
7  * Copyright 2004-2008 Germain Garand ([email protected])
8  * Copyright 2008 Vyacheslav Tokarev ([email protected])
9  * (C) 2005, 2006, 2008 Apple Computer, Inc.
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Library General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Library General Public License for more details.
20  *
21  * You should have received a copy of the GNU Library General Public License
22  * along with this library; see the file COPYING.LIB. If not, write to
23  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  * Boston, MA 02110-1301, USA.
25  */
26 
27 #include "css/cssstyleselector.h"
28 #include "css/css_stylesheetimpl.h"
29 #include "css/css_ruleimpl.h"
30 #include "css/css_valueimpl.h"
31 #include "css/csshelper.h"
32 #include "css/css_webfont.h"
33 #include "rendering/render_object.h"
34 #include "html/html_documentimpl.h"
35 #include "html/html_elementimpl.h"
36 #include "xml/dom_elementimpl.h"
37 #include "xml/dom_restyler.h"
38 #include "dom/css_rule.h"
39 #include "dom/css_value.h"
40 #include "khtml_global.h"
41 #include "khtmlpart_p.h"
42 using namespace khtml;
43 using namespace DOM;
44 
45 #include "css/cssproperties.h"
46 #include "css/cssvalues.h"
47 
48 #include "misc/khtmllayout.h"
49 #include "khtml_settings.h"
50 #include "misc/helper.h"
51 #include "misc/loader.h"
52 
53 #include "rendering/font.h"
54 
55 #include "khtmlview.h"
56 #include "khtml_part.h"
57 
58 #include <kconfig.h>
59 #include <QFile>
60 #include <QString>
61 #include <QFileInfo>
62 #include <QUrl>
63 #include <QFontDatabase>
64 #include <qstandardpaths.h>
65 
66 #include "khtml_debug.h"
67 #include <assert.h>
68 #include <stdlib.h>
69 
70 // keep in sync with html4.css'
71 #define KHTML_STYLE_VERSION 1
72 
73 #undef PRELATIVE
74 #undef PABSOLUTE
75 
76 // handle value "inherit" on a default inherited property
77 #define HANDLE_INHERIT_ON_INHERITED_PROPERTY(prop, Prop) \
78  if (isInherit) \
79  {\
80  style->set##Prop(parentStyle->prop());\
81  return;\
82  }
83 
84 // handle value "inherit" on a default non-inherited property
85 #define HANDLE_INHERIT_ON_NONINHERITED_PROPERTY(prop, Prop) \
86  if (isInherit) \
87  {\
88  style->setInheritedNoninherited(true);\
89  style->set##Prop(parentStyle->prop());\
90  return;\
91  }
92 
93 #define HANDLE_INITIAL(prop, Prop) \
94  if (isInitial) \
95  {\
96  style->set##Prop(RenderStyle::initial##Prop());\
97  return;\
98  }
99 
100 #define HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(prop, Prop) \
101  HANDLE_INITIAL(prop, Prop) \
102  else \
103  HANDLE_INHERIT_ON_NONINHERITED_PROPERTY(prop, Prop)
104 
105 #define HANDLE_INITIAL_AND_INHERIT_ON_INHERITED_PROPERTY(prop, Prop) \
106  HANDLE_INITIAL(prop, Prop) \
107  else \
108  HANDLE_INHERIT_ON_INHERITED_PROPERTY(prop, Prop)
109 
110 // all non-inherited properties
111 #define HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(prop, Prop, Value) \
112  HANDLE_INHERIT_ON_NONINHERITED_PROPERTY(prop, Prop) \
113  else if (isInitial) \
114  {\
115  style->set##Prop(RenderStyle::initial##Value());\
116  return;\
117  }
118 
119 #define HANDLE_BACKGROUND_INHERIT_AND_INITIAL(prop, Prop) \
120  if (isInherit) { \
121  style->setInheritedNoninherited(true); \
122  BackgroundLayer* currChild = style->accessBackgroundLayers(); \
123  BackgroundLayer* prevChild = nullptr; \
124  const BackgroundLayer* currParent = parentStyle->backgroundLayers(); \
125  while (currParent && currParent->is##Prop##Set()) { \
126  if (!currChild) { \
127  /* Need to make a new layer.*/ \
128  currChild = new BackgroundLayer(); \
129  prevChild->setNext(currChild); \
130  } \
131  currChild->set##Prop(currParent->prop()); \
132  prevChild = currChild; \
133  currChild = prevChild->next(); \
134  currParent = currParent->next(); \
135  } \
136  \
137  while (currChild) { \
138  /* Reset any remaining layers to not have the property set. */ \
139  currChild->clear##Prop(); \
140  currChild = currChild->next(); \
141  } \
142  } else if (isInitial) { \
143  BackgroundLayer* currChild = style->accessBackgroundLayers(); \
144  currChild->set##Prop(RenderStyle::initial##Prop()); \
145  for (currChild = currChild->next(); currChild; currChild = currChild->next()) \
146  currChild->clear##Prop(); \
147  }
148 
149 #define HANDLE_BACKGROUND_VALUE(prop, Prop, value) { \
150  HANDLE_BACKGROUND_INHERIT_AND_INITIAL(prop, Prop) \
151  else { \
152  if (!value->isPrimitiveValue() && !value->isValueList()) \
153  return; \
154  BackgroundLayer* currChild = style->accessBackgroundLayers(); \
155  BackgroundLayer* prevChild = nullptr; \
156  if (value->isPrimitiveValue()) { \
157  map##Prop(currChild, value); \
158  currChild = currChild->next(); \
159  } \
160  else { \
161  /* Walk each value and put it into a layer, creating new layers as needed. */ \
162  CSSValueListImpl* valueList = static_cast<CSSValueListImpl*>(value); \
163  for (unsigned int i = 0; i < valueList->length(); i++) { \
164  if (!currChild) { \
165  /* Need to make a new layer to hold this value */ \
166  currChild = new BackgroundLayer(); \
167  prevChild->setNext(currChild); \
168  } \
169  map##Prop(currChild, valueList->item(i)); \
170  prevChild = currChild; \
171  currChild = currChild->next(); \
172  } \
173  } \
174  while (currChild) { \
175  /* Reset all remaining layers to not have the property set. */ \
176  currChild->clear##Prop(); \
177  currChild = currChild->next(); \
178  } \
179  } }
180 
181 #define HANDLE_INHERIT_COND(propID, prop, Prop) \
182  if (id == propID) \
183  {\
184  style->set##Prop(parentStyle->prop());\
185  return;\
186  }
187 
188 #define HANDLE_INHERIT_COND_WITH_BACKUP(propID, prop, propAlt, Prop) \
189  if (id == propID) { \
190  if (parentStyle->prop().isValid()) \
191  style->set##Prop(parentStyle->prop()); \
192  else \
193  style->set##Prop(parentStyle->propAlt()); \
194  return; \
195  }
196 
197 #define HANDLE_INITIAL_COND(propID, Prop) \
198  if (id == propID) \
199  {\
200  style->set##Prop(RenderStyle::initial##Prop());\
201  return;\
202  }
203 
204 #define HANDLE_INITIAL_COND_WITH_VALUE(propID, Prop, Value) \
205  if (id == propID) \
206  {\
207  style->set##Prop(RenderStyle::initial##Value());\
208  return;\
209  }
210 
211 namespace khtml
212 {
213 
214 CSSStyleSelectorList *CSSStyleSelector::s_defaultStyle;
215 CSSStyleSelectorList *CSSStyleSelector::s_defaultQuirksStyle;
216 CSSStyleSelectorList *CSSStyleSelector::s_defaultNonCSSHintsStyle;
217 CSSStyleSelectorList *CSSStyleSelector::s_defaultPrintStyle;
218 CSSStyleSheetImpl *CSSStyleSelector::s_defaultSheet;
219 CSSStyleSheetImpl *CSSStyleSelector::s_defaultNonCSSHintsSheet;
220 RenderStyle *CSSStyleSelector::styleNotYetAvailable;
221 CSSStyleSheetImpl *CSSStyleSelector::s_quirksSheet;
222 
223 enum PseudoState { PseudoUnknown, PseudoNone, PseudoLink, PseudoVisited};
224 static PseudoState pseudoState;
225 
226 CSSStyleSelector::CSSStyleSelector(DocumentImpl *doc, QString userStyleSheet, StyleSheetListImpl *styleSheets,
227  const QUrl &url, bool _strictParsing)
228 {
229  KHTMLView *view = doc->view();
230  KHTMLPart *part = doc->part();
231 
232  m_fontSelector = new CSSFontSelector(doc);
233 
234  init(part ? part->settings() : nullptr, doc);
235 
236  strictParsing = _strictParsing;
237 
238  selectors = nullptr;
239  selectorCache = nullptr;
240  propertiesBuffer = nullptr;
241  nextPropertyIndexes = nullptr;
242  userStyle = nullptr;
243  userSheet = nullptr;
244  logicalDpiY = doc->logicalDpiY();
245 
246  if (logicalDpiY) { // this may be null, not everyone uses khtmlview (Niko)
247  computeFontSizes(logicalDpiY, part ? part->fontScaleFactor() : 100);
248  }
249 
250  // build a limited default style suitable to evaluation of media queries
251  // containing relative constraints, like "screen and (max-width: 10em)"
252  setupDefaultRootStyle(doc);
253 
254  if (view) {
255  m_medium = new MediaQueryEvaluator(view->mediaType(), view->part(), m_rootDefaultStyle);
256  } else {
257  m_medium = new MediaQueryEvaluator("all", nullptr, m_rootDefaultStyle);
258  }
259 
260  if (!userStyleSheet.isEmpty()) {
261  userSheet = new DOM::CSSStyleSheetImpl(doc);
262  userSheet->parseString(DOMString(userStyleSheet));
263 
264  userStyle = new CSSStyleSelectorList();
265  userStyle->append(userSheet, m_medium, this);
266  }
267 
268  // add stylesheets from document
269  authorStyle = nullptr;
270  implicitStyle = nullptr;
271 
272  foreach (StyleSheetImpl *sh, styleSheets->styleSheets) {
273  if (sh->isCSSStyleSheet()) {
274  if (static_cast<CSSStyleSheetImpl *>(sh)->implicit()) {
275  if (!implicitStyle) {
276  implicitStyle = new CSSStyleSelectorList();
277  }
278  implicitStyle->append(static_cast<CSSStyleSheetImpl *>(sh), m_medium, this);
279  } else if (sh->isCSSStyleSheet() && !sh->disabled()) {
280  if (!authorStyle) {
281  authorStyle = new CSSStyleSelectorList();
282  }
283  authorStyle->append(static_cast<CSSStyleSheetImpl *>(sh), m_medium, this);
284  }
285  }
286  }
287 
288  buildLists();
289 
290  //qCDebug(KHTML_LOG) << "number of style sheets in document " << authorStyleSheets.count();
291  //qCDebug(KHTML_LOG) << "CSSStyleSelector: author style has " << authorStyle->count() << " elements";
292 
293  QUrl u = url;
294 
295  u.setQuery(QString());
296  u.setFragment(QString());
297  encodedurl.file = u.url();
298  int pos = encodedurl.file.lastIndexOf('/');
299  encodedurl.path = encodedurl.file;
300  if (pos > 0) {
301  encodedurl.path.truncate(pos);
302  encodedurl.path += '/';
303  }
304  u.setPath(QString());
305  encodedurl.host = u.url();
306 
307  //qCDebug(KHTML_LOG) << "CSSStyleSelector::CSSStyleSelector encoded url " << encodedurl.path;
308 }
309 
310 CSSStyleSelector::CSSStyleSelector(CSSStyleSheetImpl *sheet)
311 {
312  m_fontSelector = new CSSFontSelector(sheet->doc());
313 
314  init(nullptr, nullptr);
315 
316  KHTMLView *view = sheet->doc()->view();
317 
318  setupDefaultRootStyle(sheet->doc());
319 
320  if (view) {
321  m_medium = new MediaQueryEvaluator(view->mediaType(), view->part(), m_rootDefaultStyle);
322  } else {
323  m_medium = new MediaQueryEvaluator("screen", nullptr, m_rootDefaultStyle);
324  }
325 
326  if (sheet->implicit()) {
327  implicitStyle = new CSSStyleSelectorList();
328  implicitStyle->append(sheet, m_medium, this);
329  } else {
330  authorStyle = new CSSStyleSelectorList();
331  authorStyle->append(sheet, m_medium, this);
332  }
333 }
334 
335 void CSSStyleSelector::init(const KHTMLSettings *_settings, DocumentImpl *doc)
336 {
337  element = nullptr;
338  settings = _settings;
339  logicalDpiY = 0;
340  if (!s_defaultStyle) {
341  loadDefaultStyle(settings, doc);
342  }
343 
344  defaultStyle = s_defaultStyle;
345  defaultPrintStyle = s_defaultPrintStyle;
346  defaultQuirksStyle = s_defaultQuirksStyle;
347  defaultNonCSSHintsStyle = s_defaultNonCSSHintsStyle;
348  m_rootDefaultStyle = nullptr;
349  m_medium = nullptr;
350 }
351 
352 CSSStyleSelector::~CSSStyleSelector()
353 {
354  clearLists();
355  delete authorStyle;
356  delete implicitStyle;
357  delete userStyle;
358  delete userSheet;
359  delete m_rootDefaultStyle;
360  delete m_medium;
361  delete m_fontSelector;
362 }
363 
364 void CSSStyleSelector::addSheet(CSSStyleSheetImpl *sheet)
365 {
366  KHTMLView *view = sheet->doc()->view();
367 
368  setupDefaultRootStyle(sheet->doc());
369 
370  delete m_medium; m_medium = nullptr;
371  delete authorStyle; authorStyle = nullptr;
372  delete implicitStyle; implicitStyle = nullptr;
373 
374  if (view) {
375  m_medium = new MediaQueryEvaluator(view->mediaType(), view->part(), m_rootDefaultStyle);
376  } else {
377  m_medium = new MediaQueryEvaluator("screen", nullptr, m_rootDefaultStyle);
378  }
379 
380  if (sheet->implicit()) {
381  if (!implicitStyle) {
382  implicitStyle = new CSSStyleSelectorList();
383  }
384  implicitStyle->append(sheet, m_medium, this);
385  } else {
386  if (!authorStyle) {
387  authorStyle = new CSSStyleSelectorList();
388  }
389  authorStyle->append(sheet, m_medium, this);
390  }
391 }
392 
393 void CSSStyleSelector::loadDefaultStyle(const KHTMLSettings *s, DocumentImpl *doc)
394 {
395  if (s_defaultStyle) {
396  return;
397  }
398 
399  MediaQueryEvaluator screenEval("screen");
400  MediaQueryEvaluator printEval("print");
401 
402  {
405 
406  QByteArray file(f.size() + 1, 0);
407  int readbytes = f.read(file.data(), f.size());
408  f.close();
409  if (readbytes >= 0) {
410  file[readbytes] = '\0';
411  }
412 
413  QString style = QLatin1String(file.data());
414 
415  QRegExp checkVersion("KHTML_STYLE_VERSION:\\s*(\\d+)");
416  checkVersion.setMinimal(true);
417  if (checkVersion.indexIn(style) == -1 || checkVersion.cap(1).toInt() != KHTML_STYLE_VERSION) {
418  qFatal("!!!!!!! ERROR !!!!!!! - KHTML default stylesheet version mismatch. Aborting. Check your installation. File used was: %s. Expected STYLE_VERSION %d\n",
419  QFileInfo(f).absoluteFilePath().toLatin1().data(), KHTML_STYLE_VERSION);
420  }
421 
422  if (s) {
423  style += s->settingsToCSS();
424  }
425  DOMString str(style);
426 
427  s_defaultSheet = new DOM::CSSStyleSheetImpl(doc);
428  s_defaultSheet->parseString(str);
429 
430  // Collect only strict-mode rules.
431  s_defaultStyle = new CSSStyleSelectorList();
432  s_defaultStyle->append(s_defaultSheet, &screenEval, doc->styleSelector());
433 
434  s_defaultPrintStyle = new CSSStyleSelectorList();
435  s_defaultPrintStyle->append(s_defaultSheet, &printEval, doc->styleSelector());
436  }
437  {
438  QFile f(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kf5/khtml/css/quirks.css"));
440 
441  QByteArray file(f.size() + 1, 0);
442  int readbytes = f.read(file.data(), f.size());
443  f.close();
444  if (readbytes >= 0) {
445  file[readbytes] = '\0';
446  }
447 
448  QString style = QLatin1String(file.data());
449  DOMString str(style);
450 
451  s_quirksSheet = new DOM::CSSStyleSheetImpl(doc);
452  s_quirksSheet->parseString(str);
453 
454  // Collect only quirks-mode rules.
455  s_defaultQuirksStyle = new CSSStyleSelectorList();
456  s_defaultQuirksStyle->append(s_quirksSheet, &screenEval, doc->styleSelector());
457  }
458  {
459  QFile f(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kf5/khtml/css/presentational.css"));
461 
462  QByteArray file(f.size() + 1, 0);
463  int readbytes = f.read(file.data(), f.size());
464  f.close();
465  if (readbytes >= 0) {
466  file[readbytes] = '\0';
467  }
468 
469  QString style = QLatin1String(file.data());
470  DOMString str(style);
471 
472  s_defaultNonCSSHintsSheet = new DOM::CSSStyleSheetImpl(doc);
473  s_defaultNonCSSHintsSheet->parseString(str);
474 
475  s_defaultNonCSSHintsStyle = new CSSStyleSelectorList();
476  s_defaultNonCSSHintsStyle->append(s_defaultNonCSSHintsSheet, &screenEval, doc->styleSelector());
477  }
478  //qCDebug(KHTML_LOG) << "CSSStyleSelector: default style has " << defaultStyle->count() << " elements";
479 }
480 
481 void CSSStyleSelector::clear()
482 {
483  delete s_defaultStyle;
484  delete s_defaultQuirksStyle;
485  delete s_defaultPrintStyle;
486  delete s_defaultNonCSSHintsStyle;
487  delete s_defaultSheet;
488  delete s_defaultNonCSSHintsSheet;
489  delete styleNotYetAvailable;
490  s_defaultStyle = nullptr;
491  s_defaultQuirksStyle = nullptr;
492  s_defaultPrintStyle = nullptr;
493  s_defaultNonCSSHintsStyle = nullptr;
494  s_defaultSheet = nullptr;
495  s_defaultNonCSSHintsSheet = nullptr;
496  styleNotYetAvailable = nullptr;
497 }
498 
499 void CSSStyleSelector::reparseConfiguration()
500 {
501  // nice leak, but best we can do right now. hopefully it is only rare.
502  s_defaultStyle = nullptr;
503  s_defaultQuirksStyle = nullptr;
504  s_defaultPrintStyle = nullptr;
505  s_defaultNonCSSHintsStyle = nullptr;
506  s_defaultSheet = nullptr;
507 }
508 
509 #define MAXFONTSIZES 8
510 
511 void CSSStyleSelector::computeFontSizes(int logicalDpiY, int zoomFactor)
512 {
513  computeFontSizesFor(logicalDpiY, zoomFactor, m_fontSizes, false);
514  computeFontSizesFor(logicalDpiY, zoomFactor, m_fixedFontSizes, true);
515 }
516 
517 void CSSStyleSelector::computeFontSizesFor(int logicalDpiY, int zoomFactor, QVector<int> &fontSizes, bool isFixed)
518 {
519 #ifdef APPLE_CHANGES
520  // We don't want to scale the settings by the dpi.
521  const float toPix = 1.0;
522 #else
523  Q_UNUSED(isFixed);
524 
525  const float toPix = qMax(logicalDpiY, 96) / 72.0f;
526 #endif // ######### fix isFixed code again.
527 
528  fontSizes.resize(MAXFONTSIZES);
529  float scale = 1.0;
530  static const float fontFactors[] = {3.0f / 5.0f, 3.0f / 4.0f, 8.0f / 9.0f, 1.0f, 6.0f / 5.0f, 3.0f / 2.0f, 2.0f, 3.0f};
531  static const float smallFontFactors[] = {3.0f / 4.0f, 5.0f / 6.0f, 8.0f / 9.0f, 1.0f, 6.0f / 5.0f, 3.0f / 2.0f, 2.0f, 3.0f};
532  float mediumFontSize, factor;
533  if (!khtml::printpainter) {
534  scale *= zoomFactor / 100.0;
535 #ifdef APPLE_CHANGES
536  if (isFixed) {
537  mediumFontSize = settings->mediumFixedFontSize() * toPix;
538  } else
539 #endif
540  mediumFontSize = settings->mediumFontSize() * toPix;
541  m_minFontSize = settings->minFontSize() * toPix;
542  } else {
543  // ### depending on something / configurable ?
544  mediumFontSize = 12;
545  m_minFontSize = 6;
546  }
547  const float *factors = scale * mediumFontSize >= 12.5 ? fontFactors : smallFontFactors;
548  for (int i = 0; i < MAXFONTSIZES; i++) {
549  factor = scale * factors[i];
550  fontSizes[i] = qMax(qRound(mediumFontSize * factor), m_minFontSize);
551  //qCDebug(KHTML_LOG) << "index:" << i << "factor:" << factors[i] << "font pix size:" << fontSizes[i];
552  }
553 }
554 
555 #undef MAXFONTSIZES
556 
557 RenderStyle *CSSStyleSelector::locateSimilarStyle()
558 {
559  ElementImpl *s = nullptr, *t = nullptr, *c = nullptr;
560  if (!element) {
561  return nullptr;
562  }
563  // Check previous siblings.
564  unsigned count = 0;
565  NodeImpl *n = element;
566  do {
567  for (n = n->previousSibling(); n && !n->isElementNode(); n = n->previousSibling());
568  if (!n) {
569  break;
570  }
571  ElementImpl *e = static_cast<ElementImpl *>(n);
572  if (++count > 10) {
573  break;
574  }
575  if (!s) {
576  s = e; // sibling match
577  }
578  if (e->id() != element->id()) {
579  continue;
580  }
581  if (!t) {
582  t = e; // tag match
583  }
584  if (element->hasClass()) {
585  if (!e->hasClass()) {
586  continue;
587  }
588  const DOMString &class1 = element->getAttribute(ATTR_CLASS);
589  const DOMString &class2 = e->getAttribute(ATTR_CLASS);
590  if (class1 != class2) {
591  continue;
592  }
593  }
594  if (!c) {
595  c = e; // class match
596  }
597  break;
598  } while (true);
599 
600  // if possible return sibling that matches tag and class
601  if (c && c->renderer() && c->renderer()->style()) {
602  return c->renderer()->style();
603  }
604  // second best: return sibling that matches tag
605  if (t && t->renderer() && t->renderer()->style()) {
606  return t->renderer()->style();
607  }
608  // third best: return sibling element
609  if (s && s->renderer() && s->renderer()->style()) {
610  return s->renderer()->style();
611  }
612  // last attempt: return parent element
613  NodeImpl *p = element->parentNode();
614  if (p && p->renderer()) {
615  return p->renderer()->style();
616  }
617 
618  return nullptr;
619 }
620 
621 static inline void bubbleSort(CSSOrderedProperty **b, CSSOrderedProperty **e)
622 {
623  while (b < e) {
624  bool swapped = false;
625  CSSOrderedProperty **y = e + 1;
626  CSSOrderedProperty **x = e;
627  CSSOrderedProperty **swappedPos = nullptr;
628  do {
629  if (!((**(--x)) < (**(--y)))) {
630  swapped = true;
631  swappedPos = x;
632  CSSOrderedProperty *tmp = *y;
633  *y = *x;
634  *x = tmp;
635  }
636  } while (x != b);
637  if (!swapped) {
638  break;
639  }
640  b = swappedPos + 1;
641  }
642 }
643 
644 RenderStyle *CSSStyleSelector::styleForElement(ElementImpl *e, RenderStyle *fallbackParentStyle)
645 {
646  if (!e->document()->haveStylesheetsLoaded() || !e->document()->view()) {
647  if (!styleNotYetAvailable) {
648  styleNotYetAvailable = new RenderStyle();
649  styleNotYetAvailable->setDisplay(NONE);
650  styleNotYetAvailable->ref();
651  }
652  return styleNotYetAvailable;
653  }
654 
655  // set some variables we will need
656  pseudoState = PseudoUnknown;
657 
658  element = e;
659  parentNode = e->parentNode();
660  parentStyle = (parentNode && parentNode->renderer()) ?
661  parentNode->renderer()->style() : fallbackParentStyle;
662  view = element->document()->view();
663  part = view->part();
664  settings = part->settings();
665  logicalDpiY = element->document()->logicalDpiY();
666 
667  // reset dynamic DOM dependencies
668  e->document()->dynamicDomRestyler().resetDependencies(e);
669 
670  style = new RenderStyle();
671  if (parentStyle) {
672  style->inheritFrom(parentStyle);
673  } else {
674  parentStyle = style;
675  }
676 
677  const RenderObject *docElementRenderer = e->document()->documentElement()->renderer();
678  m_rootStyle = docElementRenderer ? docElementRenderer->style() : m_rootDefaultStyle;
679 
680  // try to sort out most style rules as early as possible.
681  quint16 cssTagId = localNamePart(element->id());
682  int smatch = 0;
683  int schecked = 0;
684 
685  // do aggressive selection of selectors to check
686  // instead of going over whole constructed list,
687  // skip selectors that won't match for sure (e.g. with different id or class)
688  QVarLengthArray<int> selectorsForCheck;
689  // add unknown selectors to always be checked
690  for (unsigned int i = otherSelector; i < selectors_size; i = nextSimilarSelector[i]) {
691  selectorsForCheck.append(i);
692  }
693  // check if we got class attribute on element: add selectors with it to the list
694  if (e->hasClass()) {
695  const ClassNames &classNames = element->classNames();
696  for (unsigned int i = 0; i < classNames.size(); ++i) {
697  WTF::HashMap<quintptr, int>::iterator it = classSelector.find((quintptr)classNames[i].impl());
698  if (it != classSelector.end())
699  for (unsigned int j = it->second; j < selectors_size; j = nextSimilarSelector[j]) {
700  selectorsForCheck.append(j);
701  }
702  }
703  }
704  // check if we got id attribute on element: add selectors with it to the list
705  DOMStringImpl *idValue = element->getAttributeImplById(ATTR_ID);
706  if (idValue && idValue->length()) {
707  bool caseSensitive = (e->document()->htmlMode() == DocumentImpl::XHtml) || strictParsing;
708  AtomicString elementId = caseSensitive ? idValue : idValue->lower();
709  WTF::HashMap<quintptr, int>::iterator it = idSelector.find((quintptr)elementId.impl());
710  if (it != idSelector.end())
711  for (unsigned int j = it->second; j < selectors_size; j = nextSimilarSelector[j]) {
712  selectorsForCheck.append(j);
713  }
714  }
715  // add all selectors with given local tag
716  WTF::HashMap<unsigned, int>::iterator it = tagSelector.find(cssTagId);
717  if (it != tagSelector.end())
718  for (unsigned int j = it->second; j < selectors_size; j = nextSimilarSelector[j]) {
719  selectorsForCheck.append(j);
720  }
721 
722  // build per-element cache summaries.
723  prepareToMatchElement(element, true);
724 
725  propsToApply.clear();
726  pseudoProps.clear();
727  // now go over selectors that we prepared for check
728  // selectors yet in random order, so we store only matched selector indexes to sort after
729  unsigned amountOfMatchedSelectors = 0;
730  for (int k = 0; k < selectorsForCheck.size(); ++k) {
731  unsigned i = selectorsForCheck[k];
732  quint16 tag = selectors[i]->tagLocalName.id();
733  if (cssTagId == tag || tag == anyLocalName) {
734  ++schecked;
735  checkSelector(i, e);
736  if (selectorCache[i].state == Applies || selectorCache[i].state == AppliesPseudo) {
737  selectorsForCheck[amountOfMatchedSelectors++] = i;
738  }
739  } else {
740  selectorCache[i].state = Invalid;
741  }
742  }
743 
744  // sort only matched selectors and then collect properties
745  std::sort(selectorsForCheck.data(), selectorsForCheck.data() + amountOfMatchedSelectors);
746  for (unsigned k = 0; k < amountOfMatchedSelectors; ++k) {
747  unsigned i = selectorsForCheck[k];
748  if (selectorCache[i].state == Applies) {
749  ++smatch;
750  for (unsigned p = selectorCache[i].firstPropertyIndex; p < properties_size; p = nextPropertyIndexes[p]) {
751  propsToApply.append(propertiesBuffer + p);
752  }
753  } else if (selectorCache[i].state == AppliesPseudo) {
754  for (unsigned p = selectorCache[i].firstPropertyIndex; p < properties_size; p = nextPropertyIndexes[p]) {
755  pseudoProps.append(propertiesBuffer + p);
756  propertiesBuffer[p].pseudoId = (RenderStyle::PseudoId) selectors[i]->pseudoId;
757  }
758  }
759  }
760  // clear selectorsForCheck, it shouldn't be used after
761  selectorsForCheck.clear();
762 
763  // Inline style declarations, after all others.
764  // Non-css hints from presentational attributes will also be collected here
765  // receiving the proper priority so has to cascade from before author rules (cf.CSS 2.1-6.4.4).
766  addInlineDeclarations(e);
767 
768 // qDebug( "styleForElement( %s )", e->tagName().string().toLatin1().constData() );
769 // qDebug( "%d selectors, %d checked, %d match, %d properties ( of %d )",
770 // selectors_size, schecked, smatch, numPropsToApply, properties_size );
771 
772  if (propsToApply.size()) {
773  bubbleSort(propsToApply.data(), propsToApply.data() + propsToApply.size() - 1);
774  }
775  if (pseudoProps.size()) {
776  bubbleSort(pseudoProps.data(), pseudoProps.data() + pseudoProps.size() - 1);
777  }
778 
779  // we can't apply style rules without a view() and a part. This
780  // tends to happen on delayed destruction of widget Renderobjects
781  if (part) {
782  fontDirty = false;
783 
784  if (propsToApply.size()) {
785  for (unsigned int i = 0; i < propsToApply.size(); ++i) {
786  if (fontDirty && propsToApply[i]->priority >= (1 << 30)) {
787  // we are past the font properties, time to update to the
788  // correct font
789 #ifdef APPLE_CHANGES
790  checkForGenericFamilyChange(style, parentStyle);
791 #endif
792  style->htmlFont().update(logicalDpiY);
793  fontDirty = false;
794  }
795  DOM::CSSProperty *prop = propsToApply[i]->prop;
796 // if (prop->m_id == CSS_PROP__KONQ_USER_INPUT) qCDebug(KHTML_LOG) << "El: "<<e->nodeName().string() << " user-input: "<<((CSSPrimitiveValueImpl *)prop->value())->getIdent();
797 // if (prop->m_id == CSS_PROP_TEXT_TRANSFORM) qCDebug(KHTML_LOG) << "El: "<<e->nodeName().string();
798  applyRule(prop->m_id, prop->value());
799  }
800  if (fontDirty) {
801 #ifdef APPLE_CHANGES
802  checkForGenericFamilyChange(style, parentStyle);
803 #endif
804  style->htmlFont().update(logicalDpiY);
805  }
806  }
807 
808  // Clean up our style object's display and text decorations (among other fixups).
809  adjustRenderStyle(style, e);
810 
811  if (pseudoProps.size()) {
812  fontDirty = false;
813  //qDebug("%d applying %d pseudo props", e->cssTagId(), pseudoProps->count() );
814  for (unsigned int i = 0; i < pseudoProps.size(); ++i) {
815  if (fontDirty && pseudoProps[i]->priority >= (1 << 30)) {
816  // we are past the font properties, time to update to the
817  // correct font
818  //We have to do this for all pseudo styles
819  RenderStyle *pseudoStyle = style->pseudoStyle;
820  while (pseudoStyle) {
821  pseudoStyle->htmlFont().update(logicalDpiY);
822  pseudoStyle = pseudoStyle->pseudoStyle;
823  }
824  fontDirty = false;
825  }
826 
827  RenderStyle *pseudoStyle;
828  pseudoStyle = style->getPseudoStyle(pseudoProps[i]->pseudoId);
829  if (!pseudoStyle) {
830  pseudoStyle = style->addPseudoStyle(pseudoProps[i]->pseudoId);
831  if (pseudoStyle) {
832  pseudoStyle->inheritFrom(style);
833  }
834  }
835 
836  RenderStyle *oldStyle = style;
837  RenderStyle *oldParentStyle = parentStyle;
838  parentStyle = style;
839  style = pseudoStyle;
840  if (pseudoStyle) {
841  DOM::CSSProperty *prop = pseudoProps[i]->prop;
842  applyRule(prop->m_id, prop->value());
843  }
844  style = oldStyle;
845  parentStyle = oldParentStyle;
846  }
847 
848  if (fontDirty) {
849  RenderStyle *pseudoStyle = style->pseudoStyle;
850  while (pseudoStyle) {
851  pseudoStyle->htmlFont().update(logicalDpiY);
852  pseudoStyle = pseudoStyle->pseudoStyle;
853  }
854  }
855  }
856  }
857 
858  // Now adjust all our pseudo-styles.
859  RenderStyle *pseudoStyle = style->pseudoStyle;
860  while (pseudoStyle) {
861  adjustRenderStyle(pseudoStyle, nullptr);
862  pseudoStyle = pseudoStyle->pseudoStyle;
863  }
864 
865  // Try and share or partially share the style with our siblings
866  RenderStyle *commonStyle = locateSimilarStyle();
867  if (commonStyle) {
868  style->compactWith(commonStyle);
869  }
870 
871  // Now return the style.
872  return style;
873 }
874 
875 void CSSStyleSelector::prepareToMatchElement(DOM::ElementImpl *e, bool withDeps)
876 {
877  rememberDependencies = withDeps;
878  element = e;
879 
880  // build caches for element so it could be used in heuristic for descendant selectors
881  // go up the tree and cache possible tags, classes and ids
882  tagCache.clear();
883  idCache.clear();
884  classCache.clear();
885  ElementImpl *current = element;
886  while (true) {
887  NodeImpl *parent = current->parentNode();
888  if (!parent || !parent->isElementNode()) {
889  break;
890  }
891  current = static_cast<ElementImpl *>(parent);
892 
893  if (current->hasClass()) {
894  const ClassNames &classNames = current->classNames();
895  for (unsigned i = 0; i < classNames.size(); ++i) {
896  classCache.add((quintptr)classNames[i].impl());
897  }
898  }
899 
900  DOMStringImpl *idValue = current->getAttributeImplById(ATTR_ID);
901  if (idValue && idValue->length()) {
902  bool caseSensitive = (current->document()->htmlMode() == DocumentImpl::XHtml) || strictParsing;
903  AtomicString currentId = caseSensitive ? idValue : idValue->lower();
904  // though currentId is local and could be deleted from AtomicStringImpl cache right away
905  // don't care about that, cause selector values are stable and only they will be checked later
906  idCache.add((quintptr)currentId.impl());
907  }
908 
909  tagCache.add(localNamePart(current->id()));
910  }
911 }
912 
913 void CSSStyleSelector::adjustRenderStyle(RenderStyle *style, DOM::ElementImpl *e)
914 {
915  // Cache our original display.
916  style->setOriginalDisplay(style->display());
917 
918  if (style->display() != NONE) {
919  // If we have a <td> that specifies a float property, in quirks mode we just drop the float
920  // property.
921  // Sites also commonly use display:inline/block on <td>s and <table>s. In quirks mode we force
922  // these tags to retain their display types.
923  if (!strictParsing && e) {
924  if (e->id() == ID_TD) {
925  style->setDisplay(TABLE_CELL);
926  style->setFloating(FNONE);
927  } else if (e->id() == ID_TABLE) {
928  style->setDisplay(style->isDisplayInlineType() ? INLINE_TABLE : TABLE);
929  }
930  }
931 
932  // Table headers with a text-align of auto will change the text-align to center.
933  if (e && e->id() == ID_TH && style->textAlign() == TAAUTO) {
934  style->setTextAlign(CENTER);
935  }
936 
937  // Mutate the display to BLOCK or TABLE for certain cases, e.g., if someone attempts to
938  // position or float an inline, compact, or run-in. Cache the original display, since it
939  // may be needed for positioned elements that have to compute their static normal flow
940  // positions. We also force inline-level roots to be block-level.
941  if (style->display() != BLOCK && style->display() != TABLE /*&& style->display() != BOX*/ &&
942  (style->position() == PABSOLUTE || style->position() == PFIXED || style->floating() != FNONE ||
943  (e && e->document()->documentElement() == e))) {
944  if (style->display() == INLINE_TABLE) {
945  style->setDisplay(TABLE);
946  }
947 // else if (style->display() == INLINE_BOX)
948 // style->setDisplay(BOX);
949  else if (style->display() == LIST_ITEM) {
950  // It is a WinIE bug that floated list items lose their bullets, so we'll emulate the quirk,
951  // but only in quirks mode.
952  if (!strictParsing && style->floating() != FNONE) {
953  style->setDisplay(BLOCK);
954  }
955  } else {
956  style->setDisplay(BLOCK);
957  }
958  } else if (e && e->id() == ID_BUTTON && style->isOriginalDisplayInlineType()) {
959  // <button>s are supposed to be replaced elements; but we don't handle
960  // them as such (as they are rendered as CSS contexts, not natives
961  // with intrinsic sizes), so we must be careful not to make them fully
962  // inline, as that will display stuff like width:; so mutate inline-like
963  // display types into inline-block
964  style->setDisplay(INLINE_BLOCK);
965  }
966 
967  // After performing the display mutation, check our position. We do not honor position:relative on
968  // table rows and some other table displays. This is undefined behaviour in CSS2.1 (cf. 9.3.1)
969  if (style->position() == PRELATIVE) {
970  switch (style->display()) {
971  case TABLE_ROW_GROUP:
972  case TABLE_HEADER_GROUP:
973  case TABLE_FOOTER_GROUP:
974  case TABLE_ROW:
975  style->setPosition(PSTATIC);
976  default:
977  break;
978  }
979  }
980  }
981 
982  // Frames and framesets never honor position:relative or position:absolute. This is necessary to
983  // fix a crash where a site tries to position these objects.
984  if (e) {
985  // ignore display: none for <frame>
986  if (e->id() == ID_FRAME) {
987  style->setPosition(PSTATIC);
988  style->setDisplay(BLOCK);
989  } else if (e->id() == ID_FRAMESET) {
990  style->setPosition(PSTATIC);
991  }
992  }
993 
994  // Finally update our text decorations in effect, but don't allow text-decoration to percolate through
995  // tables, inline blocks, inline tables, or run-ins.
996  if (style->display() == TABLE || style->display() == INLINE_TABLE || style->display() == RUN_IN
997  || style->display() == INLINE_BLOCK /*|| style->display() == INLINE_BOX*/) {
998  style->setTextDecorationsInEffect(style->textDecoration());
999  } else {
1000  style->addToTextDecorationsInEffect(style->textDecoration());
1001  }
1002 
1003  // If either overflow value is not visible, change to auto.
1004  if (style->overflowX() == OMARQUEE && style->overflowY() != OMARQUEE) {
1005  style->setOverflowY(OMARQUEE);
1006  } else if (style->overflowY() == OMARQUEE && style->overflowX() != OMARQUEE) {
1007  style->setOverflowX(OMARQUEE);
1008  } else if (style->overflowX() == OVISIBLE && style->overflowY() != OVISIBLE) {
1009  style->setOverflowX(OAUTO);
1010  } else if (style->overflowY() == OVISIBLE && style->overflowX() != OVISIBLE) {
1011  style->setOverflowY(OAUTO);
1012  }
1013 
1014  // Table rows, sections and the table itself will support overflow:hidden and will ignore scroll/auto.
1015  // FIXME: Eventually table sections will support auto and scroll.
1016  if (style->display() == TABLE || style->display() == INLINE_TABLE ||
1017  style->display() == TABLE_ROW_GROUP || style->display() == TABLE_ROW) {
1018  if (style->overflowX() != OVISIBLE && style->overflowX() != OHIDDEN) {
1019  style->setOverflowX(OVISIBLE);
1020  }
1021  if (style->overflowY() != OVISIBLE && style->overflowY() != OHIDDEN) {
1022  style->setOverflowY(OVISIBLE);
1023  }
1024 
1025  // do comparable resets as Mozilla's nsStyleContext::ApplyStyleFixups
1026  // except they decided to do it only for center and right, for whatever strange reason. cf.#193093
1027  if (style->display() == TABLE && (style->textAlign() == KHTML_LEFT ||
1028  style->textAlign() == KHTML_RIGHT ||
1029  style->textAlign() == KHTML_CENTER)) {
1030  style->setTextAlign(TAAUTO);
1031  }
1032 
1033  }
1034 
1035  // Cull out any useless layers and also repeat patterns into additional layers.
1036  style->adjustBackgroundLayers();
1037 }
1038 
1039 void CSSStyleSelector::addInlineDeclarations(DOM::ElementImpl *e)
1040 {
1041  CSSStyleDeclarationImpl *inlineDecls = e->inlineStyleDecls();
1042  CSSStyleDeclarationImpl *nonCSSDecls = e->nonCSSStyleDecls();
1043  if (!inlineDecls && !nonCSSDecls) {
1044  return;
1045  }
1046 
1047  QList<CSSProperty *> *values = inlineDecls ? inlineDecls->values() : nullptr;
1048  QList<CSSProperty *> *nonCSSValues = nonCSSDecls ? nonCSSDecls->values() : nullptr;
1049  if (!values && !nonCSSValues) {
1050  return;
1051  }
1052 
1053  int firstLen = values ? values->count() : 0;
1054  int secondLen = nonCSSValues ? nonCSSValues->count() : 0;
1055  int totalLen = firstLen + secondLen;
1056 
1057  if (inlineProps.size() < totalLen) {
1058  inlineProps.resize(totalLen + 1);
1059  }
1060  propsToApply.reserveCapacity(propsToApply.size() + totalLen);
1061 
1062  bool inNonCSSDecls = false;
1063  CSSOrderedProperty *array = (CSSOrderedProperty *)inlineProps.data();
1064  for (int i = 0; i < totalLen; i++) {
1065  if (i == firstLen) {
1066  values = nonCSSValues;
1067  inNonCSSDecls = true;
1068  }
1069 
1070  CSSProperty *prop = values->at(i >= firstLen ? i - firstLen : i);
1071  Source source = Inline;
1072 
1073  if (prop->m_important) {
1074  source = InlineImportant;
1075  }
1076  if (inNonCSSDecls) {
1077  source = NonCSSHint;
1078  }
1079 
1080  bool first;
1081  // give special priority to font-xxx, color properties
1082  switch (prop->m_id) {
1083  case CSS_PROP_FONT_STYLE:
1084  case CSS_PROP_FONT_SIZE:
1085  case CSS_PROP_FONT_WEIGHT:
1086  case CSS_PROP_FONT_FAMILY:
1087  case CSS_PROP_FONT_VARIANT:
1088  case CSS_PROP_FONT:
1089  case CSS_PROP_COLOR:
1090  case CSS_PROP_DIRECTION:
1091  case CSS_PROP_DISPLAY:
1092  // these have to be applied first, because other properties use the computed
1093  // values of these properties.
1094  first = true;
1095  break;
1096  default:
1097  first = false;
1098  break;
1099  }
1100 
1101  array->prop = prop;
1102  array->pseudoId = RenderStyle::NOPSEUDO;
1103  array->selector = 0;
1104  array->position = i;
1105  array->priority = (!first << 30) | (source << 24);
1106  propsToApply.append(array++);
1107  }
1108 }
1109 
1110 // modified version of the one in kurl.cpp
1111 static void cleanpath(QString &path)
1112 {
1113  int pos;
1114  while ((pos = path.indexOf(QLatin1String("/../"))) != -1) {
1115  int prev = 0;
1116  if (pos > 0) {
1117  prev = path.lastIndexOf(QLatin1Char('/'), pos - 1);
1118  }
1119  // don't remove the host, i.e. http://foo.org/../foo.html
1120  if (prev < 0 || (prev > 3 && path.midRef(prev - 2, 3) == QLatin1String("://"))) {
1121  path.remove(pos, 3);
1122  } else
1123  // matching directory found ?
1124  {
1125  path.remove(prev, pos - prev + 3);
1126  }
1127  }
1128  pos = 0;
1129 
1130  // Don't remove "//" from an anchor identifier. -rjw
1131  // Set refPos to -2 to mean "I haven't looked for the anchor yet".
1132  // We don't want to waste a function call on the search for the anchor
1133  // in the vast majority of cases where there is no "//" in the path.
1134  int refPos = -2;
1135  while ((pos = path.indexOf(QLatin1String("//"), pos)) != -1) {
1136  if (refPos == -2) {
1137  refPos = path.indexOf(QLatin1Char('#'), 0);
1138  }
1139  if (refPos > 0 && pos >= refPos) {
1140  break;
1141  }
1142 
1143  if (pos == 0 || path[pos - 1] != QLatin1Char(':')) {
1144  path.remove(pos, 1);
1145  } else {
1146  pos += 2;
1147  }
1148  }
1149  while ((pos = path.indexOf(QLatin1String("/./"))) != -1) {
1150  path.remove(pos, 2);
1151  }
1152  //qCDebug(KHTML_LOG) << "checkPseudoState " << path;
1153 }
1154 
1155 static PseudoState checkPseudoState(const CSSStyleSelector::Encodedurl &encodedurl, DOM::ElementImpl *e)
1156 {
1157  if (e->id() != ID_A) {
1158  return PseudoNone;
1159  }
1160  DOMString attr = e->getAttribute(ATTR_HREF);
1161  if (attr.isNull()) {
1162  return PseudoNone;
1163  }
1164  QString url = QString::fromRawData(attr.unicode(), attr.length());
1165  if (!url.contains(QLatin1String("://"))) {
1166  if (url[0] == QLatin1Char('/')) {
1167  url = encodedurl.host + url;
1168  } else if (url[0] == QLatin1Char('#')) {
1169  url = encodedurl.file + url;
1170  } else {
1171  url = encodedurl.path + url;
1172  }
1173  cleanpath(url);
1174  }
1175  //completeURL( attr.string() );
1176  bool contains = KHTMLGlobal::vLinks()->contains(url);
1177  if (!contains && url.count(QLatin1Char('/')) == 2) {
1178  contains = KHTMLGlobal::vLinks()->contains(url + QLatin1Char('/'));
1179  }
1180  return contains ? PseudoVisited : PseudoLink;
1181 }
1182 
1183 // a helper function for parsing nth-arguments
1184 static bool matchNth(int count, const QString &nth)
1185 {
1186  if (nth.isEmpty()) {
1187  return false;
1188  }
1189  int a = 0;
1190  int b = 0;
1191  bool ok = true;
1192  if (nth == "odd") {
1193  a = 2;
1194  b = 1;
1195  } else if (nth == "even") {
1196  a = 2;
1197  b = 0;
1198  } else {
1199  int n = nth.indexOf('n'), l = nth.length();
1200  if (n != -1) {
1201  int i = 0, j, sgn = 0;
1202  // skip trailing spaces
1203  while (i < n && nth[i].isSpace()) {
1204  ++i;
1205  }
1206 
1207  // check sign
1208  if (nth[i] == '-') {
1209  sgn = -1;
1210  ++i;
1211  } else if (nth[i] == '+') {
1212  sgn = 1;
1213  ++i;
1214  }
1215 
1216  // skip spaces between '-'/'+' and digits
1217  while (i < n && nth[i].isSpace()) {
1218  ++i;
1219  }
1220 
1221  // find the number before 'n'
1222  for (j = i; j < n && nth[j].isDigit(); ++j) {}
1223 
1224  // do we have number or it's assumed to be 1
1225  a = (i < j) ? nth.mid(i, j - i).toInt(&ok) : 1;
1226  if (!ok) {
1227  return false;
1228  }
1229  if (sgn == -1) {
1230  a = -a;
1231  }
1232 
1233  // should have nothing between a and n except spaces
1234  for (; j < n; ++j) if (!nth[j].isSpace()) {
1235  return false;
1236  }
1237 
1238  // skip spaces
1239  for (i = n + 1; i < l && nth[i].isSpace(); ++i) {}
1240 
1241  // parse b
1242  if (i < l) {
1243  // must have sign
1244  if (nth[i] == '-') {
1245  sgn = -1;
1246  ++i;
1247  } else if (nth[i] == '+') {
1248  sgn = 1;
1249  ++i;
1250  } else {
1251  return false;
1252  }
1253 
1254  // skip spaces
1255  while (i < l && nth[i].isSpace()) {
1256  ++i;
1257  }
1258 
1259  // find digits
1260  for (j = i; j < l && nth[j].isDigit(); ++j) {}
1261 
1262  // must have digits
1263  if (j == i) {
1264  return false;
1265  }
1266 
1267  b = sgn * nth.mid(i, j - i).toInt(&ok);
1268  if (!ok) {
1269  return false;
1270  }
1271 
1272  // should be nothing except spaces in the end
1273  for (; j < l; ++j) if (!nth[j].isSpace()) {
1274  return false;
1275  }
1276  }
1277  } else {
1278  b = nth.toInt(&ok);
1279  if (!ok) {
1280  return false;
1281  }
1282  }
1283  }
1284  if (a == 0) {
1285  return b != 0 && count == b;
1286  }
1287  if (a > 0) {
1288  return (count < b) ? false : ((count - b) % a == 0);
1289  }
1290  // a < 0
1291  return (count > b) ? false : ((b - count) % (-a) == 0);
1292 }
1293 
1294 // Recursively work the combinator to compute static attribute dependency, similar to
1295 //structure of checkSubSelectors
1296 static void precomputeAttributeDependenciesAux(DOM::DocumentImpl *doc, DOM::CSSSelector *sel, bool isAncestor, bool isSubject)
1297 {
1298  if (sel->attrLocalName.id()) {
1299  uint selAttr = makeId(sel->attrNamespace.id(), sel->attrLocalName.id());
1300  // Sets up global dependencies of attributes
1301  if (isSubject) {
1302  doc->dynamicDomRestyler().addDependency(selAttr, PersonalDependency);
1303  } else if (isAncestor) {
1304  doc->dynamicDomRestyler().addDependency(selAttr, AncestorDependency);
1305  } else {
1306  doc->dynamicDomRestyler().addDependency(selAttr, PredecessorDependency);
1307  }
1308  }
1309  if (sel->match == CSSSelector::PseudoClass) {
1310  switch (sel->pseudoType()) {
1311  case CSSSelector::PseudoNot:
1312  precomputeAttributeDependenciesAux(doc, sel->simpleSelector, isAncestor, true);
1313  break;
1314  default:
1315  break;
1316  }
1317  }
1318  CSSSelector::Relation relation = KDE_CAST_BF_ENUM(CSSSelector::Relation, sel->relation);
1319  sel = sel->tagHistory;
1320  if (!sel) {
1321  return;
1322  }
1323 
1324  switch (relation) {
1325  case CSSSelector::Descendant:
1326  case CSSSelector::Child:
1327  precomputeAttributeDependenciesAux(doc, sel, true, false);
1328  break;
1329  case CSSSelector::IndirectAdjacent:
1330  case CSSSelector::DirectAdjacent:
1331  precomputeAttributeDependenciesAux(doc, sel, false, false);
1332  break;
1333  case CSSSelector::SubSelector:
1334  precomputeAttributeDependenciesAux(doc, sel, isAncestor, isSubject);
1335  break;
1336  }
1337 }
1338 
1339 void CSSStyleSelector::precomputeAttributeDependencies(DOM::DocumentImpl *doc, DOM::CSSSelector *sel)
1340 {
1341  precomputeAttributeDependenciesAux(doc, sel, false, true);
1342 }
1343 
1344 // Recursive check of selectors and combinators
1345 // It can return 3 different values:
1346 // * SelectorMatches - the selector is match for the node e
1347 // * SelectorFailsLocal - the selector fails for the node e
1348 // * SelectorFails - the selector fails for e and any sibling or ancestor of e
1349 CSSStyleSelector::SelectorMatch CSSStyleSelector::checkSelector(DOM::CSSSelector *sel, DOM::ElementImpl *e, bool isAncestor, bool isSubSelector)
1350 {
1351  // The simple selector has to match
1352  if (!checkSimpleSelector(sel, e, isAncestor, isSubSelector)) {
1353  return SelectorFailsLocal;
1354  }
1355 
1356  // The rest of the selectors has to match
1357  CSSSelector::Relation relation = KDE_CAST_BF_ENUM(CSSSelector::Relation, sel->relation);
1358 
1359  // Prepare next sel
1360  sel = sel->tagHistory;
1361  if (!sel) {
1362  return SelectorMatches;
1363  }
1364 
1365  switch (relation) {
1366  case CSSSelector::Descendant: {
1367  // if ancestor of original element we may want to check prepared caches first
1368  // whether given selector could possibly have a match
1369  // if no we return SelectorFails result right away and avoid going up the tree
1370  if (isAncestor) {
1371  int id = sel->tagLocalName.id();
1372  if (id != anyLocalName && !tagCache.contains(id)) {
1373  return SelectorFails;
1374  }
1375  if (sel->match == CSSSelector::Class && !classCache.contains((quintptr)sel->value.impl())) {
1376  return SelectorFails;
1377  }
1378  if (sel->match == CSSSelector::Id && !idCache.contains((quintptr)sel->value.impl())) {
1379  return SelectorFails;
1380  }
1381  }
1382 
1383  while (true) {
1384  DOM::NodeImpl *n = e->parentNode();
1385  if (!n || !n->isElementNode()) {
1386  return SelectorFails;
1387  }
1388  e = static_cast<ElementImpl *>(n);
1389  SelectorMatch match = checkSelector(sel, e, true);
1390  if (match != SelectorFailsLocal) {
1391  return match;
1392  }
1393  }
1394  break;
1395  }
1396  case CSSSelector::Child: {
1397  DOM::NodeImpl *n = e->parentNode();
1398  if (!strictParsing)
1399  while (n && n->implicitNode()) {
1400  n = n->parentNode();
1401  }
1402  if (!n || !n->isElementNode()) {
1403  return SelectorFails;
1404  }
1405  e = static_cast<ElementImpl *>(n);
1406  return checkSelector(sel, e, true);
1407  }
1408  case CSSSelector::IndirectAdjacent: {
1409  // Sibling selectors always generate structural dependencies
1410  // because newly inserted element might fullfill them.
1411  if (e->parentNode() && e->parentNode()->isElementNode()) {
1412  addDependency(StructuralDependency, static_cast<ElementImpl *>(e->parentNode()));
1413  }
1414  while (true) {
1415  DOM::NodeImpl *n = e->previousSibling();
1416  while (n && !n->isElementNode()) {
1417  n = n->previousSibling();
1418  }
1419  if (!n) {
1420  return SelectorFailsLocal;
1421  }
1422  e = static_cast<ElementImpl *>(n);
1423  SelectorMatch match = checkSelector(sel, e, false);
1424  if (match != SelectorFailsLocal) {
1425  return match;
1426  }
1427  };
1428  break;
1429  }
1430  case CSSSelector::DirectAdjacent: {
1431  if (e->parentNode() && e->parentNode()->isElementNode()) {
1432  addDependency(StructuralDependency, static_cast<ElementImpl *>(e->parentNode()));
1433  }
1434  DOM::NodeImpl *n = e->previousSibling();
1435  while (n && !n->isElementNode()) {
1436  n = n->previousSibling();
1437  }
1438  if (!n) {
1439  return SelectorFailsLocal;
1440  }
1441  e = static_cast<ElementImpl *>(n);
1442  return checkSelector(sel, e, false);
1443  }
1444  case CSSSelector::SubSelector:
1445  return checkSelector(sel, e, isAncestor, true);
1446  }
1447  assert(false); // never reached
1448  return SelectorFails;
1449 }
1450 
1451 void CSSStyleSelector::checkSelector(int selIndex, DOM::ElementImpl *e)
1452 {
1453  assert(e == element); // yes, actually
1454 
1455  dynamicPseudo = RenderStyle::NOPSEUDO;
1456 
1457  selectorCache[ selIndex ].state = Invalid;
1458  CSSSelector *sel = selectors[ selIndex ];
1459 
1460  // Check the selector
1461  SelectorMatch match = checkSelector(sel, e, true);
1462  if (match != SelectorMatches) {
1463  return;
1464  }
1465 
1466  if (dynamicPseudo != RenderStyle::NOPSEUDO) {
1467  selectorCache[selIndex].state = AppliesPseudo;
1468  selectors[ selIndex ]->pseudoId = dynamicPseudo;
1469  } else {
1470  selectorCache[ selIndex ].state = Applies;
1471  }
1472  //qDebug( "selector %d applies", selIndex );
1473  //selectors[ selIndex ]->print();
1474  return;
1475 }
1476 
1477 bool CSSStyleSelector::isMatchedByAnySelector(DOM::ElementImpl *e, const QList<DOM::CSSSelector *> &sels)
1478 {
1479  bool inited = false;
1480 
1481  quint16 elementTagId = localNamePart(e->id());
1482 
1483  // ### this may introduce extraneous restyling dependencies
1484  for (int i = 0; i < sels.size(); ++i) {
1485  DOM::CSSSelector *sel = sels[i];
1486  quint16 tag = sel->tagLocalName.id();
1487  if (elementTagId == tag || tag == anyLocalName) {
1488  if (!inited) {
1489  prepareToMatchElement(e, false);
1490  inited = true;
1491  }
1492 
1493  dynamicPseudo = RenderStyle::NOPSEUDO;
1494  SelectorMatch match = checkSelector(sel, e, true);
1495 
1496  if (match == SelectorMatches && dynamicPseudo == RenderStyle::NOPSEUDO) {
1497  return true;
1498  }
1499  }
1500  }
1501 
1502  return false;
1503 }
1504 
1505 void CSSStyleSelector::addDependency(int dependencyType, ElementImpl *dependency)
1506 {
1507  if (!rememberDependencies) {
1508  return;
1509  }
1510  element->document()->dynamicDomRestyler().addDependency(element, dependency, (StructuralDependencyType)dependencyType);
1511 }
1512 
1513 bool CSSStyleSelector::checkSimpleSelector(DOM::CSSSelector *sel, DOM::ElementImpl *e, bool isAncestor, bool isSubSelector)
1514 {
1515  uint selTag = makeId(sel->tagNamespace.id(), sel->tagLocalName.id());
1516  if (selTag != anyQName) {
1517  int eltID = e->id();
1518  quint16 localName = localNamePart(eltID);
1519  quint16 ns = namespacePart(eltID);
1520  quint16 selLocalName = localNamePart(selTag);
1521  quint16 selNS = namespacePart(selTag);
1522 
1523  // match on local
1524  if (selLocalName != anyLocalName && localName != selLocalName) {
1525  return false;
1526  }
1527  // match on namespace
1528  if (selNS != anyNamespace && ns != selNS) {
1529  return false;
1530  }
1531  }
1532 
1533  uint selAttr = makeId(sel->attrNamespace.id(), sel->attrLocalName.id());
1534  if (selAttr) {
1535  // "class" is special attribute which is pre-parsed for fast look-ups
1536  // avoid ElementImpl::getAttributeImpl here, as we don't need it
1537  if (sel->match == CSSSelector::Class) {
1538  return e->hasClass() && e->classNames().contains(sel->value);
1539  }
1540 
1541  DOMStringImpl *value = e->getAttributeImplById(selAttr);
1542  if (!value) {
1543  return false; // attribute is not set
1544  }
1545 
1546  // attributes are always case-sensitive in XHTML
1547  // attributes are sometimes case-sensitive in HTML
1548  bool caseSensitive = (e->document()->htmlMode() == DocumentImpl::XHtml) || caseSensitiveAttr(selAttr);
1549 
1550  switch (sel->match) {
1551  case CSSSelector::Set:
1552  // True if we make it this far
1553  break;
1554  case CSSSelector::Id:
1555  // treat id selectors as case-sensitive in HTML strict
1556  // for compatibility reasons
1557  caseSensitive = (e->document()->htmlMode() == DocumentImpl::XHtml) || strictParsing;
1558  // no break
1559  case CSSSelector::Exact:
1560  return caseSensitive ?
1561  !strcmp(sel->value.impl(), value) :
1562  !strcasecmp(sel->value.impl(), value);
1563  break;
1564  case CSSSelector::List: {
1565  int sel_len = sel->value.length();
1566  int val_len = value->length();
1567  // Be smart compare on length first
1568  if ((!sel_len && !val_len) || sel_len > val_len) {
1569  return false;
1570  }
1571  // Selector string may not contain spaces
1572  if ((selAttr != ATTR_CLASS || e->hasClass()) && sel->value.string().find(' ') != -1) {
1573  return false;
1574  }
1575  if (sel_len == val_len)
1576  return caseSensitive ?
1577  !strcmp(sel->value.impl(), value) :
1578  !strcasecmp(sel->value.impl(), value);
1579  // else the value is longer and can be a list
1580 
1581  QChar *sel_uc = sel->value.string().unicode();
1582  QChar *val_uc = value->unicode();
1583 
1584  QString sel_str = QString::fromRawData(sel_uc, sel_len);
1585  QString val_str = QString::fromRawData(val_uc, val_len);
1586 
1587  int pos = 0;
1588  for (;;) {
1589  pos = val_str.indexOf(sel_str, pos, caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
1590  if (pos == -1) {
1591  return false;
1592  }
1593  if (pos == 0 || val_uc[pos - 1].isSpace()) {
1594  int endpos = pos + sel_len;
1595  if (endpos >= val_len || val_uc[endpos].isSpace()) {
1596  break; // We have a match.
1597  }
1598  }
1599  ++pos;
1600  }
1601  break;
1602  }
1603  case CSSSelector::Contain: {
1604  //qCDebug(KHTML_LOG) << "checking for contains match";
1605  QString val_str = QString::fromRawData(value->unicode(), value->length());
1606  QString sel_str = QString::fromRawData(sel->value.string().unicode(), sel->value.length());
1607  return val_str.contains(sel_str, caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) && !sel_str.isEmpty();
1608  }
1609  case CSSSelector::Begin: {
1610  //qCDebug(KHTML_LOG) << "checking for beginswith match";
1611  DOMStringImpl *selValue = sel->value.impl();
1612  return selValue && selValue->length() && value->startsWith(selValue, caseSensitive ? DOM::CaseSensitive : DOM::CaseInsensitive);
1613  }
1614  case CSSSelector::End: {
1615  //qCDebug(KHTML_LOG) << "checking for endswith match";
1616  DOMStringImpl *selValue = sel->value.impl();
1617  return selValue && selValue->length() && value->endsWith(selValue, caseSensitive ? DOM::CaseSensitive : DOM::CaseInsensitive);
1618  }
1619  case CSSSelector::Hyphen: {
1620  //qCDebug(KHTML_LOG) << "checking for hyphen match";
1621  DOMStringImpl *selValue = sel->value.impl();
1622  if (value->length() < selValue->length()) {
1623  return false;
1624  }
1625  // Check if value begins with selStr:
1626  if (!value->startsWith(selValue, caseSensitive ? DOM::CaseSensitive : DOM::CaseInsensitive)) {
1627  return false;
1628  }
1629  // It does. Check for exact match or following '-':
1630  return value->length() == selValue->length() || (*value)[selValue->length()].unicode() == '-';
1631  }
1632  case CSSSelector::PseudoClass:
1633  case CSSSelector::PseudoElement:
1634  case CSSSelector::None:
1635  break;
1636  }
1637  }
1638 
1639  if (sel->match == CSSSelector::PseudoClass || sel->match == CSSSelector::PseudoElement) {
1640  switch (sel->pseudoType()) {
1641  // Pseudo classes:
1642  case CSSSelector::PseudoEmpty: {
1643  addDependency(BackwardsStructuralDependency, e);
1644  // If e is not closed yet we don't know the number of children
1645  if (!e->closed()) {
1646  return false;
1647  }
1648  NodeImpl *t = e->firstChild();
1649 
1650  // check for empty text nodes and comments
1651  while (t && (t->nodeType() == Node::COMMENT_NODE ||
1652  (t->isTextNode() && static_cast<TextImpl *>(t)->length() == 0))) {
1653  t = t->nextSibling();
1654  }
1655 
1656  return !t;
1657  break;
1658  }
1659  case CSSSelector::PseudoFirstChild: {
1660  // first-child matches the first child that is an element!
1661  if (e->parentNode() && e->parentNode()->isElementNode()) {
1662  // Handle dynamic DOM changes
1663  addDependency(StructuralDependency, static_cast<ElementImpl *>(e->parentNode()));
1664  DOM::NodeImpl *n = e->previousSibling();
1665  while (n && !n->isElementNode()) {
1666  n = n->previousSibling();
1667  }
1668  if (!n) {
1669  return true;
1670  }
1671  }
1672  break;
1673  }
1674  case CSSSelector::PseudoLastChild: {
1675  // last-child matches the last child that is an element!
1676  if (e->parentNode() && e->parentNode()->isElementNode()) {
1677  // Handle unfinished parsing and dynamic DOM changes
1678  addDependency(BackwardsStructuralDependency, static_cast<ElementImpl *>(e->parentNode()));
1679  if (!e->parentNode()->closed()) {
1680 // qCDebug(KHTML_LOG) << e->nodeName().string() << "::last-child: Parent unclosed";
1681  return false;
1682  }
1683  DOM::NodeImpl *n = e->nextSibling();
1684  while (n && !n->isElementNode()) {
1685  n = n->nextSibling();
1686  }
1687  if (!n) {
1688  return true;
1689  }
1690  }
1691  break;
1692  }
1693  case CSSSelector::PseudoOnlyChild: {
1694  // If both first-child and last-child apply, then only-child applies.
1695  if (e->parentNode() && e->parentNode()->isElementNode()) {
1696  addDependency(BackwardsStructuralDependency, static_cast<ElementImpl *>(e->parentNode()));
1697  if (!e->parentNode()->closed()) {
1698  return false;
1699  }
1700  DOM::NodeImpl *n = e->previousSibling();
1701  while (n && !n->isElementNode()) {
1702  n = n->previousSibling();
1703  }
1704  if (!n) {
1705  n = e->nextSibling();
1706  while (n && !n->isElementNode()) {
1707  n = n->nextSibling();
1708  }
1709  if (!n) {
1710  return true;
1711  }
1712  }
1713  }
1714  break;
1715  }
1716  case CSSSelector::PseudoNthChild: {
1717  // nth-child matches every (a*n+b)th element!
1718  if (e->parentNode() && e->parentNode()->isElementNode()) {
1719  addDependency(StructuralDependency, static_cast<ElementImpl *>(e->parentNode()));
1720  int count = 1;
1721  DOM::NodeImpl *n = e->previousSibling();
1722  while (n) {
1723  if (n->isElementNode()) {
1724  count++;
1725  }
1726  n = n->previousSibling();
1727  }
1728 // qCDebug(KHTML_LOG) << "NthChild " << count << "=" << sel->string_arg;
1729  if (matchNth(count, sel->string_arg.string())) {
1730  return true;
1731  }
1732  }
1733  break;
1734  }
1735  case CSSSelector::PseudoNthLastChild: {
1736  if (e->parentNode() && e->parentNode()->isElementNode()) {
1737  addDependency(BackwardsStructuralDependency, static_cast<ElementImpl *>(e->parentNode()));
1738  if (!e->parentNode()->closed()) {
1739  return false;
1740  }
1741  int count = 1;
1742  DOM::NodeImpl *n = e->nextSibling();
1743  while (n) {
1744  if (n->isElementNode()) {
1745  count++;
1746  }
1747  n = n->nextSibling();
1748  }
1749 // qCDebug(KHTML_LOG) << "NthLastChild " << count << "=" << sel->string_arg;
1750  if (matchNth(count, sel->string_arg.string())) {
1751  return true;
1752  }
1753  }
1754  break;
1755  }
1756  case CSSSelector::PseudoFirstOfType: {
1757  // first-of-type matches the first element of its type!
1758  if (e->parentNode() && e->parentNode()->isElementNode()) {
1759  addDependency(StructuralDependency, static_cast<ElementImpl *>(e->parentNode()));
1760  const DOMString &type = e->tagName();
1761  DOM::NodeImpl *n = e->previousSibling();
1762  while (n) {
1763  if (n->isElementNode())
1764  if (static_cast<ElementImpl *>(n)->tagName() == type) {
1765  break;
1766  }
1767  n = n->previousSibling();
1768  }
1769  if (!n) {
1770  return true;
1771  }
1772  }
1773  break;
1774  }
1775  case CSSSelector::PseudoLastOfType: {
1776  // last-child matches the last child that is an element!
1777  if (e->parentNode() && e->parentNode()->isElementNode()) {
1778  addDependency(BackwardsStructuralDependency, static_cast<ElementImpl *>(e->parentNode()));
1779  if (!e->parentNode()->closed()) {
1780  return false;
1781  }
1782  const DOMString &type = e->tagName();
1783  DOM::NodeImpl *n = e->nextSibling();
1784  while (n) {
1785  if (n->isElementNode())
1786  if (static_cast<ElementImpl *>(n)->tagName() == type) {
1787  break;
1788  }
1789  n = n->nextSibling();
1790  }
1791  if (!n) {
1792  return true;
1793  }
1794  }
1795  break;
1796  }
1797  case CSSSelector::PseudoOnlyOfType: {
1798  // If both first-of-type and last-of-type apply, then only-of-type applies.
1799  if (e->parentNode() && e->parentNode()->isElementNode()) {
1800  addDependency(BackwardsStructuralDependency, static_cast<ElementImpl *>(e->parentNode()));
1801  if (!e->parentNode()->closed()) {
1802  return false;
1803  }
1804  const DOMString &type = e->tagName();
1805  DOM::NodeImpl *n = e->previousSibling();
1806  while (n && !(n->isElementNode() && static_cast<ElementImpl *>(n)->tagName() == type)) {
1807  n = n->previousSibling();
1808  }
1809  if (!n) {
1810  n = e->nextSibling();
1811  while (n && !(n->isElementNode() && static_cast<ElementImpl *>(n)->tagName() == type)) {
1812  n = n->nextSibling();
1813  }
1814  if (!n) {
1815  return true;
1816  }
1817  }
1818  }
1819  break;
1820  }
1821  case CSSSelector::PseudoNthOfType: {
1822  // nth-of-type matches every (a*n+b)th element of this type!
1823  if (e->parentNode() && e->parentNode()->isElementNode()) {
1824  addDependency(StructuralDependency, static_cast<ElementImpl *>(e->parentNode()));
1825  int count = 1;
1826  const DOMString &type = e->tagName();
1827  DOM::NodeImpl *n = e->previousSibling();
1828  while (n) {
1829  if (n->isElementNode() && static_cast<ElementImpl *>(n)->tagName() == type) {
1830  count++;
1831  }
1832  n = n->previousSibling();
1833  }
1834 // qCDebug(KHTML_LOG) << "NthOfType " << count << "=" << sel->string_arg;
1835  if (matchNth(count, sel->string_arg.string())) {
1836  return true;
1837  }
1838  }
1839  break;
1840  }
1841  case CSSSelector::PseudoNthLastOfType: {
1842  if (e->parentNode() && e->parentNode()->isElementNode()) {
1843  addDependency(BackwardsStructuralDependency, static_cast<ElementImpl *>(e->parentNode()));
1844  if (!e->parentNode()->closed()) {
1845  return false;
1846  }
1847  int count = 1;
1848  const DOMString &type = e->tagName();
1849  DOM::NodeImpl *n = e->nextSibling();
1850  while (n) {
1851  if (n->isElementNode() && static_cast<ElementImpl *>(n)->tagName() == type) {
1852  count++;
1853  }
1854  n = n->nextSibling();
1855  }
1856 // qCDebug(KHTML_LOG) << "NthLastOfType " << count << "=" << sel->string_arg;
1857  if (matchNth(count, sel->string_arg.string())) {
1858  return true;
1859  }
1860  }
1861  break;
1862  }
1863  case CSSSelector::PseudoTarget:
1864  if (e == e->document()->getCSSTarget()) {
1865  return true;
1866  }
1867  break;
1868  case CSSSelector::PseudoRoot:
1869  if (e == e->document()->documentElement()) {
1870  return true;
1871  }
1872  break;
1873  case CSSSelector::PseudoLink:
1874  if (e == element) {
1875  // cache pseudoState
1876  if (pseudoState == PseudoUnknown) {
1877  pseudoState = checkPseudoState(encodedurl, e);
1878  }
1879  if (pseudoState == PseudoLink) {
1880  return true;
1881  }
1882  } else {
1883  return checkPseudoState(encodedurl, e) == PseudoLink;
1884  }
1885  break;
1886  case CSSSelector::PseudoVisited:
1887  if (e == element) {
1888  // cache pseudoState
1889  if (pseudoState == PseudoUnknown) {
1890  pseudoState = checkPseudoState(encodedurl, e);
1891  }
1892  if (pseudoState == PseudoVisited) {
1893  return true;
1894  }
1895  } else {
1896  return checkPseudoState(encodedurl, e) == PseudoVisited;
1897  }
1898  break;
1899  case CSSSelector::PseudoHover: {
1900  // If we're in quirks mode, then *:hover should only match focusable elements.
1901  if (strictParsing || (selTag != anyQName) || isSubSelector || e->isFocusable()) {
1902  addDependency(HoverDependency, e);
1903 
1904  if (e->hovered()) {
1905  return true;
1906  }
1907  }
1908  break;
1909  }
1910  case CSSSelector::PseudoActive:
1911  // If we're in quirks mode, then *:active should only match focusable elements
1912  if (strictParsing || (selTag != anyQName) || isSubSelector || e->isFocusable()) {
1913  addDependency(ActiveDependency, e);
1914 
1915  if (e->active()) {
1916  return true;
1917  }
1918  }
1919  break;
1920  case CSSSelector::PseudoFocus:
1921  if (e != element && e->isFocusable()) {
1922  // *:focus is a default style, no need to track it.
1923  addDependency(OtherStateDependency, e);
1924  }
1925  if (e->focused()) {
1926  return true;
1927  }
1928  break;
1929  case CSSSelector::PseudoLang: {
1930  // Set dynamic attribute dependency
1931  if (e == element) {
1932  e->document()->dynamicDomRestyler().addDependency(ATTR_LANG, PersonalDependency);
1933  e->document()->dynamicDomRestyler().addDependency(ATTR_LANG, AncestorDependency);
1934  } else if (isAncestor) {
1935  e->document()->dynamicDomRestyler().addDependency(ATTR_LANG, AncestorDependency);
1936  } else {
1937  e->document()->dynamicDomRestyler().addDependency(ATTR_LANG, PredecessorDependency);
1938  }
1939  // ### check xml:lang attribute in XML and XHTML documents
1940  DOMStringImpl *value = e->getAttributeImplById(ATTR_LANG);
1941  // The LANG attribute is inherited like a property
1942  NodeImpl *n = e->parent();
1943  while (n && !(value && value->length())) {
1944  if (n->isElementNode()) {
1945  value = static_cast<ElementImpl *>(n)->getAttributeImplById(ATTR_LANG);
1946  } else if (n->isDocumentNode()) {
1947  value = static_cast<DocumentImpl *>(n)->contentLanguage().implementation();
1948  }
1949  n = n->parent();
1950  }
1951  if (!(value && value->length())) {
1952  return false;
1953  }
1954 
1955  DOMStringImpl *langValue = sel->string_arg.implementation();
1956  if (value->length() < langValue->length()) {
1957  return false;
1958  }
1959  if (!value->startsWith(langValue, DOM::CaseInsensitive)) {
1960  return false;
1961  }
1962  if (value->length() != langValue->length() && (*value)[langValue->length()].unicode() != '-') {
1963  return false;
1964  }
1965  return true;
1966  }
1967  case CSSSelector::PseudoNot: {
1968  // check the simple selector
1969  for (CSSSelector *subSel = sel->simpleSelector; subSel;
1970  subSel = subSel->tagHistory) {
1971  // :not cannot nest. I don't really know why this is a restriction in CSS3,
1972  // but it is, so let's honor it.
1973  if (subSel->simpleSelector) {
1974  break;
1975  }
1976  if (!checkSimpleSelector(subSel, e, isAncestor, true)) {
1977  return true;
1978  }
1979  }
1980  break;
1981  }
1982  case CSSSelector::PseudoEnabled: {
1983  if (e->isGenericFormElement()) {
1984  addDependency(OtherStateDependency, e);
1985  HTMLGenericFormElementImpl *form;
1986  form = static_cast<HTMLGenericFormElementImpl *>(e);
1987  return !form->disabled() && !form->isHiddenInput();
1988  }
1989  break;
1990  }
1991  case CSSSelector::PseudoDisabled: {
1992  if (e->isGenericFormElement()) {
1993  addDependency(OtherStateDependency, e);
1994  HTMLGenericFormElementImpl *form;
1995  form = static_cast<HTMLGenericFormElementImpl *>(e);
1996  return form->disabled() && !form->isHiddenInput();
1997  }
1998  break;
1999  }
2000  case CSSSelector::PseudoContains: {
2001  if (e->isHTMLElement()) {
2002  addDependency(BackwardsStructuralDependency, e);
2003  if (!e->closed()) {
2004  return false;
2005  }
2006  HTMLElementImpl *elem;
2007  elem = static_cast<HTMLElementImpl *>(e);
2008  DOMString s = elem->innerText();
2009  QString selStr = sel->string_arg.string();
2010 // qCDebug(KHTML_LOG) << ":contains(\"" << selStr << "\")" << " on \"" << s << "\"";
2011  return s.string().contains(selStr);
2012  }
2013  break;
2014  }
2015  case CSSSelector::PseudoDefault: {
2016  if (e->isGenericFormElement()) {
2017  return static_cast<HTMLGenericFormElementImpl *>(e)->isDefault();
2018  }
2019  break;
2020  }
2021  case CSSSelector::PseudoReadWrite:
2022  if (e->isGenericFormElement()) {
2023  HTMLGenericFormElementImpl *fe = static_cast<HTMLGenericFormElementImpl *>(e);
2024  // no need for dependency tracking - readonly attr change always triggers a recalc
2025  return fe->isEditable() && !fe->readOnly();
2026  } else {
2027  // ### contentEditable should either not be accessible from CSS, or should not trigger selection
2028  // by this pseudo class. See with CSS WG.
2029  return e->isContentEditable();
2030  }
2031  break;
2032  case CSSSelector::PseudoReadOnly:
2033  if (e->isGenericFormElement()) {
2034  HTMLGenericFormElementImpl *fe = static_cast<HTMLGenericFormElementImpl *>(e);
2035  // no need for dependency tracking - readonly attr change always triggers a recalc
2036  return !fe->isEditable() || fe->readOnly();
2037  } else {
2038  // ### contentEditable should either not be accessible from CSS, or should not trigger selection
2039  // by this pseudo class. See with CSS WG.
2040  return !e->isContentEditable();
2041  }
2042  break;
2043  case CSSSelector::PseudoChecked: {
2044  if (e->isHTMLElement() && e->id() == ID_INPUT) {
2045  HTMLInputElementImpl *ie = static_cast<HTMLInputElementImpl *>(e);
2046  addDependency(OtherStateDependency, e);
2047  return (ie->checked() &&
2048  (ie->inputType() == HTMLInputElementImpl::RADIO || ie->inputType() == HTMLInputElementImpl::CHECKBOX));
2049  }
2050  return false;
2051  }
2052  case CSSSelector::PseudoIndeterminate: {
2053 #if 0
2054  if (e->isHTMLElement() && e->id() == ID_INPUT) {
2055  return (static_cast<HTMLInputElementImpl *>(e)->indeterminate() &&
2056  !static_cast<HTMLInputElementImpl *>(e)->checked());
2057  }
2058  return false;
2059 #endif
2060  }
2061  case CSSSelector::PseudoOther:
2062  break;
2063 
2064  // Pseudo-elements:
2065  case CSSSelector::PseudoFirstLine:
2066  case CSSSelector::PseudoFirstLetter:
2067  case CSSSelector::PseudoSelection:
2068  case CSSSelector::PseudoBefore:
2069  case CSSSelector::PseudoAfter:
2070  case CSSSelector::PseudoMarker:
2071  case CSSSelector::PseudoReplaced:
2072  // Pseudo-elements can only apply to subject
2073  if (e == element) {
2074  // Pseudo-elements has to be the last sub-selector on subject
2075  if (sel->tagHistory && sel->relation == CSSSelector::SubSelector) {
2076  return false;
2077  }
2078 
2079  assert(dynamicPseudo == RenderStyle::NOPSEUDO);
2080 
2081  switch (sel->pseudoType()) {
2082  case CSSSelector::PseudoFirstLine:
2083  dynamicPseudo = RenderStyle::FIRST_LINE;
2084  break;
2085  case CSSSelector::PseudoFirstLetter:
2086  dynamicPseudo = RenderStyle::FIRST_LETTER;
2087  break;
2088  case CSSSelector::PseudoSelection:
2089  dynamicPseudo = RenderStyle::SELECTION;
2090  break;
2091  case CSSSelector::PseudoBefore:
2092  dynamicPseudo = RenderStyle::BEFORE;
2093  break;
2094  case CSSSelector::PseudoAfter:
2095  dynamicPseudo = RenderStyle::AFTER;
2096  break;
2097  case CSSSelector::PseudoMarker:
2098  dynamicPseudo = RenderStyle::MARKER;
2099  break;
2100  case CSSSelector::PseudoReplaced:
2101  dynamicPseudo = RenderStyle::REPLACED;
2102  break;
2103  default:
2104  assert(false);
2105  }
2106  return true;
2107  }
2108  break;
2109  case CSSSelector::PseudoNotParsed:
2110  assert(false);
2111  break;
2112  }
2113  return false;
2114  }
2115  // ### add the rest of the checks...
2116  return true;
2117 }
2118 
2119 void CSSStyleSelector::clearLists()
2120 {
2121  delete[] selectors;
2122  if (selectorCache) {
2123  delete[] selectorCache;
2124  delete[] nextSimilarSelector;
2125  }
2126  if (propertiesBuffer) {
2127  delete[] propertiesBuffer;
2128  delete[] nextPropertyIndexes;
2129  }
2130  selectors = nullptr;
2131  propertiesBuffer = nullptr;
2132  selectorCache = nullptr;
2133  nextPropertyIndexes = nullptr;
2134 
2135  classSelector.clear();
2136  idSelector.clear();
2137  tagSelector.clear();
2138 }
2139 
2140 void CSSStyleSelector::setupDefaultRootStyle(DOM::DocumentImpl *d)
2141 {
2142  assert(m_fontSizes.size());
2143 
2144  // We only care about setting up a default font
2145  // that the media queries module can use early for
2146  // computing its font-relative units (e.g.em/ex)
2147  if (d) {
2148  // setup some variables needed by applyRule
2149  logicalDpiY = d->logicalDpiY();
2150  if (d->view()) {
2151  view = d->view();
2152  }
2153  if (view) {
2154  part = view->part();
2155  }
2156  if (part) {
2157  settings = part->settings();
2158  }
2159  }
2160  parentNode = nullptr;
2161  delete m_rootDefaultStyle;
2162  m_rootDefaultStyle = style = new RenderStyle();
2163  CSSInitialValueImpl i(true);
2164  applyRule(CSS_PROP_FONT_SIZE, &i);
2165  style->htmlFont().update(logicalDpiY);
2166  fontDirty = false;
2167 }
2168 
2169 void CSSStyleSelector::buildLists()
2170 {
2171  clearLists();
2172  // collect all selectors and Properties in lists. Then transfer them to the array for faster lookup.
2173 
2174  QList<CSSSelector *> selectorList;
2175  CSSOrderedPropertyList propertyList;
2176  WTF::HashMap<CSSSelector *, int> selectorsCache;
2177 
2178  if (defaultPrintStyle && m_medium->mediaTypeMatchSpecific("print"))
2179  defaultPrintStyle->collect(&selectorsCache, &selectorList, &propertyList, Default,
2180  Default);
2181  else if (defaultStyle) defaultStyle->collect(&selectorsCache, &selectorList, &propertyList,
2182  Default, Default);
2183 
2184  if (!strictParsing && defaultQuirksStyle) {
2185  defaultQuirksStyle->collect(&selectorsCache, &selectorList, &propertyList, Default, Default);
2186  }
2187 
2188  if (userStyle) {
2189  userStyle->collect(&selectorsCache, &selectorList, &propertyList, User, UserImportant);
2190  }
2191 
2192  if (defaultNonCSSHintsStyle) {
2193  defaultNonCSSHintsStyle->collect(&selectorsCache, &selectorList, &propertyList, NonCSSHint, NonCSSHint);
2194  }
2195 
2196  // Implicit styles are gathered from hidden, dynamically generated, implicit stylesheets.
2197  // They have the same priority as presentational attributes.
2198  if (implicitStyle) {
2199  implicitStyle->collect(&selectorsCache, &selectorList, &propertyList, NonCSSHint, NonCSSHint);
2200  }
2201 
2202  if (authorStyle) {
2203  authorStyle->collect(&selectorsCache, &selectorList, &propertyList, Author, AuthorImportant);
2204  }
2205 
2206  selectors_size = selectorList.count();
2207  selectors = new CSSSelector *[selectors_size];
2208  CSSSelector **sel = selectors;
2209  for (QListIterator<CSSSelector *> sit(selectorList); sit.hasNext(); ++sel) {
2210  *sel = sit.next();
2211  }
2212 
2213  selectorCache = new SelectorCache[selectors_size];
2214  for (unsigned int i = 0; i < selectors_size; i++) {
2215  selectorCache[i].state = Unknown;
2216  selectorCache[i].firstPropertyIndex = propertyList.size();
2217  }
2218 
2219  // do some pre-compution to make styleForElement faster:
2220  // 1. class selectors: put in hash by selector value
2221  // 2. the same goes for id selectors
2222  // 3. put tag selectors in hash by id
2223  // 4. other selectors (shouldn't be much) goes to plain list
2224  nextSimilarSelector = new unsigned[selectors_size];
2225  otherSelector = selectors_size;
2226  for (unsigned int i = 0; i < selectors_size; ++i) {
2227  nextSimilarSelector[i] = selectors_size;
2228  }
2229  for (int i = selectors_size - 1; i >= 0; --i) {
2230  if (selectors[i]->match == CSSSelector::Class) {
2231  pair<WTF::HashMap<quintptr, int>::iterator, bool> it = classSelector.add((quintptr)selectors[i]->value.impl(), i);
2232  if (!it.second) {
2233  nextSimilarSelector[i] = it.first->second;
2234  it.first->second = i;
2235  }
2236  } else if (selectors[i]->match == CSSSelector::Id) {
2237  pair<WTF::HashMap<quintptr, int>::iterator, bool> it = idSelector.add((quintptr)selectors[i]->value.impl(), i);
2238  if (!it.second) {
2239  nextSimilarSelector[i] = it.first->second;
2240  it.first->second = i;
2241  }
2242  } else if (selectors[i]->tagLocalName.id() && selectors[i]->tagLocalName.id() != anyLocalName) {
2243  pair<WTF::HashMap<unsigned, int>::iterator, bool> it = tagSelector.add(selectors[i]->tagLocalName.id(), i);
2244  if (!it.second) {
2245  nextSimilarSelector[i] = it.first->second;
2246  it.first->second = i;
2247  }
2248  } else {
2249  nextSimilarSelector[i] = otherSelector;
2250  otherSelector = i;
2251  }
2252  }
2253 
2254  // presort properties. Should make the sort() calls in styleForElement faster.
2255  std::sort(propertyList.begin(), propertyList.end());
2256  properties_size = propertyList.count();
2257  propertiesBuffer = new CSSOrderedProperty[properties_size];
2258  for (int i = 0; i < propertyList.size(); ++i) {
2259  propertiesBuffer[i] = propertyList[i];
2260  }
2261 
2262  // properties for one selector are not necessarily adjacent at this point
2263  // prepare sublists with same selector
2264  // create for every property next property index with same selector
2265  nextPropertyIndexes = new unsigned[properties_size];
2266  for (int i = properties_size - 1; i >= 0; --i) {
2267  unsigned selector = propertiesBuffer[i].selector;
2268  nextPropertyIndexes[i] = selectorCache[selector].firstPropertyIndex;
2269  selectorCache[selector].firstPropertyIndex = i;
2270  }
2271 }
2272 
2273 // ----------------------------------------------------------------------
2274 
2275 CSSOrderedRule::CSSOrderedRule(DOM::CSSStyleRuleImpl *r, DOM::CSSSelector *s, int _index)
2276 {
2277  rule = r;
2278  if (rule) {
2279  r->ref();
2280  }
2281  index = _index;
2282  selector = s;
2283 }
2284 
2285 CSSOrderedRule::~CSSOrderedRule()
2286 {
2287  if (rule) {
2288  rule->deref();
2289  }
2290 }
2291 
2292 // -----------------------------------------------------------------
2293 
2294 CSSStyleSelectorList::CSSStyleSelectorList()
2296 {
2297 }
2298 CSSStyleSelectorList::~CSSStyleSelectorList()
2299 {
2300  qDeleteAll(*this);
2301  clear();
2302 }
2303 
2304 void CSSStyleSelectorList::append(CSSStyleSheetImpl *sheet,
2305  MediaQueryEvaluator *medium, CSSStyleSelector *styleSelector)
2306 {
2307  if (!sheet || !sheet->isCSSStyleSheet()) {
2308  return;
2309  }
2310 
2311  // No media implies "all", but if a medialist exists it must
2312  // contain our current medium
2313  if (sheet->media() && !medium->eval(sheet->media(), styleSelector)) {
2314  return; // style sheet not applicable for this medium
2315  }
2316 
2317  int len = sheet->length();
2318  for (int i = 0; i < len; i++) {
2319  StyleBaseImpl *item = sheet->item(i);
2320  if (item->isStyleRule()) {
2321  CSSStyleRuleImpl *r = static_cast<CSSStyleRuleImpl *>(item);
2322  QList<CSSSelector *> *s = r->selector();
2323  for (int j = 0; j < s->count(); j++) {
2324  CSSOrderedRule *rule = new CSSOrderedRule(r, s->at(j), count());
2326  //qCDebug(KHTML_LOG) << "appending StyleRule!";
2327  }
2328  } else if (item->isImportRule()) {
2329  CSSImportRuleImpl *import = static_cast<CSSImportRuleImpl *>(item);
2330 
2331  //qCDebug(KHTML_LOG) << "@import: Media: "
2332  // << import->media()->mediaText().string();
2333 
2334  if (!import->media() || medium->eval(import->media(), styleSelector)) {
2335  CSSStyleSheetImpl *importedSheet = import->styleSheet();
2336  append(importedSheet, medium, styleSelector);
2337  }
2338  } else if (item->isMediaRule()) {
2339  CSSMediaRuleImpl *r = static_cast<CSSMediaRuleImpl *>(item);
2340  CSSRuleListImpl *rules = r->cssRules();
2341 
2342  //qCDebug(KHTML_LOG) << "@media: Media: "
2343  // << r->media()->mediaText().string();
2344 
2345  if ((!r->media() || medium->eval(r->media(), styleSelector)) && rules) {
2346  // Traverse child elements of the @import rule. Since
2347  // many elements are not allowed as child we do not use
2348  // a recursive call to append() here
2349  for (unsigned j = 0; j < rules->length(); j++) {
2350  //qCDebug(KHTML_LOG) << "*** Rule #" << j;
2351 
2352  CSSRuleImpl *childItem = rules->item(j);
2353  if (childItem->isStyleRule()) {
2354  // It is a StyleRule, so append it to our list
2355  CSSStyleRuleImpl *styleRule =
2356  static_cast<CSSStyleRuleImpl *>(childItem);
2357 
2358  QList<CSSSelector *> *s = styleRule->selector();
2359  for (int j = 0; j < s->count(); j++) {
2360  CSSOrderedRule *orderedRule = new CSSOrderedRule(
2361  styleRule, s->at(j), count());
2362  QList<CSSOrderedRule *>::append(orderedRule);
2363  }
2364  } else if (childItem->isFontFaceRule() && styleSelector) {
2365  const CSSFontFaceRuleImpl *fontFaceRule = static_cast<CSSFontFaceRuleImpl *>(childItem);
2366  styleSelector->fontSelector()->addFontFaceRule(fontFaceRule);
2367  } else {
2368  //qCDebug(KHTML_LOG) << "Ignoring child rule of "
2369  // "ImportRule: rule is not a StyleRule!";
2370  }
2371  } // for rules
2372  } // if rules
2373  else {
2374  //qCDebug(KHTML_LOG) << "CSSMediaRule not rendered: "
2375  // << "rule empty or wrong medium!";
2376  }
2377  } else if (item->isFontFaceRule() && styleSelector) {
2378  const CSSFontFaceRuleImpl *fontFaceRule = static_cast<CSSFontFaceRuleImpl *>(item);
2379  styleSelector->fontSelector()->addFontFaceRule(fontFaceRule);
2380  }
2381  // ### include other rules
2382  }
2383 }
2384 
2385 void CSSStyleSelectorList::collect(WTF::HashMap<CSSSelector *, int> *selectorsCache, QList<CSSSelector *> *selectorList,
2386  CSSOrderedPropertyList *propList, Source regular, Source important)
2387 {
2388  CSSOrderedRule *r;
2390 
2391  propList->reserve(propList->size() + selectorList->size());
2392  while (tIt.hasNext()) {
2393  r = tIt.next();
2394  int selectorNum = selectorsCache->size();
2395  pair<WTF::HashMap<CSSSelector *, int>::iterator, bool> cacheIterator = selectorsCache->add(r->selector, selectorNum);
2396  if (cacheIterator.second) {
2397  selectorList->append(r->selector);
2398  }
2399  selectorNum = cacheIterator.first->second;
2400  propList->append(r->rule->declaration(), selectorNum, r->selector->specificity(), regular, important);
2401  }
2402 }
2403 
2404 // -------------------------------------------------------------------------
2405 
2406 void CSSOrderedPropertyList::append(DOM::CSSStyleDeclarationImpl *decl, uint selector, uint specificity,
2407  Source regular, Source important)
2408 {
2409  QList<CSSProperty *> *values = decl->values();
2410  if (!values) {
2411  return;
2412  }
2413  int len = values->count();
2414  for (int i = 0; i < len; i++) {
2415  CSSProperty *prop = values->at(i);
2416  Source source = regular;
2417 
2418  if (prop->m_important) {
2419  source = important;
2420  }
2421 
2422  bool first = false;
2423  // give special priority to font-xxx, color properties
2424  switch (prop->m_id) {
2425  case CSS_PROP_FONT_STYLE:
2426  case CSS_PROP_FONT_SIZE:
2427  case CSS_PROP_FONT_WEIGHT:
2428  case CSS_PROP_FONT_FAMILY:
2429  case CSS_PROP_FONT_VARIANT:
2430  case CSS_PROP_FONT:
2431  case CSS_PROP_COLOR:
2432  case CSS_PROP_DIRECTION:
2433  case CSS_PROP_DISPLAY:
2434  // these have to be applied first, because other properties use the computed
2435  // values of these porperties.
2436  first = true;
2437  break;
2438  default:
2439  break;
2440  }
2441 
2442  QVector<CSSOrderedProperty>::append(CSSOrderedProperty(prop, selector, first, source, specificity, count()));
2443  }
2444 }
2445 
2446 // -------------------------------------------------------------------------------------
2447 // this is mostly boring stuff on how to apply a certain rule to the renderstyle...
2448 
2449 static Length convertToLength(CSSPrimitiveValueImpl *primitiveValue, RenderStyle *style, RenderStyle *rootStyle, int logicalDpiY, bool *ok = nullptr)
2450 {
2451  Length l;
2452  if (!primitiveValue) {
2453  if (ok) {
2454  *ok = false;
2455  }
2456  } else {
2457  int type = primitiveValue->primitiveType();
2458  if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) {
2459  l = Length(primitiveValue->computeLength(style, rootStyle, logicalDpiY), Fixed);
2460  } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) {
2461  l = Length(primitiveValue->floatValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
2462  } else if (type == CSSPrimitiveValue::CSS_NUMBER) {
2463  l = Length(primitiveValue->floatValue(CSSPrimitiveValue::CSS_NUMBER) * 100.0, Percent);
2464  } else if (type == CSSPrimitiveValue::CSS_HTML_RELATIVE) {
2465  l = Length(int(primitiveValue->floatValue(CSSPrimitiveValue::CSS_HTML_RELATIVE)), Relative);
2466  } else if (ok) {
2467  *ok = false;
2468  }
2469  }
2470  return l;
2471 }
2472 
2473 static inline int nextFontSize(const QVector<int> &a, int v, bool smaller)
2474 {
2475  // return the nearest bigger/smaller value in scale a, when v is in range.
2476  // otherwise increase/decrease value using a 1.2 fixed ratio
2477  int m, l = 0, r = a.count() - 1;
2478  while (l <= r) {
2479  m = (l + r) / 2;
2480  if (a[m] == v)
2481  return smaller ? (m ? a[m - 1] : (v * 5) / 6) :
2482  (m + 1 < int(a.count()) ? a[m + 1] : (v * 6) / 5);
2483  else if (v < a[m]) {
2484  r = m - 1;
2485  } else {
2486  l = m + 1;
2487  }
2488  }
2489  if (!l) {
2490  return smaller ? (v * 5) / 6 : qMin((v * 6) / 5, a[0]);
2491  }
2492  if (l == int(a.count())) {
2493  return smaller ? qMax((v * 5) / 6, a[r]) : (v * 6) / 5;
2494  }
2495 
2496  return smaller ? a[r] : a[l];
2497 }
2498 
2499 // If we're explicitly inheriting an initial border-color, its computed value is based
2500 // on the parents' computed value of color, not ours.
2501 static QColor inheritedBorderColor(RenderStyle *parentStyle, const QColor &value)
2502 {
2503  if (value.isValid()) {
2504  return value;
2505  } else {
2506  return parentStyle->color();
2507  }
2508 }
2509 
2510 void CSSStyleSelector::applyRule(int id, DOM::CSSValueImpl *value)
2511 {
2512 // qCDebug(KHTML_LOG) << "applying property " << getPropertyName(id);
2513 
2514  CSSPrimitiveValueImpl *primitiveValue = nullptr;
2515  if (value->isPrimitiveValue()) {
2516  primitiveValue = static_cast<CSSPrimitiveValueImpl *>(value);
2517  }
2518 
2519  Length l;
2520  bool apply = false;
2521 
2522  bool isInherit = (parentNode && value->cssValueType() == CSSValue::CSS_INHERIT);
2523  bool isInitial = (value->cssValueType() == CSSValue::CSS_INITIAL) ||
2524  (!parentNode && value->cssValueType() == CSSValue::CSS_INHERIT);
2525 
2526  // These properties are used to set the correct margins/padding on RTL lists.
2527  if (id == CSS_PROP__KHTML_MARGIN_START) {
2528  id = style->direction() == LTR ? CSS_PROP_MARGIN_LEFT : CSS_PROP_MARGIN_RIGHT;
2529  } else if (id == CSS_PROP__KHTML_PADDING_START) {
2530  id = style->direction() == LTR ? CSS_PROP_PADDING_LEFT : CSS_PROP_PADDING_RIGHT;
2531  }
2532 
2533  // What follows is a list that maps the CSS properties into their corresponding front-end
2534  // RenderStyle values. Shorthands (e.g. border, background) occur in this list as well and
2535  // are only hit when mapping "inherit" or "initial" into front-end values.
2536  switch (id) {
2537 // ident only properties
2538  case CSS_PROP_BACKGROUND_ATTACHMENT:
2539  HANDLE_BACKGROUND_VALUE(backgroundAttachment, BackgroundAttachment, value)
2540  break;
2541  case CSS_PROP_BACKGROUND_CLIP:
2542  HANDLE_BACKGROUND_VALUE(backgroundClip, BackgroundClip, value)
2543  break;
2544  case CSS_PROP_BACKGROUND_ORIGIN:
2545  HANDLE_BACKGROUND_VALUE(backgroundOrigin, BackgroundOrigin, value)
2546  break;
2547  case CSS_PROP_BACKGROUND_REPEAT:
2548  HANDLE_BACKGROUND_VALUE(backgroundRepeat, BackgroundRepeat, value)
2549  break;
2550  case CSS_PROP_BACKGROUND_SIZE:
2551  HANDLE_BACKGROUND_VALUE(backgroundSize, BackgroundSize, value)
2552  break;
2553  case CSS_PROP_BORDER_COLLAPSE:
2554  HANDLE_INITIAL_AND_INHERIT_ON_INHERITED_PROPERTY(borderCollapse, BorderCollapse)
2555  if (!primitiveValue) {
2556  break;
2557  }
2558  switch (primitiveValue->getIdent()) {
2559  case CSS_VAL_COLLAPSE:
2560  style->setBorderCollapse(true);
2561  break;
2562  case CSS_VAL_SEPARATE:
2563  style->setBorderCollapse(false);
2564  break;
2565  default:
2566  return;
2567  }
2568  break;
2569 
2570  case CSS_PROP_BORDER_TOP_STYLE:
2571  HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderTopStyle, BorderTopStyle, BorderStyle)
2572  if (!primitiveValue) {
2573  return;
2574  }
2575  style->setBorderTopStyle((EBorderStyle)(primitiveValue->getIdent() - CSS_VAL__KHTML_NATIVE));
2576  break;
2577  case CSS_PROP_BORDER_RIGHT_STYLE:
2578  HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderRightStyle, BorderRightStyle, BorderStyle)
2579  if (!primitiveValue) {
2580  return;
2581  }
2582  style->setBorderRightStyle((EBorderStyle)(primitiveValue->getIdent() - CSS_VAL__KHTML_NATIVE));
2583  break;
2584  case CSS_PROP_BORDER_BOTTOM_STYLE:
2585  HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderBottomStyle, BorderBottomStyle, BorderStyle)
2586  if (!primitiveValue) {
2587  return;
2588  }
2589  style->setBorderBottomStyle((EBorderStyle)(primitiveValue->getIdent() - CSS_VAL__KHTML_NATIVE));
2590  break;
2591  case CSS_PROP_BORDER_LEFT_STYLE:
2592  HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderLeftStyle, BorderLeftStyle, BorderStyle)
2593  if (!primitiveValue) {
2594  return;
2595  }
2596  style->setBorderLeftStyle((EBorderStyle)(primitiveValue->getIdent() - CSS_VAL__KHTML_NATIVE));
2597  break;
2598  case CSS_PROP_OUTLINE_STYLE:
2599  HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(outlineStyle, OutlineStyle, BorderStyle)
2600  if (!primitiveValue) {
2601  return;
2602  }
2603  style->setOutlineStyle((EBorderStyle)(primitiveValue->getIdent() - CSS_VAL__KHTML_NATIVE));
2604  break;
2605  case CSS_PROP_CAPTION_SIDE: {
2606  HANDLE_INITIAL_AND_INHERIT_ON_INHERITED_PROPERTY(captionSide, CaptionSide)
2607 
2608  if (!primitiveValue) {
2609  break;
2610  }
2611  ECaptionSide c = RenderStyle::initialCaptionSide();
2612  switch (primitiveValue->getIdent()) {
2613  case CSS_VAL_LEFT:
2614  c = CAPLEFT; break;
2615  case CSS_VAL_RIGHT:
2616  c = CAPRIGHT; break;
2617  case CSS_VAL_TOP:
2618  c = CAPTOP; break;
2619  case CSS_VAL_BOTTOM:
2620  c = CAPBOTTOM; break;
2621  default:
2622  return;
2623  }
2624  style->setCaptionSide(c);
2625  return;
2626  }
2627  case CSS_PROP_CLEAR: {
2628  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(clear, Clear)
2629  if (!primitiveValue) {
2630  break;
2631  }
2632  EClear c = CNONE;
2633  switch (primitiveValue->getIdent()) {
2634  case CSS_VAL_LEFT:
2635  c = CLEFT; break;
2636  case CSS_VAL_RIGHT:
2637  c = CRIGHT; break;
2638  case CSS_VAL_BOTH:
2639  c = CBOTH; break;
2640  case CSS_VAL_NONE:
2641  c = CNONE; break;
2642  default:
2643  return;
2644  }
2645  style->setClear(c);
2646  return;
2647  }
2648  case CSS_PROP_DIRECTION: {
2649  HANDLE_INITIAL_AND_INHERIT_ON_INHERITED_PROPERTY(direction, Direction)
2650  if (!primitiveValue) {
2651  break;
2652  }
2653  style->setDirection((EDirection)(primitiveValue->getIdent() - CSS_VAL_LTR));
2654  return;
2655  }
2656  case CSS_PROP_DISPLAY: {
2657  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(display, Display)
2658  if (!primitiveValue) {
2659  break;
2660  }
2661  int id = primitiveValue->getIdent();
2662  style->setDisplay(id == CSS_VAL_NONE ? NONE : EDisplay(id - CSS_VAL_INLINE));
2663  break;
2664  }
2665 
2666  case CSS_PROP_EMPTY_CELLS: {
2667  HANDLE_INHERIT_ON_INHERITED_PROPERTY(emptyCells, EmptyCells);
2668  if (!primitiveValue) {
2669  break;
2670  }
2671  int id = primitiveValue->getIdent();
2672  if (id == CSS_VAL_SHOW) {
2673  style->setEmptyCells(SHOW);
2674  } else if (id == CSS_VAL_HIDE) {
2675  style->setEmptyCells(HIDE);
2676  }
2677  break;
2678  }
2679  case CSS_PROP_FLOAT: {
2680  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(floating, Floating)
2681  if (!primitiveValue) {
2682  return;
2683  }
2684  EFloat f;
2685  switch (primitiveValue->getIdent()) {
2686  case CSS_VAL__KHTML_LEFT:
2687  f = FLEFT_ALIGN; break;
2688  case CSS_VAL_LEFT:
2689  f = FLEFT; break;
2690  case CSS_VAL__KHTML_RIGHT:
2691  f = FRIGHT_ALIGN; break;
2692  case CSS_VAL_RIGHT:
2693  f = FRIGHT; break;
2694  case CSS_VAL_NONE:
2695  case CSS_VAL_CENTER: //Non standart CSS-Value
2696  f = FNONE; break;
2697  default:
2698  return;
2699  }
2700  if (f != FNONE && style->display() == LIST_ITEM) {
2701  style->setDisplay(BLOCK);
2702  }
2703 
2704  style->setFloating(f);
2705  break;
2706  }
2707 
2708  case CSS_PROP_FONT_STYLE: {
2709  FontDef fontDef = style->htmlFont().fontDef;
2710  if (isInherit) {
2711  fontDef.italic = parentStyle->htmlFont().fontDef.italic;
2712  } else if (isInitial) {
2713  fontDef.italic = false;
2714  } else {
2715  if (!primitiveValue) {
2716  return;
2717  }
2718  switch (primitiveValue->getIdent()) {
2719  case CSS_VAL_OBLIQUE:
2720  // ### oblique is the same as italic for the moment...
2721  case CSS_VAL_ITALIC:
2722  fontDef.italic = true;
2723  break;
2724  case CSS_VAL_NORMAL:
2725  fontDef.italic = false;
2726  break;
2727  default:
2728  return;
2729  }
2730  }
2731  fontDirty |= style->setFontDef(fontDef);
2732  break;
2733  }
2734 
2735  case CSS_PROP_FONT_VARIANT: {
2736  FontDef fontDef = style->htmlFont().fontDef;
2737  if (isInherit) {
2738  fontDef.smallCaps = parentStyle->htmlFont().fontDef.smallCaps;
2739  } else if (isInitial) {
2740  fontDef.smallCaps = false;
2741  } else {
2742  if (!primitiveValue) {
2743  return;
2744  }
2745  int id = primitiveValue->getIdent();
2746  if (id == CSS_VAL_NORMAL) {
2747  fontDef.smallCaps = false;
2748  } else if (id == CSS_VAL_SMALL_CAPS) {
2749  fontDef.smallCaps = true;
2750  } else {
2751  return;
2752  }
2753  }
2754  fontDirty |= style->setFontDef(fontDef);
2755  break;
2756  }
2757 
2758  case CSS_PROP_FONT_WEIGHT: {
2759  FontDef fontDef = style->htmlFont().fontDef;
2760  if (isInherit) {
2761  fontDef.weight = parentStyle->htmlFont().fontDef.weight;
2762  } else if (isInitial) {
2763  fontDef.weight = QFont::Normal;
2764  } else if (primitiveValue) {
2765  // Map CSS weights into available QFont::Weight
2766  switch (primitiveValue->getIdent()) {
2767  case CSS_VAL_100:
2768  case CSS_VAL_200:
2769  case CSS_VAL_300:
2770  fontDef.weight = QFont::Light; // 25
2771  break;
2772  case CSS_VAL_NORMAL:
2773  case CSS_VAL_400:
2774  case CSS_VAL_500:
2775  fontDef.weight = QFont::Normal; // 50
2776  break;
2777  case CSS_VAL_600:
2778  fontDef.weight = QFont::DemiBold; // 63
2779  break;
2780  case CSS_VAL_BOLD:
2781  case CSS_VAL_700:
2782  fontDef.weight = QFont::Bold; // 75
2783  break;
2784  case CSS_VAL_800:
2785  case CSS_VAL_900:
2786  fontDef.weight = QFont::Black; // 87
2787  break;
2788  case CSS_VAL_BOLDER: {
2789  // FIXME: Should return the next heaviest weight available for current family
2790  const unsigned int inheritedWeight = parentStyle->htmlFont().fontDef.weight;
2791  if (inheritedWeight < QFont::Normal) {
2792  fontDef.weight = QFont::Normal;
2793  } else if (inheritedWeight < QFont::DemiBold) {
2794  fontDef.weight = QFont::DemiBold;
2795  } else if (inheritedWeight < QFont::Bold) {
2796  fontDef.weight = QFont::Bold;
2797  } else {
2798  fontDef.weight = QFont::Black;
2799  }
2800  }
2801  break;
2802  case CSS_VAL_LIGHTER: {
2803  // FIXME: Should return the next lightest weight available for current family
2804  const unsigned int inheritedWeight = parentStyle->htmlFont().fontDef.weight;
2805  if (inheritedWeight > QFont::Bold) {
2806  fontDef.weight = QFont::Bold;
2807  } else if (inheritedWeight > QFont::DemiBold) {
2808  fontDef.weight = QFont::DemiBold;
2809  } else if (inheritedWeight > QFont::Normal) {
2810  fontDef.weight = QFont::Normal;
2811  } else {
2812  fontDef.weight = QFont::Light;
2813  }
2814  }
2815  break;
2816  default:
2817  return;
2818  }
2819  } else {
2820  return;
2821  }
2822  fontDirty |= style->setFontDef( fontDef );
2823  break;
2824  }
2825 
2826  case CSS_PROP_LIST_STYLE_POSITION: {
2827  HANDLE_INITIAL_AND_INHERIT_ON_INHERITED_PROPERTY(listStylePosition, ListStylePosition)
2828  if (!primitiveValue) {
2829  return;
2830  }
2831  if (primitiveValue->getIdent()) {
2832  style->setListStylePosition((EListStylePosition)(primitiveValue->getIdent() - CSS_VAL_OUTSIDE));
2833  }
2834  return;
2835  }
2836 
2837  case CSS_PROP_LIST_STYLE_TYPE: {
2838  HANDLE_INITIAL_AND_INHERIT_ON_INHERITED_PROPERTY(listStyleType, ListStyleType)
2839  if (!primitiveValue) {
2840  return;
2841  }
2842  if (primitiveValue->getIdent()) {
2843  EListStyleType t;
2844  int id = primitiveValue->getIdent();
2845  if (id == CSS_VAL_NONE) { // important!!
2846  t = LNONE;
2847  } else {
2848  t = EListStyleType(id - CSS_VAL_DISC);
2849  }
2850  style->setListStyleType(t);
2851  }
2852  return;
2853  }
2854 
2855  case CSS_PROP_OVERFLOW: {
2856  if (isInherit) {
2857  style->setOverflowX(parentStyle->overflowX());
2858  style->setOverflowY(parentStyle->overflowY());
2859  style->setInheritedNoninherited(true);
2860  return;
2861  }
2862 
2863  if (isInitial) {
2864  style->setOverflowX(RenderStyle::initialOverflowX());
2865  style->setOverflowY(RenderStyle::initialOverflowY());
2866  return;
2867  }
2868 
2869  if (!primitiveValue) {
2870  return;
2871  }
2872  EOverflow o;
2873  switch (primitiveValue->getIdent()) {
2874  case CSS_VAL_VISIBLE:
2875  o = OVISIBLE; break;
2876  case CSS_VAL_HIDDEN:
2877  o = OHIDDEN; break;
2878  case CSS_VAL_SCROLL:
2879  o = OSCROLL; break;
2880  case CSS_VAL_AUTO:
2881  o = OAUTO; break;
2882  case CSS_VAL_MARQUEE:
2883  o = OMARQUEE; break;
2884  default:
2885  return;
2886  }
2887  style->setOverflowX(o);
2888  style->setOverflowY(o);
2889  return;
2890  }
2891  case CSS_PROP_OVERFLOW_X: {
2892  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(overflowX, OverflowX)
2893  if (!primitiveValue) {
2894  return;
2895  }
2896  EOverflow o;
2897  switch (primitiveValue->getIdent()) {
2898  case CSS_VAL_VISIBLE:
2899  o = OVISIBLE; break;
2900  case CSS_VAL_HIDDEN:
2901  o = OHIDDEN; break;
2902  case CSS_VAL_SCROLL:
2903  o = OSCROLL; break;
2904  case CSS_VAL_AUTO:
2905  o = OAUTO; break;
2906  default:
2907  return;
2908  }
2909  style->setOverflowX(o);
2910  return;
2911  }
2912  case CSS_PROP_OVERFLOW_Y: {
2913  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(overflowY, OverflowY)
2914  if (!primitiveValue) {
2915  return;
2916  }
2917  EOverflow o;
2918  switch (primitiveValue->getIdent()) {
2919  case CSS_VAL_VISIBLE:
2920  o = OVISIBLE; break;
2921  case CSS_VAL_HIDDEN:
2922  o = OHIDDEN; break;
2923  case CSS_VAL_SCROLL:
2924  o = OSCROLL; break;
2925  case CSS_VAL_AUTO:
2926  o = OAUTO; break;
2927  default:
2928  return;
2929  }
2930  style->setOverflowY(o);
2931  return;
2932  }
2933  case CSS_PROP_PAGE_BREAK_BEFORE: {
2934  HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(pageBreakBefore, PageBreakBefore, PageBreak)
2935  if (!primitiveValue) {
2936  return;
2937  }
2938  switch (primitiveValue->getIdent()) {
2939  case CSS_VAL_AUTO:
2940  style->setPageBreakBefore(PBAUTO);
2941  break;
2942  case CSS_VAL_LEFT:
2943  case CSS_VAL_RIGHT:
2944  // CSS2.1: "Conforming user agents may map left/right to always."
2945  case CSS_VAL_ALWAYS:
2946  style->setPageBreakBefore(PBALWAYS);
2947  break;
2948  case CSS_VAL_AVOID:
2949  style->setPageBreakBefore(PBAVOID);
2950  break;
2951  }
2952  break;
2953  }
2954 
2955  case CSS_PROP_PAGE_BREAK_AFTER: {
2956  HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(pageBreakAfter, PageBreakAfter, PageBreak)
2957  if (!primitiveValue) {
2958  return;
2959  }
2960  switch (primitiveValue->getIdent()) {
2961  case CSS_VAL_AUTO:
2962  style->setPageBreakAfter(PBAUTO);
2963  break;
2964  case CSS_VAL_LEFT:
2965  case CSS_VAL_RIGHT:
2966  // CSS2.1: "Conforming user agents may map left/right to always."
2967  case CSS_VAL_ALWAYS:
2968  style->setPageBreakAfter(PBALWAYS);
2969  break;
2970  case CSS_VAL_AVOID:
2971  style->setPageBreakAfter(PBAVOID);
2972  break;
2973  }
2974  break;
2975  }
2976 
2977  case CSS_PROP_PAGE_BREAK_INSIDE: {
2978  HANDLE_INITIAL_AND_INHERIT_ON_INHERITED_PROPERTY(pageBreakInside, PageBreakInside)
2979  if (!primitiveValue) {
2980  return;
2981  }
2982  if (primitiveValue->getIdent() == CSS_VAL_AUTO) {
2983  style->setPageBreakInside(true);
2984  } else if (primitiveValue->getIdent() == CSS_VAL_AVOID) {
2985  style->setPageBreakInside(false);
2986  }
2987  return;
2988  }
2989 // case CSS_PROP_PAUSE_AFTER:
2990 // case CSS_PROP_PAUSE_BEFORE:
2991  break;
2992 
2993  case CSS_PROP_POSITION: {
2994  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(position, Position)
2995  if (!primitiveValue) {
2996  return;
2997  }
2998  EPosition p;
2999  switch (primitiveValue->getIdent()) {
3000  case CSS_VAL_STATIC:
3001  p = PSTATIC; break;
3002  case CSS_VAL_RELATIVE:
3003  p = PRELATIVE; break;
3004  case CSS_VAL_ABSOLUTE:
3005  p = PABSOLUTE; break;
3006  case CSS_VAL_FIXED:
3007  p = PFIXED; break;
3008  default:
3009  return;
3010  }
3011  style->setPosition(p);
3012  return;
3013  }
3014 
3015  case CSS_PROP_TABLE_LAYOUT: {
3016  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(tableLayout, TableLayout)
3017 
3018  if (!primitiveValue) {
3019  return;
3020  }
3021 
3022  ETableLayout l = RenderStyle::initialTableLayout();
3023  switch (primitiveValue->getIdent()) {
3024  case CSS_VAL_FIXED:
3025  l = TFIXED;
3026  // fall through
3027  case CSS_VAL_AUTO:
3028  style->setTableLayout(l);
3029  default:
3030  break;
3031  }
3032  break;
3033  }
3034 
3035  case CSS_PROP_UNICODE_BIDI: {
3036  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(unicodeBidi, UnicodeBidi)
3037  if (!primitiveValue) {
3038  break;
3039  }
3040  switch (primitiveValue->getIdent()) {
3041  case CSS_VAL_NORMAL:
3042  style->setUnicodeBidi(UBNormal);
3043  break;
3044  case CSS_VAL_EMBED:
3045  style->setUnicodeBidi(Embed);
3046  break;
3047  case CSS_VAL_BIDI_OVERRIDE:
3048  style->setUnicodeBidi(Override);
3049  break;
3050  default:
3051  return;
3052  }
3053  break;
3054  }
3055  case CSS_PROP_TEXT_TRANSFORM: {
3056  HANDLE_INITIAL_AND_INHERIT_ON_INHERITED_PROPERTY(textTransform, TextTransform)
3057 
3058  if (!primitiveValue) {
3059  break;
3060  }
3061  if (!primitiveValue->getIdent()) {
3062  return;
3063  }
3064 
3065  ETextTransform tt;
3066  switch (primitiveValue->getIdent()) {
3067  case CSS_VAL_CAPITALIZE: tt = CAPITALIZE; break;
3068  case CSS_VAL_UPPERCASE: tt = UPPERCASE; break;
3069  case CSS_VAL_LOWERCASE: tt = LOWERCASE; break;
3070  case CSS_VAL_NONE:
3071  default: tt = TTNONE; break;
3072  }
3073  style->setTextTransform(tt);
3074  break;
3075  }
3076 
3077  case CSS_PROP_VISIBILITY: {
3078  HANDLE_INITIAL_AND_INHERIT_ON_INHERITED_PROPERTY(visibility, Visibility)
3079 
3080  if (!primitiveValue) {
3081  break;
3082  }
3083  switch (primitiveValue->getIdent()) {
3084  case CSS_VAL_HIDDEN:
3085  style->setVisibility(HIDDEN);
3086  break;
3087  case CSS_VAL_VISIBLE:
3088  style->setVisibility(VISIBLE);
3089  break;
3090  case CSS_VAL_COLLAPSE:
3091  style->setVisibility(COLLAPSE);
3092  default:
3093  break;
3094  }
3095  break;
3096  }
3097  case CSS_PROP_WHITE_SPACE:
3098  HANDLE_INITIAL_AND_INHERIT_ON_INHERITED_PROPERTY(whiteSpace, WhiteSpace)
3099 
3100  if (!primitiveValue) {
3101  break;
3102  }
3103  if (!primitiveValue->getIdent()) {
3104  return;
3105  }
3106 
3107  EWhiteSpace s;
3108  switch (primitiveValue->getIdent()) {
3109  case CSS_VAL__KHTML_NOWRAP:
3110  s = KHTML_NOWRAP;
3111  break;
3112  case CSS_VAL_NOWRAP:
3113  s = NOWRAP;
3114  break;
3115  case CSS_VAL_PRE:
3116  s = PRE;
3117  break;
3118  case CSS_VAL_PRE_WRAP:
3119  s = PRE_WRAP;
3120  break;
3121  case CSS_VAL_PRE_LINE:
3122  s = PRE_LINE;
3123  break;
3124  case CSS_VAL_NORMAL:
3125  default:
3126  s = NORMAL;
3127  break;
3128  }
3129  style->setWhiteSpace(s);
3130  break;
3131 
3132  case CSS_PROP_BACKGROUND_POSITION:
3133  HANDLE_BACKGROUND_INHERIT_AND_INITIAL(backgroundXPosition, BackgroundXPosition);
3134  HANDLE_BACKGROUND_INHERIT_AND_INITIAL(backgroundYPosition, BackgroundYPosition);
3135  break;
3136  case CSS_PROP_BACKGROUND_POSITION_X: {
3137  HANDLE_BACKGROUND_VALUE(backgroundXPosition, BackgroundXPosition, value)
3138  break;
3139  }
3140  case CSS_PROP_BACKGROUND_POSITION_Y: {
3141  HANDLE_BACKGROUND_VALUE(backgroundYPosition, BackgroundYPosition, value)
3142  break;
3143  }
3144  case CSS_PROP_BORDER_SPACING: {
3145  if (value->cssValueType() != CSSValue::CSS_INHERIT || !parentNode) {
3146  return;
3147  }
3148  style->setBorderHorizontalSpacing(parentStyle->borderHorizontalSpacing());
3149  style->setBorderVerticalSpacing(parentStyle->borderVerticalSpacing());
3150  break;
3151  }
3152  case CSS_PROP__KHTML_BORDER_HORIZONTAL_SPACING: {
3153  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(borderHorizontalSpacing, BorderHorizontalSpacing)
3154  if (!primitiveValue) {
3155  break;
3156  }
3157  short spacing = primitiveValue->computeLength(style, m_rootStyle, logicalDpiY);
3158  style->setBorderHorizontalSpacing(spacing);
3159  break;
3160  }
3161  case CSS_PROP__KHTML_BORDER_VERTICAL_SPACING: {
3162  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(borderVerticalSpacing, BorderVerticalSpacing)
3163  if (!primitiveValue) {
3164  break;
3165  }
3166  short spacing = primitiveValue->computeLength(style, m_rootStyle, logicalDpiY);
3167  style->setBorderVerticalSpacing(spacing);
3168  break;
3169  }
3170 
3171  case CSS_PROP_BORDER_TOP_RIGHT_RADIUS:
3172  case CSS_PROP_BORDER_TOP_LEFT_RADIUS:
3173  case CSS_PROP_BORDER_BOTTOM_RIGHT_RADIUS:
3174  case CSS_PROP_BORDER_BOTTOM_LEFT_RADIUS: {
3175  if (isInherit) {
3176  style->setInheritedNoninherited(true);
3177  HANDLE_INHERIT_COND(CSS_PROP_BORDER_TOP_RIGHT_RADIUS, borderTopRightRadius, BorderTopRightRadius)
3178  HANDLE_INHERIT_COND(CSS_PROP_BORDER_TOP_LEFT_RADIUS, borderTopLeftRadius, BorderTopLeftRadius)
3179  HANDLE_INHERIT_COND(CSS_PROP_BORDER_BOTTOM_RIGHT_RADIUS, borderBottomRightRadius, BorderBottomRightRadius)
3180  HANDLE_INHERIT_COND(CSS_PROP_BORDER_BOTTOM_LEFT_RADIUS, borderBottomLeftRadius, BorderBottomLeftRadius)
3181  return;
3182  }
3183  if (isInitial) {
3184  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_TOP_RIGHT_RADIUS, BorderTopRightRadius, BorderRadius)
3185  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_TOP_LEFT_RADIUS, BorderTopLeftRadius, BorderRadius)
3186  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_BOTTOM_RIGHT_RADIUS, BorderBottomRightRadius, BorderRadius)
3187  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_BOTTOM_LEFT_RADIUS, BorderBottomLeftRadius, BorderRadius)
3188  return;
3189  }
3190 
3191  if (!primitiveValue) {
3192  return;
3193  }
3194 
3195  PairImpl *p = primitiveValue->getPairValue();
3196  if (!p) {
3197  return;
3198  }
3199 
3200  BorderRadii bradii;
3201  bradii.horizontal = convertToLength((p->first()), style, m_rootStyle, logicalDpiY);
3202  bradii.vertical = convertToLength((p->second()), style, m_rootStyle, logicalDpiY);
3203 
3204  switch(id) {
3205  case CSS_PROP_BORDER_TOP_RIGHT_RADIUS:
3206  style->setBorderTopRightRadius(bradii);
3207  break;
3208  case CSS_PROP_BORDER_TOP_LEFT_RADIUS:
3209  style->setBorderTopLeftRadius(bradii);
3210  break;
3211  case CSS_PROP_BORDER_BOTTOM_RIGHT_RADIUS:
3212  style->setBorderBottomRightRadius(bradii);
3213  break;
3214  case CSS_PROP_BORDER_BOTTOM_LEFT_RADIUS:
3215  style->setBorderBottomLeftRadius(bradii);
3216  break;
3217  default:
3218  break;
3219  }
3220  return;
3221  }
3222  break;
3223 
3224  case CSS_PROP_CURSOR:
3225  HANDLE_INITIAL_AND_INHERIT_ON_INHERITED_PROPERTY(cursor, Cursor)
3226  if (!primitiveValue) {
3227  break;
3228  }
3229  ECursor cursor;
3230  switch (primitiveValue->getIdent()) {
3231  case CSS_VAL_NONE:
3232  cursor = CURSOR_NONE;
3233  break;
3234  default:
3235  cursor = (ECursor)(primitiveValue->getIdent() - CSS_VAL_AUTO);
3236  }
3237  style->setCursor(cursor);
3238  break;
3239 // colors || inherit
3240  case CSS_PROP_COLOR:
3241  // If the 'currentColor' keyword is set on the 'color' property itself,
3242  // it is treated as 'color:inherit' at parse time
3243  if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_CURRENTCOLOR) {
3244  isInherit = true;
3245  }
3246  case CSS_PROP_BACKGROUND_COLOR:
3247  case CSS_PROP_BORDER_TOP_COLOR:
3248  case CSS_PROP_BORDER_RIGHT_COLOR:
3249  case CSS_PROP_BORDER_BOTTOM_COLOR:
3250  case CSS_PROP_BORDER_LEFT_COLOR:
3251  case CSS_PROP_OUTLINE_COLOR:
3252  // this property is an extension used to get HTML4 <font> right.
3253  case CSS_PROP_SCROLLBAR_BASE_COLOR:
3254  case CSS_PROP_SCROLLBAR_FACE_COLOR:
3255  case CSS_PROP_SCROLLBAR_SHADOW_COLOR:
3256  case CSS_PROP_SCROLLBAR_HIGHLIGHT_COLOR:
3257  case CSS_PROP_SCROLLBAR_3DLIGHT_COLOR:
3258  case CSS_PROP_SCROLLBAR_DARKSHADOW_COLOR:
3259  case CSS_PROP_SCROLLBAR_TRACK_COLOR:
3260  case CSS_PROP_SCROLLBAR_ARROW_COLOR: {
3261  QColor col;
3262  if (isInherit) {
3263  if (id != CSS_PROP_COLOR) {
3264  style->setInheritedNoninherited(true);
3265  }
3266  HANDLE_INHERIT_COND(CSS_PROP_BACKGROUND_COLOR, backgroundColor, BackgroundColor)
3267  HANDLE_INHERIT_COND_WITH_BACKUP(CSS_PROP_BORDER_TOP_COLOR, borderTopColor, color, BorderTopColor)
3268  HANDLE_INHERIT_COND_WITH_BACKUP(CSS_PROP_BORDER_BOTTOM_COLOR, borderBottomColor, color, BorderBottomColor)
3269  HANDLE_INHERIT_COND_WITH_BACKUP(CSS_PROP_BORDER_RIGHT_COLOR, borderRightColor, color, BorderRightColor)
3270  HANDLE_INHERIT_COND_WITH_BACKUP(CSS_PROP_BORDER_LEFT_COLOR, borderLeftColor, color, BorderLeftColor)
3271  HANDLE_INHERIT_COND(CSS_PROP_COLOR, color, Color)
3272  HANDLE_INHERIT_COND_WITH_BACKUP(CSS_PROP_OUTLINE_COLOR, outlineColor, color, OutlineColor)
3273  return;
3274  } else if (isInitial) {
3275  // The border/outline colors will just map to the invalid color |col| above. This will have the
3276  // effect of forcing the use of the currentColor when it comes time to draw the borders (and of
3277  // not painting the background since the color won't be valid).
3278  if (id == CSS_PROP_COLOR) {
3279  col = RenderStyle::initialColor();
3280  }
3281  } else {
3282  if (!primitiveValue) {
3283  return;
3284  }
3285  int ident = primitiveValue->getIdent();
3286  if (ident) {
3287  if (ident == CSS_VAL__KHTML_TEXT) {
3288  col = element->document()->textColor();
3289  } else if (ident == CSS_VAL_CURRENTCOLOR) {
3290  col = style->color();
3291  } else {
3292  col = colorForCSSValue(ident);
3293  }
3294  } else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_RGBCOLOR) {
3295  col.setRgba(primitiveValue->getRGBColorValue());
3296  } else {
3297  return;
3298  }
3299  }
3300  //qCDebug(KHTML_LOG) << "applying color " << col.isValid();
3301  switch (id) {
3302  case CSS_PROP_BACKGROUND_COLOR:
3303  style->setBackgroundColor(col); break;
3304  case CSS_PROP_BORDER_TOP_COLOR:
3305  style->setBorderTopColor(col); break;
3306  case CSS_PROP_BORDER_RIGHT_COLOR:
3307  style->setBorderRightColor(col); break;
3308  case CSS_PROP_BORDER_BOTTOM_COLOR:
3309  style->setBorderBottomColor(col); break;
3310  case CSS_PROP_BORDER_LEFT_COLOR:
3311  style->setBorderLeftColor(col); break;
3312  case CSS_PROP_COLOR:
3313  style->setColor(col); break;
3314  case CSS_PROP_OUTLINE_COLOR:
3315  style->setOutlineColor(col); break;
3316 #ifndef APPLE_CHANGES
3317  case CSS_PROP_SCROLLBAR_FACE_COLOR:
3318  style->setPaletteColor(QPalette::Active, QPalette::Button, col);
3319  style->setPaletteColor(QPalette::Inactive, QPalette::Button, col);
3320  break;
3321  case CSS_PROP_SCROLLBAR_SHADOW_COLOR:
3322  style->setPaletteColor(QPalette::Active, QPalette::Shadow, col);
3323  style->setPaletteColor(QPalette::Inactive, QPalette::Shadow, col);
3324  break;
3325  case CSS_PROP_SCROLLBAR_HIGHLIGHT_COLOR:
3326  style->setPaletteColor(QPalette::Active, QPalette::Light, col);
3327  style->setPaletteColor(QPalette::Inactive, QPalette::Light, col);
3328  break;
3329  case CSS_PROP_SCROLLBAR_3DLIGHT_COLOR:
3330  break;
3331  case CSS_PROP_SCROLLBAR_DARKSHADOW_COLOR:
3332  style->setPaletteColor(QPalette::Active, QPalette::Dark, col);
3333  style->setPaletteColor(QPalette::Inactive, QPalette::Dark, col);
3334  break;
3335  case CSS_PROP_SCROLLBAR_TRACK_COLOR:
3336  style->setPaletteColor(QPalette::Active, QPalette::Mid, col);
3337  style->setPaletteColor(QPalette::Inactive, QPalette::Mid, col);
3338  style->setPaletteColor(QPalette::Active, QPalette::Window, col);
3339  style->setPaletteColor(QPalette::Inactive, QPalette::Window, col);
3340  // fall through
3341  case CSS_PROP_SCROLLBAR_BASE_COLOR:
3342  style->setPaletteColor(QPalette::Active, QPalette::Base, col);
3343  style->setPaletteColor(QPalette::Inactive, QPalette::Base, col);
3344  break;
3345  case CSS_PROP_SCROLLBAR_ARROW_COLOR:
3346  style->setPaletteColor(QPalette::Active, QPalette::ButtonText, col);
3347  style->setPaletteColor(QPalette::Inactive, QPalette::ButtonText, col);
3348  break;
3349 #endif
3350  default:
3351  return;
3352  }
3353  return;
3354  }
3355  break;
3356 // uri || inherit
3357  case CSS_PROP_BACKGROUND_IMAGE:
3358  HANDLE_BACKGROUND_VALUE(backgroundImage, BackgroundImage, value)
3359  break;
3360  case CSS_PROP_LIST_STYLE_IMAGE: {
3361  HANDLE_INITIAL_AND_INHERIT_ON_INHERITED_PROPERTY(listStyleImage, ListStyleImage)
3362  if (!primitiveValue) {
3363  return;
3364  }
3365  style->setListStyleImage(static_cast<CSSImageValueImpl *>(primitiveValue)->requestCssImage(element->document()));
3366  break;
3367  }
3368 
3369 // length
3370  case CSS_PROP_BORDER_TOP_WIDTH:
3371  case CSS_PROP_BORDER_RIGHT_WIDTH:
3372  case CSS_PROP_BORDER_BOTTOM_WIDTH:
3373  case CSS_PROP_BORDER_LEFT_WIDTH:
3374  case CSS_PROP_OUTLINE_WIDTH: {
3375  if (isInherit) {
3376  style->setInheritedNoninherited(true);
3377  HANDLE_INHERIT_COND(CSS_PROP_BORDER_TOP_WIDTH, borderTopWidth, BorderTopWidth)
3378  HANDLE_INHERIT_COND(CSS_PROP_BORDER_RIGHT_WIDTH, borderRightWidth, BorderRightWidth)
3379  HANDLE_INHERIT_COND(CSS_PROP_BORDER_BOTTOM_WIDTH, borderBottomWidth, BorderBottomWidth)
3380  HANDLE_INHERIT_COND(CSS_PROP_BORDER_LEFT_WIDTH, borderLeftWidth, BorderLeftWidth)
3381  HANDLE_INHERIT_COND(CSS_PROP_OUTLINE_WIDTH, outlineWidth, OutlineWidth)
3382  return;
3383  } else if (isInitial) {
3384  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_TOP_WIDTH, BorderTopWidth, BorderWidth)
3385  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_RIGHT_WIDTH, BorderRightWidth, BorderWidth)
3386  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_BOTTOM_WIDTH, BorderBottomWidth, BorderWidth)
3387  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_LEFT_WIDTH, BorderLeftWidth, BorderWidth)
3388  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_OUTLINE_WIDTH, OutlineWidth, BorderWidth)
3389  return;
3390  }
3391 
3392  if (!primitiveValue) {
3393  break;
3394  }
3395  short width = 3;
3396  switch (primitiveValue->getIdent()) {
3397  case CSS_VAL_THIN:
3398  width = 1;
3399  break;
3400  case CSS_VAL_MEDIUM:
3401  width = 3;
3402  break;
3403  case CSS_VAL_THICK:
3404  width = 5;
3405  break;
3406  case CSS_VAL_INVALID: {
3407  double widthd = primitiveValue->computeLengthFloat(style, m_rootStyle, logicalDpiY);
3408  width = CSSPrimitiveValueImpl::snapValue(widthd);
3409  // somewhat resemble Mozilla's granularity
3410  // this makes border-width: 0.5pt borders visible
3411  if (width == 0 && widthd >= 0.025) {
3412  width++;
3413  }
3414  break;
3415  }
3416  default:
3417  return;
3418  }
3419 
3420  if (width < 0) {
3421  return;
3422  }
3423  switch (id) {
3424  case CSS_PROP_BORDER_TOP_WIDTH:
3425  style->setBorderTopWidth(width);
3426  break;
3427  case CSS_PROP_BORDER_RIGHT_WIDTH:
3428  style->setBorderRightWidth(width);
3429  break;
3430  case CSS_PROP_BORDER_BOTTOM_WIDTH:
3431  style->setBorderBottomWidth(width);
3432  break;
3433  case CSS_PROP_BORDER_LEFT_WIDTH:
3434  style->setBorderLeftWidth(width);
3435  break;
3436  case CSS_PROP_OUTLINE_WIDTH:
3437  style->setOutlineWidth(width);
3438  break;
3439  default:
3440  return;
3441  }
3442  return;
3443  }
3444 
3445  case CSS_PROP_LETTER_SPACING:
3446  case CSS_PROP_WORD_SPACING: {
3447  if (isInherit) {
3448  HANDLE_INHERIT_COND(CSS_PROP_LETTER_SPACING, letterSpacing, LetterSpacing)
3449  HANDLE_INHERIT_COND(CSS_PROP_WORD_SPACING, wordSpacing, WordSpacing)
3450  return;
3451  } else if (isInitial) {
3452  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_LETTER_SPACING, LetterSpacing, LetterWordSpacing)
3453  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_WORD_SPACING, WordSpacing, LetterWordSpacing)
3454  return;
3455  }
3456  if (!primitiveValue) {
3457  return;
3458  }
3459 
3460  int width = 0;
3461  if (primitiveValue->getIdent() != CSS_VAL_NORMAL) {
3462  width = primitiveValue->computeLength(style, m_rootStyle, logicalDpiY);
3463  }
3464 
3465  switch (id) {
3466  case CSS_PROP_LETTER_SPACING:
3467  style->setLetterSpacing(width);
3468  break;
3469  case CSS_PROP_WORD_SPACING:
3470  style->setWordSpacing(width);
3471  break;
3472  // ### needs the definitions in renderstyle
3473  default: break;
3474  }
3475  return;
3476  }
3477 
3478  // length, percent
3479  case CSS_PROP_MAX_WIDTH:
3480  // +none +inherit
3481  if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_NONE) {
3482  apply = true;
3483  l = Length(UNDEFINED, Fixed);
3484  }
3485  case CSS_PROP_TOP:
3486  case CSS_PROP_LEFT:
3487  case CSS_PROP_RIGHT:
3488  case CSS_PROP_BOTTOM:
3489  case CSS_PROP_WIDTH:
3490  case CSS_PROP_MIN_WIDTH:
3491  case CSS_PROP_MARGIN_TOP:
3492  case CSS_PROP_MARGIN_RIGHT:
3493  case CSS_PROP_MARGIN_BOTTOM:
3494  case CSS_PROP_MARGIN_LEFT:
3495  // +inherit +auto
3496  if (id != CSS_PROP_MAX_WIDTH && primitiveValue &&
3497  primitiveValue->getIdent() == CSS_VAL_AUTO) {
3498  //qCDebug(KHTML_LOG) << "found value=auto";
3499  apply = true;
3500  }
3501  case CSS_PROP_PADDING_TOP:
3502  case CSS_PROP_PADDING_RIGHT:
3503  case CSS_PROP_PADDING_BOTTOM:
3504  case CSS_PROP_PADDING_LEFT:
3505  case CSS_PROP_TEXT_INDENT:
3506  // +inherit
3507  {
3508  if (isInherit) {
3509  if (id != CSS_PROP_TEXT_INDENT) {
3510  style->setInheritedNoninherited(true);
3511  }
3512  HANDLE_INHERIT_COND(CSS_PROP_MAX_WIDTH, maxWidth, MaxWidth)
3513  HANDLE_INHERIT_COND(CSS_PROP_BOTTOM, bottom, Bottom)
3514  HANDLE_INHERIT_COND(CSS_PROP_TOP, top, Top)
3515  HANDLE_INHERIT_COND(CSS_PROP_LEFT, left, Left)
3516  HANDLE_INHERIT_COND(CSS_PROP_RIGHT, right, Right)
3517  HANDLE_INHERIT_COND(CSS_PROP_WIDTH, width, Width)
3518  HANDLE_INHERIT_COND(CSS_PROP_MIN_WIDTH, minWidth, MinWidth)
3519  HANDLE_INHERIT_COND(CSS_PROP_PADDING_TOP, paddingTop, PaddingTop)
3520  HANDLE_INHERIT_COND(CSS_PROP_PADDING_RIGHT, paddingRight, PaddingRight)
3521  HANDLE_INHERIT_COND(CSS_PROP_PADDING_BOTTOM, paddingBottom, PaddingBottom)
3522  HANDLE_INHERIT_COND(CSS_PROP_PADDING_LEFT, paddingLeft, PaddingLeft)
3523  HANDLE_INHERIT_COND(CSS_PROP_MARGIN_TOP, marginTop, MarginTop)
3524  HANDLE_INHERIT_COND(CSS_PROP_MARGIN_RIGHT, marginRight, MarginRight)
3525  HANDLE_INHERIT_COND(CSS_PROP_MARGIN_BOTTOM, marginBottom, MarginBottom)
3526  HANDLE_INHERIT_COND(CSS_PROP_MARGIN_LEFT, marginLeft, MarginLeft)
3527  HANDLE_INHERIT_COND(CSS_PROP_TEXT_INDENT, textIndent, TextIndent)
3528  return;
3529  } else if (isInitial) {
3530  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MAX_WIDTH, MaxWidth, MaxSize)
3531  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BOTTOM, Bottom, Offset)
3532  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_TOP, Top, Offset)
3533  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_LEFT, Left, Offset)
3534  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_RIGHT, Right, Offset)
3535  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_WIDTH, Width, Size)
3536  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MIN_WIDTH, MinWidth, MinSize)
3537  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_PADDING_TOP, PaddingTop, Padding)
3538  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_PADDING_RIGHT, PaddingRight, Padding)
3539  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_PADDING_BOTTOM, PaddingBottom, Padding)
3540  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_PADDING_LEFT, PaddingLeft, Padding)
3541  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MARGIN_TOP, MarginTop, Margin)
3542  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MARGIN_RIGHT, MarginRight, Margin)
3543  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MARGIN_BOTTOM, MarginBottom, Margin)
3544  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MARGIN_LEFT, MarginLeft, Margin)
3545  HANDLE_INITIAL_COND(CSS_PROP_TEXT_INDENT, TextIndent)
3546  return;
3547  }
3548 
3549  if (primitiveValue && !apply) {
3550  int type = primitiveValue->primitiveType();
3551  if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
3552  // Handle our quirky margin units if we have them.
3553  l = Length(primitiveValue->computeLength(style, m_rootStyle, logicalDpiY), Fixed, primitiveValue->isQuirkValue());
3554  else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) {
3555  l = Length(primitiveValue->floatValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
3556  } else if (type == CSSPrimitiveValue::CSS_HTML_RELATIVE) {
3557  l = Length(int(primitiveValue->floatValue(CSSPrimitiveValue::CSS_HTML_RELATIVE)), Relative);
3558  } else {
3559  return;
3560  }
3561  apply = true;
3562  }
3563  if (!apply) {
3564  return;
3565  }
3566  switch (id) {
3567  case CSS_PROP_MAX_WIDTH:
3568  style->setMaxWidth(l); break;
3569  case CSS_PROP_BOTTOM:
3570  style->setBottom(l); break;
3571  case CSS_PROP_TOP:
3572  style->setTop(l); break;
3573  case CSS_PROP_LEFT:
3574  style->setLeft(l); break;
3575  case CSS_PROP_RIGHT:
3576  style->setRight(l); break;
3577  case CSS_PROP_WIDTH:
3578  style->setWidth(l); break;
3579  case CSS_PROP_MIN_WIDTH:
3580  style->setMinWidth(l); break;
3581  case CSS_PROP_PADDING_TOP:
3582  style->setPaddingTop(l); break;
3583  case CSS_PROP_PADDING_RIGHT:
3584  style->setPaddingRight(l); break;
3585  case CSS_PROP_PADDING_BOTTOM:
3586  style->setPaddingBottom(l); break;
3587  case CSS_PROP_PADDING_LEFT:
3588  style->setPaddingLeft(l); break;
3589  case CSS_PROP_MARGIN_TOP:
3590  style->setMarginTop(l); break;
3591  case CSS_PROP_MARGIN_RIGHT:
3592  style->setMarginRight(l); break;
3593  case CSS_PROP_MARGIN_BOTTOM:
3594  style->setMarginBottom(l); break;
3595  case CSS_PROP_MARGIN_LEFT:
3596  style->setMarginLeft(l); break;
3597  case CSS_PROP_TEXT_INDENT:
3598  style->setTextIndent(l); break;
3599  default: break;
3600  }
3601  return;
3602  }
3603 
3604  case CSS_PROP_MAX_HEIGHT:
3605  if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_NONE) {
3606  apply = true;
3607  l = Length(UNDEFINED, Fixed);
3608  }
3609  case CSS_PROP_HEIGHT:
3610  case CSS_PROP_MIN_HEIGHT:
3611  if (id != CSS_PROP_MAX_HEIGHT && primitiveValue &&
3612  primitiveValue->getIdent() == CSS_VAL_AUTO) {
3613  apply = true;
3614  }
3615  if (isInherit) {
3616  style->setInheritedNoninherited(true);
3617  HANDLE_INHERIT_COND(CSS_PROP_MAX_HEIGHT, maxHeight, MaxHeight)
3618  HANDLE_INHERIT_COND(CSS_PROP_HEIGHT, height, Height)
3619  HANDLE_INHERIT_COND(CSS_PROP_MIN_HEIGHT, minHeight, MinHeight)
3620  return;
3621  } else if (isInitial) {
3622  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MAX_HEIGHT, MaxHeight, MaxSize)
3623  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_HEIGHT, Height, Size)
3624  HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MIN_HEIGHT, MinHeight, MinSize)
3625  return;
3626  }
3627 
3628  if (primitiveValue && !apply) {
3629  int type = primitiveValue->primitiveType();
3630  if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) {
3631  l = Length(primitiveValue->computeLength(style, m_rootStyle, logicalDpiY), Fixed);
3632  } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) {
3633  l = Length(primitiveValue->floatValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
3634  } else {
3635  return;
3636  }
3637  apply = true;
3638  }
3639  if (!apply) {
3640  return;
3641  }
3642  switch (id) {
3643  case CSS_PROP_MAX_HEIGHT:
3644  style->setMaxHeight(l); break;
3645  case CSS_PROP_HEIGHT:
3646  style->setHeight(l); break;
3647  case CSS_PROP_MIN_HEIGHT:
3648  style->setMinHeight(l); break;
3649  default:
3650  return;
3651  }
3652  return;
3653 
3654  break;
3655 
3656  case CSS_PROP_VERTICAL_ALIGN:
3657  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(verticalAlign, VerticalAlign)
3658  if (!primitiveValue) {
3659  return;
3660  }
3661  if (primitiveValue->getIdent()) {
3662  khtml::EVerticalAlign align;
3663 
3664  switch (primitiveValue->getIdent()) {
3665  case CSS_VAL_TOP:
3666  align = TOP; break;
3667  case CSS_VAL_BOTTOM:
3668  align = BOTTOM; break;
3669  case CSS_VAL_MIDDLE:
3670  align = MIDDLE; break;
3671  case CSS_VAL_BASELINE:
3672  align = BASELINE; break;
3673  case CSS_VAL_TEXT_BOTTOM:
3674  align = TEXT_BOTTOM; break;
3675  case CSS_VAL_TEXT_TOP:
3676  align = TEXT_TOP; break;
3677  case CSS_VAL_SUB:
3678  align = SUB; break;
3679  case CSS_VAL_SUPER:
3680  align = SUPER; break;
3681  case CSS_VAL__KHTML_BASELINE_MIDDLE:
3682  align = BASELINE_MIDDLE; break;
3683  default:
3684  return;
3685  }
3686  style->setVerticalAlign(align);
3687  return;
3688  } else {
3689  int type = primitiveValue->primitiveType();
3690  Length l;
3691  if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) {
3692  l = Length(primitiveValue->computeLength(style, m_rootStyle, logicalDpiY), Fixed);
3693  } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) {
3694  l = Length(primitiveValue->floatValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
3695  }
3696 
3697  style->setVerticalAlign(LENGTH);
3698  style->setVerticalAlignLength(l);
3699  }
3700  break;
3701 
3702  case CSS_PROP_FONT_SIZE: {
3703  FontDef fontDef = style->htmlFont().fontDef;
3704  int size = 0;
3705 
3706  const bool isRootElement = element && (element->document()->documentElement() == element);
3707 
3708  if (isInherit) {
3709  size = parentStyle->font().pixelSize();
3710  } else if (isInitial) {
3711  size = m_fontSizes[3];
3712  } else if (primitiveValue->getIdent()) {
3713  // keywords are being used. Pick the correct default
3714  // based off the font family.
3715 #ifdef APPLE_CHANGES
3716  const QVector<int> &fontSizes = (fontDef.genericFamily == FontDef::eMonospace) ?
3717  m_fixedFontSizes : m_fontSizes;
3718 #else
3719  const QVector<int> &fontSizes = m_fontSizes;
3720 #endif
3721  int oldSize;
3722  if (parentNode) {
3723  oldSize = parentStyle->font().pixelSize();
3724  } else {
3725  oldSize = m_fontSizes[3];
3726  }
3727  switch (primitiveValue->getIdent()) {
3728  case CSS_VAL_XX_SMALL: size = fontSizes[0]; break;
3729  case CSS_VAL_X_SMALL: size = fontSizes[1]; break;
3730  case CSS_VAL_SMALL: size = fontSizes[2]; break;
3731  case CSS_VAL_MEDIUM: size = fontSizes[3]; break;
3732  case CSS_VAL_LARGE: size = fontSizes[4]; break;
3733  case CSS_VAL_X_LARGE: size = fontSizes[5]; break;
3734  case CSS_VAL_XX_LARGE: size = fontSizes[6]; break;
3735  case CSS_VAL__KHTML_XXX_LARGE: size = fontSizes[7]; break;
3736  case CSS_VAL_LARGER:
3737  size = nextFontSize(fontSizes, oldSize, false);
3738  break;
3739  case CSS_VAL_SMALLER:
3740  size = nextFontSize(fontSizes, oldSize, true);
3741  break;
3742  default:
3743  return;
3744  }
3745 
3746  } else {
3747  const int type = primitiveValue->primitiveType();
3748  if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) {
3749  // Scale for the font zoom factor only for types other than "em", "ex", "ch", "rem",
3750  // since those are already based on the font size.
3751  if (!khtml::printpainter && !(type >= CSSPrimitiveValue::CSS_EMS && type <= CSSPrimitiveValue::CSS_REMS) && view && view->part()) {
3752  size = qRound(primitiveValue->computeLengthFloat(parentStyle, m_rootStyle, logicalDpiY) * view->part()->fontScaleFactor() / 100.0);
3753  } else {
3754  size = qRound(primitiveValue->computeLengthFloat(parentStyle, isRootElement ? m_rootDefaultStyle : m_rootStyle, logicalDpiY));
3755  }
3756  } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
3757  size = qRound(primitiveValue->floatValue(CSSPrimitiveValue::CSS_PERCENTAGE) * parentStyle->font().pixelSize() / 100.0);
3758  else {
3759  return;
3760  }
3761 
3762  // we never want to get smaller than the minimum font size to keep fonts readable
3763  // do not however maximize zero as that is commonly used for fancy layouting purposes
3764  if (size) {
3765  size = qMax(size, m_minFontSize);
3766  }
3767  }
3768 
3769  //qCDebug(KHTML_LOG) << "computed raw font size: " << size;
3770 
3771  fontDef.size = size;
3772  fontDirty |= style->setFontDef(fontDef);
3773 
3774  if (isRootElement) {
3775  // We changed font size of root element, update now our root style reference
3776  // so that root css properties based on 'rem' unit are correctly computed
3777  // TESTCASE: html { font-size: 30px; width: 10rem; border: solid; }
3778  m_rootStyle = style;
3779  }
3780 
3781  return;
3782  }
3783 
3784  case CSS_PROP_Z_INDEX: {
3785  if (isInherit) {
3786  style->setInheritedNoninherited(true);
3787  if (parentStyle->hasAutoZIndex()) {
3788  style->setHasAutoZIndex();
3789  } else {
3790  style->setZIndex(parentStyle->zIndex());
3791  }
3792  return;
3793  }
3794 
3795  if (isInitial) {
3796  style->setHasAutoZIndex();
3797  return;
3798  }
3799 
3800  if (!primitiveValue) {
3801  return;
3802  }
3803 
3804  if (primitiveValue->getIdent() == CSS_VAL_AUTO) {
3805  style->setHasAutoZIndex();
3806  return;
3807  }
3808 
3809  if (primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER) {
3810  return; // Error case.
3811  }
3812 
3813  style->setZIndex((int)primitiveValue->floatValue(CSSPrimitiveValue::CSS_NUMBER));
3814  return;
3815  }
3816 
3817  case CSS_PROP_WIDOWS: {
3818  HANDLE_INITIAL_AND_INHERIT_ON_INHERITED_PROPERTY(widows, Widows)
3819  if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER) {
3820  return;
3821  }
3822  style->setWidows((short)primitiveValue->floatValue(CSSPrimitiveValue::CSS_NUMBER));
3823  break;
3824  }
3825 
3826  case CSS_PROP_ORPHANS: {
3827  HANDLE_INITIAL_AND_INHERIT_ON_INHERITED_PROPERTY(orphans, Orphans)
3828  if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER) {
3829  return;
3830  }
3831  style->setOrphans((short)primitiveValue->floatValue(CSSPrimitiveValue::CSS_NUMBER));
3832  break;
3833  }
3834 
3835 // length, percent, number
3836  case CSS_PROP_LINE_HEIGHT: {
3837  HANDLE_INITIAL_AND_INHERIT_ON_INHERITED_PROPERTY(lineHeight, LineHeight)
3838  if (!primitiveValue) {
3839  return;
3840  }
3841  Length lineHeight;
3842  const int type = primitiveValue->primitiveType();
3843  if (primitiveValue->getIdent() == CSS_VAL_NORMAL) {
3844  lineHeight = Length(-100.0, Percent);
3845  } else if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) {
3846  // Scale for the font zoom factor only for types other than "em", "ex", "ch", "rem",
3847  // since those are already based on the font size.
3848  if (!khtml::printpainter && !(type >= CSSPrimitiveValue::CSS_EMS && type <= CSSPrimitiveValue::CSS_REMS) && view && view->part()) {
3849  lineHeight = Length(primitiveValue->computeLength(style, m_rootStyle, logicalDpiY) * view->part()->fontScaleFactor() / 100, Fixed);
3850  } else {
3851  lineHeight = Length(primitiveValue->computeLength(style, m_rootStyle, logicalDpiY), Fixed);
3852  }
3853  } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) {
3854  lineHeight = Length((style->font().pixelSize() * int(primitiveValue->floatValue(CSSPrimitiveValue::CSS_PERCENTAGE))) / 100, Fixed);
3855  } else if (type == CSSPrimitiveValue::CSS_NUMBER) {
3856  lineHeight = Length(primitiveValue->floatValue(CSSPrimitiveValue::CSS_NUMBER) * 100.0, Percent);
3857  } else {
3858  return;
3859  }
3860  style->setLineHeight(lineHeight);
3861  return;
3862  }
3863 
3864 // string
3865  case CSS_PROP_TEXT_ALIGN: {
3866  HANDLE_INITIAL_AND_INHERIT_ON_INHERITED_PROPERTY(textAlign, TextAlign)
3867  if (!primitiveValue) {
3868  return;
3869  }
3870  if (primitiveValue->getIdent()) {
3871  style->setTextAlign((ETextAlign)(primitiveValue->getIdent() - CSS_VAL__KHTML_AUTO));
3872  }
3873  return;
3874  }
3875 
3876 // rect
3877  case CSS_PROP_CLIP: {
3878  Length top = Length();
3879  Length right = Length();
3880  Length bottom = Length();
3881  Length left = Length();
3882 
3883  bool hasClip = false;
3884 
3885  if (isInherit && parentStyle->hasClip()) {
3886  hasClip = true;
3887  top = parentStyle->clipTop();
3888  right = parentStyle->clipRight();
3889  bottom = parentStyle->clipBottom();
3890  left = parentStyle->clipLeft();
3891  } else if (primitiveValue && primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_RECT) {
3892  RectImpl *rect = primitiveValue->getRectValue();
3893  if (rect) {
3894  hasClip = true;
3895  // As a convention, we pass in auto as Length(Auto). See RenderBox::clipRect
3896  top = rect->top()->getIdent() == CSS_VAL_AUTO ? Length(Auto)
3897  : convertToLength(rect->top(), style, m_rootStyle, logicalDpiY);
3898 
3899  right = rect->right()->getIdent() == CSS_VAL_AUTO ? Length(Auto)
3900  : convertToLength(rect->right(), style, m_rootStyle, logicalDpiY);
3901 
3902  bottom = rect->bottom()->getIdent() == CSS_VAL_AUTO ? Length(Auto)
3903  : convertToLength(rect->bottom(), style, m_rootStyle, logicalDpiY);
3904 
3905  left = rect->left()->getIdent() == CSS_VAL_AUTO ? Length(Auto)
3906  : convertToLength(rect->left(), style, m_rootStyle, logicalDpiY);
3907  }
3908  }
3909 
3910  style->setClip(top, right, bottom, left);
3911  style->setHasClip(hasClip);
3912 
3913  // rect, ident
3914  break;
3915  }
3916 
3917 // lists
3918  case CSS_PROP_CONTENT:
3919  // list of string, uri, counter, attr, i
3920  {
3921  // FIXME: In CSS3, it will be possible to inherit content. In CSS2 it is not. This
3922  // note is a reminder that eventually "inherit" needs to be supported.
3923 
3924  // not allowed on non-generated pseudo-elements:
3925  if (style->styleType() == RenderStyle::FIRST_LETTER ||
3926  style->styleType() == RenderStyle::FIRST_LINE ||
3927  style->styleType() == RenderStyle::SELECTION) {
3928  break;
3929  }
3930 
3931  if (isInitial) {
3932  style->setContentNormal();
3933  return;
3934  }
3935 
3936  if (primitiveValue && primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_IDENT) {
3937  // normal | none
3938  if (primitiveValue->getIdent() == CSS_VAL_NORMAL) {
3939  style->setContentNormal();
3940  } else if (primitiveValue->getIdent() == CSS_VAL_NONE) {
3941  style->setContentNone();
3942  } else {
3943  assert(false);
3944  }
3945  return;
3946  }
3947 
3948  if (!value->isValueList()) {
3949  return;
3950  }
3951  CSSValueListImpl *list = static_cast<CSSValueListImpl *>(value);
3952  int len = list->length();
3953 
3954  style->setContentNormal(); // clear the content
3955 
3956  for (int i = 0; i < len; i++) {
3957  CSSValueImpl *item = list->item(i);
3958  if (!item->isPrimitiveValue()) {
3959  continue;
3960  }
3961  CSSPrimitiveValueImpl *val = static_cast<CSSPrimitiveValueImpl *>(item);
3962  if (val->primitiveType() == CSSPrimitiveValue::CSS_STRING) {
3963  style->addContent(val->getStringValue());
3964  } else if (val->primitiveType() == CSSPrimitiveValue::CSS_ATTR) {
3965  // TODO: setup dynamic attribute dependencies
3966  LocalName attrName;
3967  if (element->htmlCompat()) {
3968  attrName = LocalName::fromString(DOMString(val->getStringValue()).lower());
3969  } else {
3970  attrName = LocalName::fromString(val->getStringValue());
3971  }
3972  if (attrName.id()) {
3973  style->addContent(element->getAttribute(makeId(emptyNamespace, attrName.id())).implementation());
3974  } else {
3975  // qCDebug(KHTML_LOG) << "Attribute \"" << val->getStringValue() << "\" not found";
3976  }
3977  } else if (val->primitiveType() == CSSPrimitiveValue::CSS_URI) {
3978  CSSImageValueImpl *image = static_cast<CSSImageValueImpl *>(val);
3979  style->addContent(image->requestCssImage(element->document()));
3980  } else if (val->primitiveType() == CSSPrimitiveValue::CSS_COUNTER) {
3981  style->addContent(val->getCounterValue());
3982  } else if (val->primitiveType() == CSSPrimitiveValue::CSS_IDENT) {
3983  EQuoteContent quote;
3984  switch (val->getIdent()) {
3985  case CSS_VAL_OPEN_QUOTE:
3986  quote = OPEN_QUOTE;
3987  break;
3988  case CSS_VAL_NO_OPEN_QUOTE:
3989  quote = NO_OPEN_QUOTE;
3990  break;
3991  case CSS_VAL_CLOSE_QUOTE:
3992  quote = CLOSE_QUOTE;
3993  break;
3994  case CSS_VAL_NO_CLOSE_QUOTE:
3995  quote = NO_CLOSE_QUOTE;
3996  break;
3997  default:
3998  assert(false);
3999  quote = NO_QUOTE;
4000  }
4001  style->addContent(quote);
4002  } else {
4003  // qCDebug(KHTML_LOG) << "Unrecognized CSS content";
4004  }
4005  }
4006  break;
4007  }
4008 
4009  case CSS_PROP_COUNTER_INCREMENT: {
4010  if (!value->isValueList()) {
4011  return;
4012  }
4013 
4014  CSSValueListImpl *list = static_cast<CSSValueListImpl *>(value);
4015  style->setCounterIncrement(list);
4016  break;
4017  }
4018  case CSS_PROP_COUNTER_RESET: {
4019  if (!value->isValueList()) {
4020  return;
4021  }
4022 
4023  CSSValueListImpl *list = static_cast<CSSValueListImpl *>(value);
4024  style->setCounterReset(list);
4025  break;
4026  }
4027  case CSS_PROP_FONT_FAMILY:
4028  // list of strings and ids
4029  {
4030  if (isInherit) {
4031  FontDef parentFontDef = parentStyle->htmlFont().fontDef;
4032  FontDef fontDef = style->htmlFont().fontDef;
4033  fontDef.family = parentFontDef.family;
4034  if (style->setFontDef(fontDef)) {
4035  fontDirty = true;
4036  }
4037  return;
4038  } else if (isInitial) {
4039  FontDef fontDef = style->htmlFont().fontDef;
4040  FontDef initialDef = FontDef();
4041 #ifdef APPLE_CHANGES
4042  fontDef.family = initialDef.firstFamily();
4043 #else
4044  fontDef.family = initialDef.family;
4045 #endif
4046  if (style->setFontDef(fontDef)) {
4047  fontDirty = true;
4048  }
4049  return;
4050  }
4051  if (!value->isValueList()) {
4052  return;
4053  }
4054  FontDef fontDef = style->htmlFont().fontDef;
4055  CSSValueListImpl *list = static_cast<CSSValueListImpl *>(value);
4056  int len = list->length();
4057  bool hasFamilyName = false;
4058  for (int i = 0; i < len; i++) {
4059  CSSValueImpl *item = list->item(i);
4060  if (!item->isPrimitiveValue()) {
4061  continue;
4062  }
4063  CSSPrimitiveValueImpl *val = static_cast<CSSPrimitiveValueImpl *>(item);
4064  QString face;
4065  if (val->primitiveType() == CSSPrimitiveValue::CSS_STRING) {
4066  face = static_cast<FontFamilyValueImpl *>(val)->fontName();
4067  m_fontSelector->requestFamilyName(DOMString(face));
4068  } else if (val->primitiveType() == CSSPrimitiveValue::CSS_IDENT) {
4069  switch (val->getIdent()) {
4070  case CSS_VAL_SERIF:
4071  face = settings->serifFontName();
4072  break;
4073  case CSS_VAL_SANS_SERIF:
4074  face = settings->sansSerifFontName();
4075  break;
4076  case CSS_VAL_CURSIVE:
4077  face = settings->cursiveFontName();
4078  break;
4079  case CSS_VAL_FANTASY:
4080  face = settings->fantasyFontName();
4081  break;
4082  case CSS_VAL_MONOSPACE:
4083  face = settings->fixedFontName();
4084  break;
4085  default:
4086  return;
4087  }
4088  } else {
4089  return;
4090  }
4091  if (!face.isEmpty()) {
4092  if (!hasFamilyName) {
4093  fontDef.family = face;
4094  hasFamilyName = true;
4095  } else {
4096  fontDef.family += ",";
4097  fontDef.family += face;
4098  }
4099  }
4100  }
4101  if (hasFamilyName) {
4102  fontDirty |= style->setFontDef(fontDef);
4103  }
4104  break;
4105  }
4106  case CSS_PROP_QUOTES:
4107  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(quotes, Quotes)
4108  if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_NONE) {
4109  // set a set of empty quotes
4110  QuotesValueImpl *quotes = new QuotesValueImpl();
4111  style->setQuotes(quotes);
4112  } else {
4113  QuotesValueImpl *quotes = static_cast<QuotesValueImpl *>(value);
4114  style->setQuotes(quotes);
4115  }
4116  break;
4117  case CSS_PROP_SIZE:
4118  // ### look up
4119  break;
4120  case CSS_PROP_TEXT_DECORATION: {
4121  // list of ident
4122  HANDLE_INITIAL_AND_INHERIT_ON_INHERITED_PROPERTY(textDecoration, TextDecoration)
4123  int t = RenderStyle::initialTextDecoration();
4124  if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_NONE) {
4125  // do nothing
4126  } else {
4127  if (!value->isValueList()) {
4128  return;
4129  }
4130  CSSValueListImpl *list = static_cast<CSSValueListImpl *>(value);
4131  int len = list->length();
4132  for (int i = 0; i < len; i++) {
4133  CSSValueImpl *item = list->item(i);
4134  if (!item->isPrimitiveValue()) {
4135  continue;
4136  }
4137  primitiveValue = static_cast<CSSPrimitiveValueImpl *>(item);
4138  switch (primitiveValue->getIdent()) {
4139  case CSS_VAL_NONE:
4140  t = TDNONE; break;
4141  case CSS_VAL_UNDERLINE:
4142  t |= UNDERLINE; break;
4143  case CSS_VAL_OVERLINE:
4144  t |= OVERLINE; break;
4145  case CSS_VAL_LINE_THROUGH:
4146  t |= LINE_THROUGH; break;
4147  case CSS_VAL_BLINK:
4148  t |= BLINK; break;
4149  default:
4150  return;
4151  }
4152  }
4153  }
4154  style->setTextDecoration(t);
4155  break;
4156  }
4157  case CSS_PROP__KHTML_FLOW_MODE:
4158  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(flowAroundFloats, FlowAroundFloats)
4159  if (!primitiveValue) {
4160  return;
4161  }
4162  if (primitiveValue->getIdent()) {
4163  style->setFlowAroundFloats(primitiveValue->getIdent() == CSS_VAL__KHTML_AROUND_FLOATS);
4164  return;
4165  }
4166  break;
4167  case CSS_PROP__KHTML_USER_INPUT: {
4168  if (value->cssValueType() == CSSValue::CSS_INHERIT) {
4169  if (!parentNode) {
4170  return;
4171  }
4172  style->setUserInput(parentStyle->userInput());
4173 // qCDebug(KHTML_LOG) << "UI erm";
4174  return;
4175  }
4176  if (!primitiveValue) {
4177  return;
4178  }
4179  int id = primitiveValue->getIdent();
4180  if (id == CSS_VAL_NONE) {
4181  style->setUserInput(UI_NONE);
4182  } else {
4183  style->setUserInput(EUserInput(id - CSS_VAL_ENABLED));
4184  }
4185 // qCDebug(KHTML_LOG) << "userInput: " << style->userEdit();
4186  return;
4187  }
4188 
4189 // shorthand properties
4190  case CSS_PROP_BACKGROUND:
4191  if (isInitial) {
4192  style->setBackgroundColor(QColor());
4193  return;
4194  } else if (isInherit) {
4195  style->setInheritedNoninherited(true);
4196  style->inheritBackgroundLayers(*parentStyle->backgroundLayers());
4197  style->setBackgroundColor(parentStyle->backgroundColor());
4198  }
4199  break;
4200  case CSS_PROP_BORDER:
4201  case CSS_PROP_BORDER_STYLE:
4202  case CSS_PROP_BORDER_WIDTH:
4203  case CSS_PROP_BORDER_COLOR:
4204  if (isInherit) {
4205  style->setInheritedNoninherited(true);
4206  }
4207  if (id == CSS_PROP_BORDER || id == CSS_PROP_BORDER_COLOR) {
4208  if (isInherit) {
4209  style->setBorderTopColor(inheritedBorderColor(parentStyle, parentStyle->borderTopColor()));
4210  style->setBorderBottomColor(inheritedBorderColor(parentStyle, parentStyle->borderBottomColor()));
4211  style->setBorderLeftColor(inheritedBorderColor(parentStyle, parentStyle->borderLeftColor()));
4212  style->setBorderRightColor(inheritedBorderColor(parentStyle, parentStyle->borderRightColor()));
4213  } else if (isInitial) {
4214  style->setBorderTopColor(QColor()); // Reset to invalid color so currentColor is used instead.
4215  style->setBorderBottomColor(QColor());
4216  style->setBorderLeftColor(QColor());
4217  style->setBorderRightColor(QColor());
4218  }
4219  }
4220  if (id == CSS_PROP_BORDER || id == CSS_PROP_BORDER_STYLE) {
4221  if (isInherit) {
4222  style->setBorderTopStyle(parentStyle->borderTopStyle());
4223  style->setBorderBottomStyle(parentStyle->borderBottomStyle());
4224  style->setBorderLeftStyle(parentStyle->borderLeftStyle());
4225  style->setBorderRightStyle(parentStyle->borderRightStyle());
4226  } else if (isInitial) {
4227  style->setBorderTopStyle(RenderStyle::initialBorderStyle());
4228  style->setBorderBottomStyle(RenderStyle::initialBorderStyle());
4229  style->setBorderLeftStyle(RenderStyle::initialBorderStyle());
4230  style->setBorderRightStyle(RenderStyle::initialBorderStyle());
4231  }
4232  }
4233  if (id == CSS_PROP_BORDER || id == CSS_PROP_BORDER_WIDTH) {
4234  if (isInherit) {
4235  style->setBorderTopWidth(parentStyle->borderTopWidth());
4236  style->setBorderBottomWidth(parentStyle->borderBottomWidth());
4237  style->setBorderLeftWidth(parentStyle->borderLeftWidth());
4238  style->setBorderRightWidth(parentStyle->borderRightWidth());
4239  } else if (isInitial) {
4240  style->setBorderTopWidth(RenderStyle::initialBorderWidth());
4241  style->setBorderBottomWidth(RenderStyle::initialBorderWidth());
4242  style->setBorderLeftWidth(RenderStyle::initialBorderWidth());
4243  style->setBorderRightWidth(RenderStyle::initialBorderWidth());
4244  }
4245  }
4246  return;
4247  case CSS_PROP_BORDER_RADIUS:
4248  if (isInherit) {
4249  style->setInheritedNoninherited(true);
4250  style->setBorderTopLeftRadius(parentStyle->borderTopLeftRadius());
4251  style->setBorderTopRightRadius(parentStyle->borderTopRightRadius());
4252  style->setBorderBottomRightRadius(parentStyle->borderBottomRightRadius());
4253  style->setBorderBottomLeftRadius(parentStyle->borderBottomLeftRadius());
4254  } else if (isInitial) {
4255  style->setBorderTopLeftRadius(RenderStyle::initialBorderRadius());
4256  style->setBorderTopRightRadius(RenderStyle::initialBorderRadius());
4257  style->setBorderBottomRightRadius(RenderStyle::initialBorderRadius());
4258  style->setBorderBottomLeftRadius(RenderStyle::initialBorderRadius());
4259  }
4260  return;
4261  case CSS_PROP_BORDER_TOP:
4262  if (isInherit) {
4263  style->setInheritedNoninherited(true);
4264  style->setBorderTopColor(inheritedBorderColor(parentStyle, parentStyle->borderTopColor()));
4265  style->setBorderTopStyle(parentStyle->borderTopStyle());
4266  style->setBorderTopWidth(parentStyle->borderTopWidth());
4267  } else if (isInitial) {
4268  style->resetBorderTop();
4269  }
4270  return;
4271  case CSS_PROP_BORDER_RIGHT:
4272  if (isInherit) {
4273  style->setInheritedNoninherited(true);
4274  style->setBorderRightColor(inheritedBorderColor(parentStyle, parentStyle->borderRightColor()));
4275  style->setBorderRightStyle(parentStyle->borderRightStyle());
4276  style->setBorderRightWidth(parentStyle->borderRightWidth());
4277  } else if (isInitial) {
4278  style->resetBorderRight();
4279  }
4280  return;
4281  case CSS_PROP_BORDER_BOTTOM:
4282  if (isInherit) {
4283  style->setInheritedNoninherited(true);
4284  style->setBorderBottomColor(inheritedBorderColor(parentStyle, parentStyle->borderBottomColor()));
4285  style->setBorderBottomStyle(parentStyle->borderBottomStyle());
4286  style->setBorderBottomWidth(parentStyle->borderBottomWidth());
4287  } else if (isInitial) {
4288  style->resetBorderBottom();
4289  }
4290  return;
4291  case CSS_PROP_BORDER_LEFT:
4292  if (isInherit) {
4293  style->setInheritedNoninherited(true);
4294  style->setBorderLeftColor(inheritedBorderColor(parentStyle, parentStyle->borderLeftColor()));
4295  style->setBorderLeftStyle(parentStyle->borderLeftStyle());
4296  style->setBorderLeftWidth(parentStyle->borderLeftWidth());
4297  } else if (isInitial) {
4298  style->resetBorderLeft();
4299  }
4300  return;
4301  case CSS_PROP_MARGIN:
4302  if (isInherit) {
4303  style->setInheritedNoninherited(true);
4304  style->setMarginTop(parentStyle->marginTop());
4305  style->setMarginBottom(parentStyle->marginBottom());
4306  style->setMarginLeft(parentStyle->marginLeft());
4307  style->setMarginRight(parentStyle->marginRight());
4308  } else if (isInitial) {
4309  style->resetMargin();
4310  }
4311  return;
4312  case CSS_PROP_PADDING:
4313  if (isInherit) {
4314  style->setInheritedNoninherited(true);
4315  style->setPaddingTop(parentStyle->paddingTop());
4316  style->setPaddingBottom(parentStyle->paddingBottom());
4317  style->setPaddingLeft(parentStyle->paddingLeft());
4318  style->setPaddingRight(parentStyle->paddingRight());
4319  } else if (isInitial) {
4320  style->resetPadding();
4321  }
4322  return;
4323  case CSS_PROP_FONT:
4324  if (isInherit) {
4325  FontDef fontDef = parentStyle->htmlFont().fontDef;
4326  style->setLineHeight(parentStyle->lineHeight());
4327  fontDirty |= style->setFontDef(fontDef);
4328  } else if (isInitial) {
4329  FontDef fontDef;
4330  fontDef.size = m_fontSizes[3];
4331  style->setLineHeight(RenderStyle::initialLineHeight());
4332  fontDirty |= style->setFontDef(fontDef);
4333  } else if (primitiveValue) {
4334  // Handle system fonts. We extract out properties from a QFont
4335  // into the RenderStyle.
4336  QFont f;
4337  switch (primitiveValue->getIdent()) {
4338  case CSS_VAL_ICON:
4340  break;
4341 
4342  case CSS_VAL_MENU:
4344  break;
4345 
4346  case CSS_VAL_SMALL_CAPTION:
4348  break;
4349 
4350  case CSS_VAL_CAPTION:
4351  case CSS_VAL_MESSAGE_BOX:
4352  case CSS_VAL_STATUS_BAR:
4354  break;
4355  default:
4356  return;
4357  }
4358 
4359  FontDef fontDef = style->htmlFont().fontDef;
4360  fontDef.family = f.family();
4361  fontDef.italic = f.italic();
4362  fontDef.smallCaps = (f.capitalization() == QFont::SmallCaps);
4363  fontDef.weight = f.weight();
4364  fontDirty |= style->setFontDef(fontDef);
4365 
4366  // Use applyRule to apply height, so it can convert
4367  // point sizes, and cap pixel sizes appropriately.
4368  if (f.pixelSize() != -1) {
4369  CSSPrimitiveValueImpl size(f.pixelSize(), CSSPrimitiveValue::CSS_PX);
4370  applyRule(CSS_PROP_FONT_SIZE, &size);
4371  } else {
4372  CSSPrimitiveValueImpl size(f.pointSize(), CSSPrimitiveValue::CSS_PT);
4373  applyRule(CSS_PROP_FONT_SIZE, &size);
4374  }
4375 
4376  // line-height just gets default.
4377  style->setLineHeight(RenderStyle::initialLineHeight());
4378  }
4379  return;
4380 
4381  case CSS_PROP_LIST_STYLE:
4382  if (isInherit) {
4383  style->setListStyleType(parentStyle->listStyleType());
4384  style->setListStyleImage(parentStyle->listStyleImage());
4385  style->setListStylePosition(parentStyle->listStylePosition());
4386  } else if (isInitial) {
4387  style->setListStyleType(RenderStyle::initialListStyleType());
4388  style->setListStyleImage(RenderStyle::initialListStyleImage());
4389  style->setListStylePosition(RenderStyle::initialListStylePosition());
4390  }
4391  break;
4392  case CSS_PROP_OUTLINE:
4393  if (isInherit) {
4394  style->setInheritedNoninherited(true);
4395  style->setOutlineWidth(parentStyle->outlineWidth());
4396  style->setOutlineColor(parentStyle->outlineColor());
4397  style->setOutlineStyle(parentStyle->outlineStyle());
4398  } else if (isInitial) {
4399  style->resetOutline();
4400  }
4401  break;
4402  /* CSS3 properties */
4403  case CSS_PROP_BOX_SIZING:
4404  HANDLE_INHERIT_ON_NONINHERITED_PROPERTY(boxSizing, BoxSizing)
4405  if (!primitiveValue) {
4406  return;
4407  }
4408  if (primitiveValue->getIdent() == CSS_VAL_CONTENT_BOX) {
4409  style->setBoxSizing(CONTENT_BOX);
4410  } else if (primitiveValue->getIdent() == CSS_VAL_BORDER_BOX) {
4411  style->setBoxSizing(BORDER_BOX);
4412  }
4413  break;
4414  case CSS_PROP_OUTLINE_OFFSET: {
4415  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(outlineOffset, OutlineOffset)
4416 
4417  int offset = primitiveValue->computeLength(style, m_rootStyle, logicalDpiY);
4418  if (offset < 0) {
4419  return;
4420  }
4421 
4422  style->setOutlineOffset(offset);
4423  break;
4424  }
4425  case CSS_PROP_TEXT_SHADOW: {
4426  if (isInherit) {
4427  style->setTextShadow(parentStyle->textShadow() ? new ShadowData(*parentStyle->textShadow()) : nullptr);
4428  return;
4429  } else if (isInitial) {
4430  style->setTextShadow(nullptr);
4431  return;
4432  }
4433 
4434  if (primitiveValue) { // none
4435  style->setTextShadow(nullptr);
4436  return;
4437  }
4438 
4439  if (!value->isValueList()) {
4440  return;
4441  }
4442  CSSValueListImpl *list = static_cast<CSSValueListImpl *>(value);
4443  int len = list->length();
4444  for (int i = 0; i < len; i++) {
4445  ShadowValueImpl *item = static_cast<ShadowValueImpl *>(list->item(i));
4446 
4447  int x = item->x->computeLength(style, m_rootStyle, logicalDpiY);
4448  int y = item->y->computeLength(style, m_rootStyle, logicalDpiY);
4449  int blur = item->blur ? item->blur->computeLength(style, m_rootStyle, logicalDpiY) : 0;
4450  QColor col = khtml::transparentColor;
4451  if (item->color) {
4452  int ident = item->color->getIdent();
4453  if (ident) {
4454  col = colorForCSSValue(ident);
4455  } else if (item->color->primitiveType() == CSSPrimitiveValue::CSS_RGBCOLOR) {
4456  col.setRgba(item->color->getRGBColorValue());
4457  }
4458  }
4459  ShadowData *shadowData = new ShadowData(x, y, blur, col);
4460  style->setTextShadow(shadowData, i != 0);
4461  }
4462 
4463  break;
4464  }
4465  case CSS_PROP_OPACITY:
4466  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(opacity, Opacity)
4467  if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER) {
4468  return; // Error case.
4469  }
4470 
4471  // Clamp opacity to the range 0-1
4472  style->setOpacity(qMin(1.0f, qMax(0.0f, (float)primitiveValue->floatValue(CSSPrimitiveValue::CSS_NUMBER))));
4473  break;
4474  case CSS_PROP__KHTML_MARQUEE:
4475  if (value->cssValueType() != CSSValue::CSS_INHERIT || !parentNode) {
4476  return;
4477  }
4478  style->setMarqueeDirection(parentStyle->marqueeDirection());
4479  style->setMarqueeIncrement(parentStyle->marqueeIncrement());
4480  style->setMarqueeSpeed(parentStyle->marqueeSpeed());
4481  style->setMarqueeLoopCount(parentStyle->marqueeLoopCount());
4482  style->setMarqueeBehavior(parentStyle->marqueeBehavior());
4483  break;
4484  case CSS_PROP__KHTML_MARQUEE_REPETITION: {
4485  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(marqueeLoopCount, MarqueeLoopCount)
4486  if (!primitiveValue) {
4487  return;
4488  }
4489  if (primitiveValue->getIdent() == CSS_VAL_INFINITE) {
4490  style->setMarqueeLoopCount(-1); // -1 means repeat forever.
4491  } else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) {
4492  style->setMarqueeLoopCount((int)(primitiveValue->floatValue(CSSPrimitiveValue::CSS_NUMBER)));
4493  }
4494  break;
4495  }
4496  case CSS_PROP__KHTML_MARQUEE_SPEED: {
4497  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(marqueeSpeed, MarqueeSpeed)
4498  if (!primitiveValue) {
4499  return;
4500  }
4501  if (primitiveValue->getIdent()) {
4502  switch (primitiveValue->getIdent()) {
4503  case CSS_VAL_SLOW:
4504  style->setMarqueeSpeed(500); // 500 msec.
4505  break;
4506  case CSS_VAL_NORMAL:
4507  style->setMarqueeSpeed(85); // 85msec. The WinIE default.
4508  break;
4509  case CSS_VAL_FAST:
4510  style->setMarqueeSpeed(10); // 10msec. Super fast.
4511  break;
4512  }
4513  } else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_S) {
4514  style->setMarqueeSpeed(int(1000 * primitiveValue->floatValue(CSSPrimitiveValue::CSS_S)));
4515  } else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_MS) {
4516  style->setMarqueeSpeed(int(primitiveValue->floatValue(CSSPrimitiveValue::CSS_MS)));
4517  } else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) { // For scrollamount support.
4518  style->setMarqueeSpeed(int(primitiveValue->floatValue(CSSPrimitiveValue::CSS_NUMBER)));
4519  }
4520  break;
4521  }
4522  case CSS_PROP__KHTML_MARQUEE_INCREMENT: {
4523  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(marqueeIncrement, MarqueeIncrement)
4524  if (!primitiveValue) {
4525  return;
4526  }
4527  if (primitiveValue->getIdent()) {
4528  switch (primitiveValue->getIdent()) {
4529  case CSS_VAL_SMALL:
4530  style->setMarqueeIncrement(Length(1, Fixed)); // 1px.
4531  break;
4532  case CSS_VAL_NORMAL:
4533  style->setMarqueeIncrement(Length(6, Fixed)); // 6px. The WinIE default.
4534  break;
4535  case CSS_VAL_LARGE:
4536  style->setMarqueeIncrement(Length(36, Fixed)); // 36px.
4537  break;
4538  }
4539  } else {
4540  bool ok = true;
4541  Length l = convertToLength(primitiveValue, style, m_rootStyle, logicalDpiY, &ok);
4542  if (ok) {
4543  style->setMarqueeIncrement(l);
4544  }
4545  }
4546  break;
4547  }
4548  case CSS_PROP__KHTML_MARQUEE_STYLE: {
4549  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(marqueeBehavior, MarqueeBehavior)
4550  if (!primitiveValue || !primitiveValue->getIdent()) {
4551  return;
4552  }
4553  switch (primitiveValue->getIdent()) {
4554  case CSS_VAL_NONE:
4555  style->setMarqueeBehavior(MNONE);
4556  break;
4557  case CSS_VAL_SCROLL:
4558  style->setMarqueeBehavior(MSCROLL);
4559  break;
4560  case CSS_VAL_SLIDE:
4561  style->setMarqueeBehavior(MSLIDE);
4562  break;
4563  case CSS_VAL_ALTERNATE:
4564  style->setMarqueeBehavior(MALTERNATE);
4565  break;
4566  case CSS_VAL_UNFURL:
4567  style->setMarqueeBehavior(MUNFURL);
4568  break;
4569  }
4570  break;
4571  }
4572  case CSS_PROP__KHTML_MARQUEE_DIRECTION: {
4573  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(marqueeDirection, MarqueeDirection)
4574  if (!primitiveValue || !primitiveValue->getIdent()) {
4575  return;
4576  }
4577  switch (primitiveValue->getIdent()) {
4578  case CSS_VAL_FORWARDS:
4579  style->setMarqueeDirection(MFORWARD);
4580  break;
4581  case CSS_VAL_BACKWARDS:
4582  style->setMarqueeDirection(MBACKWARD);
4583  break;
4584  case CSS_VAL_AUTO:
4585  style->setMarqueeDirection(MAUTO);
4586  break;
4587  case CSS_VAL_AHEAD:
4588  case CSS_VAL_UP: // We don't support vertical languages, so AHEAD just maps to UP.
4589  style->setMarqueeDirection(MUP);
4590  break;
4591  case CSS_VAL_REVERSE:
4592  case CSS_VAL_DOWN: // REVERSE just maps to DOWN, since we don't do vertical text.
4593  style->setMarqueeDirection(MDOWN);
4594  break;
4595  case CSS_VAL_LEFT:
4596  style->setMarqueeDirection(MLEFT);
4597  break;
4598  case CSS_VAL_RIGHT:
4599  style->setMarqueeDirection(MRIGHT);
4600  break;
4601  }
4602  break;
4603  }
4604  case CSS_PROP_TEXT_OVERFLOW: {
4605  // This property is supported by WinIE, and so we leave off the "-khtml-" in order to
4606  // work with WinIE-specific pages that use the property.
4607  HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(textOverflow, TextOverflow)
4608  if (!primitiveValue || !primitiveValue->getIdent()) {
4609  return;
4610  }
4611  style->setTextOverflow(primitiveValue->getIdent() == CSS_VAL_ELLIPSIS);
4612  break;
4613  }
4614  case CSS_PROP_WORD_WRAP: {
4615  HANDLE_INITIAL_AND_INHERIT_ON_INHERITED_PROPERTY(wordWrap, WordWrap)
4616  if (!primitiveValue) {
4617  return;
4618  }
4619  style->setWordWrap(primitiveValue->getIdent() == CSS_VAL_NORMAL ? WWNORMAL : WWBREAKWORD);
4620  break;
4621  }
4622  default:
4623  applySVGRule(id, value);
4624  return;
4625  }
4626 }
4627 
4628 void CSSStyleSelector::mapBackgroundAttachment(BackgroundLayer *layer, DOM::CSSValueImpl *value)
4629 {
4630  if (value->cssValueType() == CSSValue::CSS_INITIAL) {
4631  layer->setBackgroundAttachment(RenderStyle::initialBackgroundAttachment());
4632  return;
4633  }
4634 
4635  if (!value->isPrimitiveValue()) {
4636  return;
4637  }
4638  CSSPrimitiveValueImpl *primitiveValue = static_cast<CSSPrimitiveValueImpl *>(value);
4639  switch (primitiveValue->getIdent()) {
4640  case CSS_VAL_SCROLL:
4641  layer->setBackgroundAttachment(BGASCROLL);
4642  break;
4643  case CSS_VAL_FIXED:
4644  layer->setBackgroundAttachment(BGAFIXED);
4645  break;
4646  case CSS_VAL_LOCAL:
4647  layer->setBackgroundAttachment(BGALOCAL);
4648  break;
4649  default:
4650  return;
4651  }
4652 }
4653 
4654 void CSSStyleSelector::mapBackgroundClip(BackgroundLayer *layer, CSSValueImpl *value)
4655 {
4656  if (value->cssValueType() == CSSValue::CSS_INITIAL) {
4657  layer->setBackgroundClip(RenderStyle::initialBackgroundClip());
4658  return;
4659  }
4660 
4661  if (!value->isPrimitiveValue()) {
4662  return;
4663  }
4664  CSSPrimitiveValueImpl *primitiveValue = static_cast<CSSPrimitiveValueImpl *>(value);
4665  switch (primitiveValue->getIdent()) {
4666  case CSS_VAL_BORDER_BOX:
4667  layer->setBackgroundClip(BGBORDER);
4668  break;
4669  case CSS_VAL_PADDING_BOX:
4670  layer->setBackgroundClip(BGPADDING);
4671  break;
4672  default: // CSS_VAL_CONTENT_BOX
4673  layer->setBackgroundClip(BGCONTENT);
4674  break;
4675  }
4676 }
4677 
4678 void CSSStyleSelector::mapBackgroundOrigin(BackgroundLayer *layer, CSSValueImpl *value)
4679 {
4680  if (value->cssValueType() == CSSValue::CSS_INITIAL) {
4681  layer->setBackgroundOrigin(RenderStyle::initialBackgroundOrigin());
4682  return;
4683  }
4684 
4685  if (!value->isPrimitiveValue()) {
4686  return;
4687  }
4688  CSSPrimitiveValueImpl *primitiveValue = static_cast<CSSPrimitiveValueImpl *>(value);
4689  switch (primitiveValue->getIdent()) {
4690  case CSS_VAL_BORDER_BOX:
4691  layer->setBackgroundOrigin(BGBORDER);
4692  break;
4693  case CSS_VAL_PADDING_BOX:
4694  layer->setBackgroundOrigin(BGPADDING);
4695  break;
4696  default: // CSS_VAL_CONTENT_BOX
4697  layer->setBackgroundOrigin(BGCONTENT);
4698  break;
4699  }
4700 }
4701 
4702 void CSSStyleSelector::mapBackgroundImage(BackgroundLayer *layer, DOM::CSSValueImpl *value)
4703 {
4704  if (value->cssValueType() == CSSValue::CSS_INITIAL) {
4705  layer->setBackgroundImage(RenderStyle::initialBackgroundImage());
4706  return;
4707  }
4708 
4709  if (!value->isPrimitiveValue()) {
4710  return;
4711  }
4712  CSSPrimitiveValueImpl *primitiveValue = static_cast<CSSPrimitiveValueImpl *>(value);
4713  layer->setBackgroundImage(static_cast<CSSImageValueImpl *>(primitiveValue)->requestCssImage(element->document()));
4714 }
4715 
4716 void CSSStyleSelector::mapBackgroundRepeat(BackgroundLayer *layer, DOM::CSSValueImpl *value)
4717 {
4718  if (value->cssValueType() == CSSValue::CSS_INITIAL) {
4719  layer->setBackgroundRepeat(RenderStyle::initialBackgroundRepeat());
4720  return;
4721  }
4722 
4723  if (!value->isPrimitiveValue()) {
4724  return;
4725  }
4726  CSSPrimitiveValueImpl *primitiveValue = static_cast<CSSPrimitiveValueImpl *>(value);
4727  switch (primitiveValue->getIdent()) {
4728  case CSS_VAL_REPEAT:
4729  layer->setBackgroundRepeat(REPEAT);
4730  break;
4731  case CSS_VAL_REPEAT_X:
4732  layer->setBackgroundRepeat(REPEAT_X);
4733  break;
4734  case CSS_VAL_REPEAT_Y:
4735  layer->setBackgroundRepeat(REPEAT_Y);
4736  break;
4737  case CSS_VAL_NO_REPEAT:
4738  layer->setBackgroundRepeat(NO_REPEAT);
4739  break;
4740  default:
4741  return;
4742  }
4743 }
4744 
4745 void CSSStyleSelector::mapBackgroundSize(BackgroundLayer *layer, CSSValueImpl *value)
4746 {
4747  if (value->cssValueType() == CSSValue::CSS_INITIAL) {
4748  layer->setBackgroundSize(RenderStyle::initialBackgroundSize());
4749  return;
4750  }
4751 
4752  if (!value->isPrimitiveValue()) {
4753  return;
4754  }
4755 
4756  CSSPrimitiveValueImpl *primitiveValue = static_cast<CSSPrimitiveValueImpl *>(value);
4757  const int id = primitiveValue->getIdent();
4758  if (id == CSS_VAL_CONTAIN) {
4759  layer->setBackgroundSize(BGSize(BGSCONTAIN));
4760  return;
4761  }
4762  if (id == CSS_VAL_COVER) {
4763  layer->setBackgroundSize(BGSize(BGSCOVER));
4764  return;
4765  }
4766 
4767  PairImpl *pair = primitiveValue->getPairValue();
4768  if (!pair) {
4769  return;
4770  }
4771 
4772  CSSPrimitiveValueImpl *first = static_cast<CSSPrimitiveValueImpl *>(pair->first());
4773  CSSPrimitiveValueImpl *second = static_cast<CSSPrimitiveValueImpl *>(pair->second());
4774 
4775  if (!first || !second) {
4776  return;
4777  }
4778 
4779  Length firstLength, secondLength;
4780 
4781  if (first->getIdent() == CSS_VAL_AUTO) {
4782  firstLength = Length(Auto);
4783  } else {
4784  const int type = first->primitiveType();
4785  if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) {
4786  firstLength = Length(first->computeLength(style, m_rootStyle, logicalDpiY), Fixed);
4787  } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) {
4788  firstLength = Length(first->floatValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
4789  } else {
4790  return;
4791  }
4792  }
4793 
4794  if (second->getIdent() == CSS_VAL_AUTO) {
4795  secondLength = Length(Auto);
4796  } else {
4797  const int type = second->primitiveType();
4798  if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) {
4799  secondLength = Length(second->computeLength(style, m_rootStyle, logicalDpiY), Fixed);
4800  } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) {
4801  secondLength = Length(second->floatValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
4802  } else {
4803  return;
4804  }
4805  }
4806 
4807  layer->setBackgroundSize(BGSize(firstLength, secondLength));
4808 }
4809 
4810 void CSSStyleSelector::mapBackgroundXPosition(BackgroundLayer *layer, DOM::CSSValueImpl *value)
4811 {
4812  if (value->cssValueType() == CSSValue::CSS_INITIAL) {
4813  layer->setBackgroundXPosition(RenderStyle::initialBackgroundXPosition());
4814  return;
4815  }
4816 
4817  if (!value->isPrimitiveValue()) {
4818  return;
4819  }
4820  CSSPrimitiveValueImpl *primitiveValue = static_cast<CSSPrimitiveValueImpl *>(value);
4821  Length l;
4822  int type = primitiveValue->primitiveType();
4823  if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) {
4824  l = Length(primitiveValue->computeLength(style, m_rootStyle, logicalDpiY), Fixed);
4825  } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) {
4826  l = Length(primitiveValue->floatValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
4827  } else {
4828  return;
4829  }
4830  layer->setBackgroundXPosition(l);
4831 }
4832 
4833 void CSSStyleSelector::mapBackgroundYPosition(BackgroundLayer *layer, DOM::CSSValueImpl *value)
4834 {
4835  if (value->cssValueType() == CSSValue::CSS_INITIAL) {
4836  layer->setBackgroundYPosition(RenderStyle::initialBackgroundYPosition());
4837  return;
4838  }
4839 
4840  if (!value->isPrimitiveValue()) {
4841  return;
4842  }
4843  CSSPrimitiveValueImpl *primitiveValue = static_cast<CSSPrimitiveValueImpl *>(value);
4844  Length l;
4845  int type = primitiveValue->primitiveType();
4846  if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) {
4847  l = Length(primitiveValue->computeLength(style, m_rootStyle, logicalDpiY), Fixed);
4848  } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) {
4849  l = Length(primitiveValue->floatValue(CSSPrimitiveValue::CSS_PERCENTAGE), Percent);
4850  } else {
4851  return;
4852  }
4853  layer->setBackgroundYPosition(l);
4854 }
4855 
4856 #ifdef APPLE_CHANGES
4857 void CSSStyleSelector::checkForGenericFamilyChange(RenderStyle *aStyle, RenderStyle *aParentStyle)
4858 {
4859  const FontDef &childFont = aStyle->htmlFont().fontDef;
4860 
4861  if (childFont.sizeSpecified || !aParentStyle) {
4862  return;
4863  }
4864 
4865  const FontDef &parentFont = aParentStyle->htmlFont().fontDef;
4866 
4867  if (childFont.genericFamily == parentFont.genericFamily) {
4868  return;
4869  }
4870 
4871  // For now, lump all families but monospace together.
4872  if (childFont.genericFamily != FontDef::eMonospace &&
4873  parentFont.genericFamily != FontDef::eMonospace) {
4874  return;
4875  }
4876 
4877  // We know the parent is monospace or the child is monospace, and that font
4878  // size was unspecified. We want to alter our font size to use the correct
4879  // "medium" font for our family.
4880  float size = 0;
4881  int minFontSize = settings->minFontSize();
4882  size = (childFont.genericFamily == FontDef::eMonospace) ? m_fixedFontSizes[3] : m_fontSizes[3];
4883  int isize = (int)size;
4884  if (isize < minFontSize) {
4885  isize = minFontSize;
4886  }
4887 
4888  FontDef newFontDef(childFont);
4889  newFontDef.size = isize;
4890  aStyle->setFontDef(newFontDef);
4891 }
4892 #endif
4893 
4894 // #### FIXME!! this is ugly and isn't even properly updated or destroyed.
4895 
4896 void CSSStyleSelector::addViewportDependentMediaQueryResult(const MediaQueryExp *expr, bool result)
4897 {
4898  m_viewportDependentMediaQueryResults.append(new MediaQueryResult(*expr, result));
4899 }
4900 
4901 bool CSSStyleSelector::affectedByViewportChange() const
4902 {
4903  const int s = m_viewportDependentMediaQueryResults.size();
4904  for (int i = 0; i < s; i++) {
4905  if (m_medium->eval(&m_viewportDependentMediaQueryResults.at(i)->m_expression) != m_viewportDependentMediaQueryResults.at(i)->m_result) {
4906  return true;
4907  }
4908  }
4909  return false;
4910 }
4911 
4912 } // namespace khtml
4913 
QString url(QUrl::FormattingOptions options) const const
Settings for the HTML view.
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
void setFragment(const QString &fragment, QUrl::ParsingMode mode)
int pixelSize() const const
The CSSNamespaceRule interface represents an.
Definition: css_rule.h:455
const T & next()
void append(const T &value)
void setRgba(QRgb rgba)
void append(const T &t)
int length() const const
int weight() const const
This file is part of the HTML rendering engine for KDE.
const T & at(int i) const const
Left
This class is khtml&#39;s main class.
Definition: khtml_part.h:208
Renders and displays HTML in a QScrollArea.
Definition: khtmlview.h:97
virtual bool contains(const QString &item) const
QFont::Capitalization capitalization() const const
QString & remove(int position, int n)
int size() const const
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
bool italic() const const
QVector< V > values(const QMultiHash< K, V > &c)
void setPath(const QString &path, QUrl::ParsingMode mode)
KHTMLPart * part() const
Returns a pointer to the KHTMLPart that is rendering the page.
Definition: khtmlview.h:139
QString fromRawData(const QChar *unicode, int size)
int count(const T &value) const const
void append(const T &value)
void resize(int size)
CaseSensitive
int toInt(bool *ok, int base) const const
bool isEmpty() const const
CSSStyleSelector(DOM::DocumentImpl *doc, QString userStyleSheet, DOM::StyleSheetListImpl *styleSheets, const QUrl &url, bool _strictParsing)
creates a new StyleSelector for a Document.
bool eval(const DOM::MediaListImpl *, CSSStyleSelector *=nullptr) const
Evaluates a list of media queries.
Author
This class implements the basic string we use in the DOM.
Definition: dom_string.h:44
qint64 read(char *data, qint64 maxSize)
Direction
virtual bool open(QIODevice::OpenMode mode) override
the StyleSelector implementation for CSS.
ushort unicode() const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
Width
virtual qint64 size() const const override
QStringRef midRef(int position, int n) const const
QCA_EXPORT void init()
This library provides a full-featured HTML parser and widget.
QFont systemFont(QFontDatabase::SystemFont type)
Top
QString mid(int position, int n) const const
Class that evaluates css media queries as defined in CSS3 Module "Media Queries" (https://www.w3.org/TR/css3-mediaqueries/) Special constructors are needed, if simple media queries are to be evaluated without knowledge of the medium features.
virtual void close() override
int count() const const
QString family() const const
int count(const T &value) const const
Base Class for all rendering tree objects.
int length() const const
int fontScaleFactor() const
Returns the current font scale factor.
void setQuery(const QString &query, QUrl::ParsingMode mode)
Height
int size() const const
const KHTMLSettings * settings() const
int pointSize() const const
QString locate(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options)
bool isValid() const const
bool hasNext() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Oct 16 2021 22:47:51 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.