File indexing completed on 2024-04-21 11:29:32
0001 /** 0002 * This file is part of the CSS implementation for KDE. 0003 * 0004 * Copyright 1999-2003 Lars Knoll (knoll@kde.org) 0005 * Copyright 2003-2004 Apple Computer, Inc. 0006 * Copyright 2004-2010 Allan Sandfeld Jensen (kde@carewolf.com) 0007 * Copyright 2004-2008 Germain Garand (germain@ebooksfrance.org) 0008 * Copyright 2008 Vyacheslav Tokarev (tsjoker@gmail.com) 0009 * (C) 2005, 2006, 2008 Apple Computer, Inc. 0010 * 0011 * This library is free software; you can redistribute it and/or 0012 * modify it under the terms of the GNU Library General Public 0013 * License as published by the Free Software Foundation; either 0014 * version 2 of the License, or (at your option) any later version. 0015 * 0016 * This library is distributed in the hope that it will be useful, 0017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0019 * Library General Public License for more details. 0020 * 0021 * You should have received a copy of the GNU Library General Public License 0022 * along with this library; see the file COPYING.LIB. If not, write to 0023 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0024 * Boston, MA 02110-1301, USA. 0025 */ 0026 0027 #include "css/cssstyleselector.h" 0028 #include "css/css_stylesheetimpl.h" 0029 #include "css/css_ruleimpl.h" 0030 #include "css/css_valueimpl.h" 0031 #include "css/csshelper.h" 0032 #include "css/css_webfont.h" 0033 #include "rendering/render_object.h" 0034 #include "html/html_documentimpl.h" 0035 #include "html/html_elementimpl.h" 0036 #include "xml/dom_elementimpl.h" 0037 #include "xml/dom_restyler.h" 0038 #include "dom/css_rule.h" 0039 #include "dom/css_value.h" 0040 #include "khtml_global.h" 0041 #include "khtmlpart_p.h" 0042 using namespace khtml; 0043 using namespace DOM; 0044 0045 #include "css/cssproperties.h" 0046 #include "css/cssvalues.h" 0047 0048 #include "misc/khtmllayout.h" 0049 #include "khtml_settings.h" 0050 #include "misc/helper.h" 0051 #include "misc/loader.h" 0052 0053 #include "rendering/font.h" 0054 0055 #include "khtmlview.h" 0056 #include "khtml_part.h" 0057 0058 #include <kconfig.h> 0059 #include <QFile> 0060 #include <QString> 0061 #include <QFileInfo> 0062 #include <QUrl> 0063 #include <QFontDatabase> 0064 #include <qstandardpaths.h> 0065 0066 #include "khtml_debug.h" 0067 #include <assert.h> 0068 #include <stdlib.h> 0069 0070 // keep in sync with html4.css' 0071 #define KHTML_STYLE_VERSION 1 0072 0073 #undef PRELATIVE 0074 #undef PABSOLUTE 0075 0076 // handle value "inherit" on a default inherited property 0077 #define HANDLE_INHERIT_ON_INHERITED_PROPERTY(prop, Prop) \ 0078 if (isInherit) \ 0079 {\ 0080 style->set##Prop(parentStyle->prop());\ 0081 return;\ 0082 } 0083 0084 // handle value "inherit" on a default non-inherited property 0085 #define HANDLE_INHERIT_ON_NONINHERITED_PROPERTY(prop, Prop) \ 0086 if (isInherit) \ 0087 {\ 0088 style->setInheritedNoninherited(true);\ 0089 style->set##Prop(parentStyle->prop());\ 0090 return;\ 0091 } 0092 0093 #define HANDLE_INITIAL(prop, Prop) \ 0094 if (isInitial) \ 0095 {\ 0096 style->set##Prop(RenderStyle::initial##Prop());\ 0097 return;\ 0098 } 0099 0100 #define HANDLE_INITIAL_AND_INHERIT_ON_NONINHERITED_PROPERTY(prop, Prop) \ 0101 HANDLE_INITIAL(prop, Prop) \ 0102 else \ 0103 HANDLE_INHERIT_ON_NONINHERITED_PROPERTY(prop, Prop) 0104 0105 #define HANDLE_INITIAL_AND_INHERIT_ON_INHERITED_PROPERTY(prop, Prop) \ 0106 HANDLE_INITIAL(prop, Prop) \ 0107 else \ 0108 HANDLE_INHERIT_ON_INHERITED_PROPERTY(prop, Prop) 0109 0110 // all non-inherited properties 0111 #define HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(prop, Prop, Value) \ 0112 HANDLE_INHERIT_ON_NONINHERITED_PROPERTY(prop, Prop) \ 0113 else if (isInitial) \ 0114 {\ 0115 style->set##Prop(RenderStyle::initial##Value());\ 0116 return;\ 0117 } 0118 0119 #define HANDLE_BACKGROUND_INHERIT_AND_INITIAL(prop, Prop) \ 0120 if (isInherit) { \ 0121 style->setInheritedNoninherited(true); \ 0122 BackgroundLayer* currChild = style->accessBackgroundLayers(); \ 0123 BackgroundLayer* prevChild = nullptr; \ 0124 const BackgroundLayer* currParent = parentStyle->backgroundLayers(); \ 0125 while (currParent && currParent->is##Prop##Set()) { \ 0126 if (!currChild) { \ 0127 /* Need to make a new layer.*/ \ 0128 currChild = new BackgroundLayer(); \ 0129 prevChild->setNext(currChild); \ 0130 } \ 0131 currChild->set##Prop(currParent->prop()); \ 0132 prevChild = currChild; \ 0133 currChild = prevChild->next(); \ 0134 currParent = currParent->next(); \ 0135 } \ 0136 \ 0137 while (currChild) { \ 0138 /* Reset any remaining layers to not have the property set. */ \ 0139 currChild->clear##Prop(); \ 0140 currChild = currChild->next(); \ 0141 } \ 0142 } else if (isInitial) { \ 0143 BackgroundLayer* currChild = style->accessBackgroundLayers(); \ 0144 currChild->set##Prop(RenderStyle::initial##Prop()); \ 0145 for (currChild = currChild->next(); currChild; currChild = currChild->next()) \ 0146 currChild->clear##Prop(); \ 0147 } 0148 0149 #define HANDLE_BACKGROUND_VALUE(prop, Prop, value) { \ 0150 HANDLE_BACKGROUND_INHERIT_AND_INITIAL(prop, Prop) \ 0151 else { \ 0152 if (!value->isPrimitiveValue() && !value->isValueList()) \ 0153 return; \ 0154 BackgroundLayer* currChild = style->accessBackgroundLayers(); \ 0155 BackgroundLayer* prevChild = nullptr; \ 0156 if (value->isPrimitiveValue()) { \ 0157 map##Prop(currChild, value); \ 0158 currChild = currChild->next(); \ 0159 } \ 0160 else { \ 0161 /* Walk each value and put it into a layer, creating new layers as needed. */ \ 0162 CSSValueListImpl* valueList = static_cast<CSSValueListImpl*>(value); \ 0163 for (unsigned int i = 0; i < valueList->length(); i++) { \ 0164 if (!currChild) { \ 0165 /* Need to make a new layer to hold this value */ \ 0166 currChild = new BackgroundLayer(); \ 0167 prevChild->setNext(currChild); \ 0168 } \ 0169 map##Prop(currChild, valueList->item(i)); \ 0170 prevChild = currChild; \ 0171 currChild = currChild->next(); \ 0172 } \ 0173 } \ 0174 while (currChild) { \ 0175 /* Reset all remaining layers to not have the property set. */ \ 0176 currChild->clear##Prop(); \ 0177 currChild = currChild->next(); \ 0178 } \ 0179 } } 0180 0181 #define HANDLE_INHERIT_COND(propID, prop, Prop) \ 0182 if (id == propID) \ 0183 {\ 0184 style->set##Prop(parentStyle->prop());\ 0185 return;\ 0186 } 0187 0188 #define HANDLE_INHERIT_COND_WITH_BACKUP(propID, prop, propAlt, Prop) \ 0189 if (id == propID) { \ 0190 if (parentStyle->prop().isValid()) \ 0191 style->set##Prop(parentStyle->prop()); \ 0192 else \ 0193 style->set##Prop(parentStyle->propAlt()); \ 0194 return; \ 0195 } 0196 0197 #define HANDLE_INITIAL_COND(propID, Prop) \ 0198 if (id == propID) \ 0199 {\ 0200 style->set##Prop(RenderStyle::initial##Prop());\ 0201 return;\ 0202 } 0203 0204 #define HANDLE_INITIAL_COND_WITH_VALUE(propID, Prop, Value) \ 0205 if (id == propID) \ 0206 {\ 0207 style->set##Prop(RenderStyle::initial##Value());\ 0208 return;\ 0209 } 0210 0211 namespace khtml 0212 { 0213 0214 CSSStyleSelectorList *CSSStyleSelector::s_defaultStyle; 0215 CSSStyleSelectorList *CSSStyleSelector::s_defaultQuirksStyle; 0216 CSSStyleSelectorList *CSSStyleSelector::s_defaultNonCSSHintsStyle; 0217 CSSStyleSelectorList *CSSStyleSelector::s_defaultPrintStyle; 0218 CSSStyleSheetImpl *CSSStyleSelector::s_defaultSheet; 0219 CSSStyleSheetImpl *CSSStyleSelector::s_defaultNonCSSHintsSheet; 0220 RenderStyle *CSSStyleSelector::styleNotYetAvailable; 0221 CSSStyleSheetImpl *CSSStyleSelector::s_quirksSheet; 0222 0223 enum PseudoState { PseudoUnknown, PseudoNone, PseudoLink, PseudoVisited}; 0224 static PseudoState pseudoState; 0225 0226 CSSStyleSelector::CSSStyleSelector(DocumentImpl *doc, QString userStyleSheet, StyleSheetListImpl *styleSheets, 0227 const QUrl &url, bool _strictParsing) 0228 { 0229 KHTMLView *view = doc->view(); 0230 KHTMLPart *part = doc->part(); 0231 0232 m_fontSelector = new CSSFontSelector(doc); 0233 0234 init(part ? part->settings() : nullptr, doc); 0235 0236 strictParsing = _strictParsing; 0237 0238 selectors = nullptr; 0239 selectorCache = nullptr; 0240 propertiesBuffer = nullptr; 0241 nextPropertyIndexes = nullptr; 0242 userStyle = nullptr; 0243 userSheet = nullptr; 0244 logicalDpiY = doc->logicalDpiY(); 0245 0246 if (logicalDpiY) { // this may be null, not everyone uses khtmlview (Niko) 0247 computeFontSizes(logicalDpiY, part ? part->fontScaleFactor() : 100); 0248 } 0249 0250 // build a limited default style suitable to evaluation of media queries 0251 // containing relative constraints, like "screen and (max-width: 10em)" 0252 setupDefaultRootStyle(doc); 0253 0254 if (view) { 0255 m_medium = new MediaQueryEvaluator(view->mediaType(), view->part(), m_rootDefaultStyle); 0256 } else { 0257 m_medium = new MediaQueryEvaluator("all", nullptr, m_rootDefaultStyle); 0258 } 0259 0260 if (!userStyleSheet.isEmpty()) { 0261 userSheet = new DOM::CSSStyleSheetImpl(doc); 0262 userSheet->parseString(DOMString(userStyleSheet)); 0263 0264 userStyle = new CSSStyleSelectorList(); 0265 userStyle->append(userSheet, m_medium, this); 0266 } 0267 0268 // add stylesheets from document 0269 authorStyle = nullptr; 0270 implicitStyle = nullptr; 0271 0272 foreach (StyleSheetImpl *sh, styleSheets->styleSheets) { 0273 if (sh->isCSSStyleSheet()) { 0274 if (static_cast<CSSStyleSheetImpl *>(sh)->implicit()) { 0275 if (!implicitStyle) { 0276 implicitStyle = new CSSStyleSelectorList(); 0277 } 0278 implicitStyle->append(static_cast<CSSStyleSheetImpl *>(sh), m_medium, this); 0279 } else if (sh->isCSSStyleSheet() && !sh->disabled()) { 0280 if (!authorStyle) { 0281 authorStyle = new CSSStyleSelectorList(); 0282 } 0283 authorStyle->append(static_cast<CSSStyleSheetImpl *>(sh), m_medium, this); 0284 } 0285 } 0286 } 0287 0288 buildLists(); 0289 0290 //qCDebug(KHTML_LOG) << "number of style sheets in document " << authorStyleSheets.count(); 0291 //qCDebug(KHTML_LOG) << "CSSStyleSelector: author style has " << authorStyle->count() << " elements"; 0292 0293 QUrl u = url; 0294 0295 u.setQuery(QString()); 0296 u.setFragment(QString()); 0297 encodedurl.file = u.url(); 0298 int pos = encodedurl.file.lastIndexOf('/'); 0299 encodedurl.path = encodedurl.file; 0300 if (pos > 0) { 0301 encodedurl.path.truncate(pos); 0302 encodedurl.path += '/'; 0303 } 0304 u.setPath(QString()); 0305 encodedurl.host = u.url(); 0306 0307 //qCDebug(KHTML_LOG) << "CSSStyleSelector::CSSStyleSelector encoded url " << encodedurl.path; 0308 } 0309 0310 CSSStyleSelector::CSSStyleSelector(CSSStyleSheetImpl *sheet) 0311 { 0312 m_fontSelector = new CSSFontSelector(sheet->doc()); 0313 0314 init(nullptr, nullptr); 0315 0316 KHTMLView *view = sheet->doc()->view(); 0317 0318 setupDefaultRootStyle(sheet->doc()); 0319 0320 if (view) { 0321 m_medium = new MediaQueryEvaluator(view->mediaType(), view->part(), m_rootDefaultStyle); 0322 } else { 0323 m_medium = new MediaQueryEvaluator("screen", nullptr, m_rootDefaultStyle); 0324 } 0325 0326 if (sheet->implicit()) { 0327 implicitStyle = new CSSStyleSelectorList(); 0328 implicitStyle->append(sheet, m_medium, this); 0329 } else { 0330 authorStyle = new CSSStyleSelectorList(); 0331 authorStyle->append(sheet, m_medium, this); 0332 } 0333 } 0334 0335 void CSSStyleSelector::init(const KHTMLSettings *_settings, DocumentImpl *doc) 0336 { 0337 element = nullptr; 0338 settings = _settings; 0339 logicalDpiY = 0; 0340 if (!s_defaultStyle) { 0341 loadDefaultStyle(settings, doc); 0342 } 0343 0344 defaultStyle = s_defaultStyle; 0345 defaultPrintStyle = s_defaultPrintStyle; 0346 defaultQuirksStyle = s_defaultQuirksStyle; 0347 defaultNonCSSHintsStyle = s_defaultNonCSSHintsStyle; 0348 m_rootDefaultStyle = nullptr; 0349 m_medium = nullptr; 0350 } 0351 0352 CSSStyleSelector::~CSSStyleSelector() 0353 { 0354 clearLists(); 0355 delete authorStyle; 0356 delete implicitStyle; 0357 delete userStyle; 0358 delete userSheet; 0359 delete m_rootDefaultStyle; 0360 delete m_medium; 0361 delete m_fontSelector; 0362 } 0363 0364 void CSSStyleSelector::addSheet(CSSStyleSheetImpl *sheet) 0365 { 0366 KHTMLView *view = sheet->doc()->view(); 0367 0368 setupDefaultRootStyle(sheet->doc()); 0369 0370 delete m_medium; m_medium = nullptr; 0371 delete authorStyle; authorStyle = nullptr; 0372 delete implicitStyle; implicitStyle = nullptr; 0373 0374 if (view) { 0375 m_medium = new MediaQueryEvaluator(view->mediaType(), view->part(), m_rootDefaultStyle); 0376 } else { 0377 m_medium = new MediaQueryEvaluator("screen", nullptr, m_rootDefaultStyle); 0378 } 0379 0380 if (sheet->implicit()) { 0381 if (!implicitStyle) { 0382 implicitStyle = new CSSStyleSelectorList(); 0383 } 0384 implicitStyle->append(sheet, m_medium, this); 0385 } else { 0386 if (!authorStyle) { 0387 authorStyle = new CSSStyleSelectorList(); 0388 } 0389 authorStyle->append(sheet, m_medium, this); 0390 } 0391 } 0392 0393 void CSSStyleSelector::loadDefaultStyle(const KHTMLSettings *s, DocumentImpl *doc) 0394 { 0395 if (s_defaultStyle) { 0396 return; 0397 } 0398 0399 MediaQueryEvaluator screenEval("screen"); 0400 MediaQueryEvaluator printEval("print"); 0401 0402 { 0403 QFile f(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kf5/khtml/css/html4.css")); 0404 f.open(QIODevice::ReadOnly); 0405 0406 QByteArray file(f.size() + 1, 0); 0407 int readbytes = f.read(file.data(), f.size()); 0408 f.close(); 0409 if (readbytes >= 0) { 0410 file[readbytes] = '\0'; 0411 } 0412 0413 QString style = QLatin1String(file.data()); 0414 0415 QRegExp checkVersion("KHTML_STYLE_VERSION:\\s*(\\d+)"); 0416 checkVersion.setMinimal(true); 0417 if (checkVersion.indexIn(style) == -1 || checkVersion.cap(1).toInt() != KHTML_STYLE_VERSION) { 0418 qFatal("!!!!!!! ERROR !!!!!!! - KHTML default stylesheet version mismatch. Aborting. Check your installation. File used was: %s. Expected STYLE_VERSION %d\n", 0419 QFileInfo(f).absoluteFilePath().toLatin1().data(), KHTML_STYLE_VERSION); 0420 } 0421 0422 if (s) { 0423 style += s->settingsToCSS(); 0424 } 0425 DOMString str(style); 0426 0427 s_defaultSheet = new DOM::CSSStyleSheetImpl(doc); 0428 s_defaultSheet->parseString(str); 0429 0430 // Collect only strict-mode rules. 0431 s_defaultStyle = new CSSStyleSelectorList(); 0432 s_defaultStyle->append(s_defaultSheet, &screenEval, doc->styleSelector()); 0433 0434 s_defaultPrintStyle = new CSSStyleSelectorList(); 0435 s_defaultPrintStyle->append(s_defaultSheet, &printEval, doc->styleSelector()); 0436 } 0437 { 0438 QFile f(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kf5/khtml/css/quirks.css")); 0439 f.open(QIODevice::ReadOnly); 0440 0441 QByteArray file(f.size() + 1, 0); 0442 int readbytes = f.read(file.data(), f.size()); 0443 f.close(); 0444 if (readbytes >= 0) { 0445 file[readbytes] = '\0'; 0446 } 0447 0448 QString style = QLatin1String(file.data()); 0449 DOMString str(style); 0450 0451 s_quirksSheet = new DOM::CSSStyleSheetImpl(doc); 0452 s_quirksSheet->parseString(str); 0453 0454 // Collect only quirks-mode rules. 0455 s_defaultQuirksStyle = new CSSStyleSelectorList(); 0456 s_defaultQuirksStyle->append(s_quirksSheet, &screenEval, doc->styleSelector()); 0457 } 0458 { 0459 QFile f(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kf5/khtml/css/presentational.css")); 0460 f.open(QIODevice::ReadOnly); 0461 0462 QByteArray file(f.size() + 1, 0); 0463 int readbytes = f.read(file.data(), f.size()); 0464 f.close(); 0465 if (readbytes >= 0) { 0466 file[readbytes] = '\0'; 0467 } 0468 0469 QString style = QLatin1String(file.data()); 0470 DOMString str(style); 0471 0472 s_defaultNonCSSHintsSheet = new DOM::CSSStyleSheetImpl(doc); 0473 s_defaultNonCSSHintsSheet->parseString(str); 0474 0475 s_defaultNonCSSHintsStyle = new CSSStyleSelectorList(); 0476 s_defaultNonCSSHintsStyle->append(s_defaultNonCSSHintsSheet, &screenEval, doc->styleSelector()); 0477 } 0478 //qCDebug(KHTML_LOG) << "CSSStyleSelector: default style has " << defaultStyle->count() << " elements"; 0479 } 0480 0481 void CSSStyleSelector::clear() 0482 { 0483 delete s_defaultStyle; 0484 delete s_defaultQuirksStyle; 0485 delete s_defaultPrintStyle; 0486 delete s_defaultNonCSSHintsStyle; 0487 delete s_defaultSheet; 0488 delete s_defaultNonCSSHintsSheet; 0489 delete styleNotYetAvailable; 0490 s_defaultStyle = nullptr; 0491 s_defaultQuirksStyle = nullptr; 0492 s_defaultPrintStyle = nullptr; 0493 s_defaultNonCSSHintsStyle = nullptr; 0494 s_defaultSheet = nullptr; 0495 s_defaultNonCSSHintsSheet = nullptr; 0496 styleNotYetAvailable = nullptr; 0497 } 0498 0499 void CSSStyleSelector::reparseConfiguration() 0500 { 0501 // nice leak, but best we can do right now. hopefully it is only rare. 0502 s_defaultStyle = nullptr; 0503 s_defaultQuirksStyle = nullptr; 0504 s_defaultPrintStyle = nullptr; 0505 s_defaultNonCSSHintsStyle = nullptr; 0506 s_defaultSheet = nullptr; 0507 } 0508 0509 #define MAXFONTSIZES 8 0510 0511 void CSSStyleSelector::computeFontSizes(int logicalDpiY, int zoomFactor) 0512 { 0513 computeFontSizesFor(logicalDpiY, zoomFactor, m_fontSizes, false); 0514 computeFontSizesFor(logicalDpiY, zoomFactor, m_fixedFontSizes, true); 0515 } 0516 0517 void CSSStyleSelector::computeFontSizesFor(int logicalDpiY, int zoomFactor, QVector<int> &fontSizes, bool isFixed) 0518 { 0519 #ifdef APPLE_CHANGES 0520 // We don't want to scale the settings by the dpi. 0521 const float toPix = 1.0; 0522 #else 0523 Q_UNUSED(isFixed); 0524 0525 const float toPix = qMax(logicalDpiY, 96) / 72.0f; 0526 #endif // ######### fix isFixed code again. 0527 0528 fontSizes.resize(MAXFONTSIZES); 0529 float scale = 1.0; 0530 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}; 0531 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}; 0532 float mediumFontSize, factor; 0533 if (!khtml::printpainter) { 0534 scale *= zoomFactor / 100.0; 0535 #ifdef APPLE_CHANGES 0536 if (isFixed) { 0537 mediumFontSize = settings->mediumFixedFontSize() * toPix; 0538 } else 0539 #endif 0540 mediumFontSize = settings->mediumFontSize() * toPix; 0541 m_minFontSize = settings->minFontSize() * toPix; 0542 } else { 0543 // ### depending on something / configurable ? 0544 mediumFontSize = 12; 0545 m_minFontSize = 6; 0546 } 0547 const float *factors = scale * mediumFontSize >= 12.5 ? fontFactors : smallFontFactors; 0548 for (int i = 0; i < MAXFONTSIZES; i++) { 0549 factor = scale * factors[i]; 0550 fontSizes[i] = qMax(qRound(mediumFontSize * factor), m_minFontSize); 0551 //qCDebug(KHTML_LOG) << "index:" << i << "factor:" << factors[i] << "font pix size:" << fontSizes[i]; 0552 } 0553 } 0554 0555 #undef MAXFONTSIZES 0556 0557 RenderStyle *CSSStyleSelector::locateSimilarStyle() 0558 { 0559 ElementImpl *s = nullptr, *t = nullptr, *c = nullptr; 0560 if (!element) { 0561 return nullptr; 0562 } 0563 // Check previous siblings. 0564 unsigned count = 0; 0565 NodeImpl *n = element; 0566 do { 0567 for (n = n->previousSibling(); n && !n->isElementNode(); n = n->previousSibling()); 0568 if (!n) { 0569 break; 0570 } 0571 ElementImpl *e = static_cast<ElementImpl *>(n); 0572 if (++count > 10) { 0573 break; 0574 } 0575 if (!s) { 0576 s = e; // sibling match 0577 } 0578 if (e->id() != element->id()) { 0579 continue; 0580 } 0581 if (!t) { 0582 t = e; // tag match 0583 } 0584 if (element->hasClass()) { 0585 if (!e->hasClass()) { 0586 continue; 0587 } 0588 const DOMString &class1 = element->getAttribute(ATTR_CLASS); 0589 const DOMString &class2 = e->getAttribute(ATTR_CLASS); 0590 if (class1 != class2) { 0591 continue; 0592 } 0593 } 0594 if (!c) { 0595 c = e; // class match 0596 } 0597 break; 0598 } while (true); 0599 0600 // if possible return sibling that matches tag and class 0601 if (c && c->renderer() && c->renderer()->style()) { 0602 return c->renderer()->style(); 0603 } 0604 // second best: return sibling that matches tag 0605 if (t && t->renderer() && t->renderer()->style()) { 0606 return t->renderer()->style(); 0607 } 0608 // third best: return sibling element 0609 if (s && s->renderer() && s->renderer()->style()) { 0610 return s->renderer()->style(); 0611 } 0612 // last attempt: return parent element 0613 NodeImpl *p = element->parentNode(); 0614 if (p && p->renderer()) { 0615 return p->renderer()->style(); 0616 } 0617 0618 return nullptr; 0619 } 0620 0621 static inline void bubbleSort(CSSOrderedProperty **b, CSSOrderedProperty **e) 0622 { 0623 while (b < e) { 0624 bool swapped = false; 0625 CSSOrderedProperty **y = e + 1; 0626 CSSOrderedProperty **x = e; 0627 CSSOrderedProperty **swappedPos = nullptr; 0628 do { 0629 if (!((**(--x)) < (**(--y)))) { 0630 swapped = true; 0631 swappedPos = x; 0632 CSSOrderedProperty *tmp = *y; 0633 *y = *x; 0634 *x = tmp; 0635 } 0636 } while (x != b); 0637 if (!swapped) { 0638 break; 0639 } 0640 b = swappedPos + 1; 0641 } 0642 } 0643 0644 RenderStyle *CSSStyleSelector::styleForElement(ElementImpl *e, RenderStyle *fallbackParentStyle) 0645 { 0646 if (!e->document()->haveStylesheetsLoaded() || !e->document()->view()) { 0647 if (!styleNotYetAvailable) { 0648 styleNotYetAvailable = new RenderStyle(); 0649 styleNotYetAvailable->setDisplay(NONE); 0650 styleNotYetAvailable->ref(); 0651 } 0652 return styleNotYetAvailable; 0653 } 0654 0655 // set some variables we will need 0656 pseudoState = PseudoUnknown; 0657 0658 element = e; 0659 parentNode = e->parentNode(); 0660 parentStyle = (parentNode && parentNode->renderer()) ? 0661 parentNode->renderer()->style() : fallbackParentStyle; 0662 view = element->document()->view(); 0663 part = view->part(); 0664 settings = part->settings(); 0665 logicalDpiY = element->document()->logicalDpiY(); 0666 0667 // reset dynamic DOM dependencies 0668 e->document()->dynamicDomRestyler().resetDependencies(e); 0669 0670 style = new RenderStyle(); 0671 if (parentStyle) { 0672 style->inheritFrom(parentStyle); 0673 } else { 0674 parentStyle = style; 0675 } 0676 0677 const RenderObject *docElementRenderer = e->document()->documentElement()->renderer(); 0678 m_rootStyle = docElementRenderer ? docElementRenderer->style() : m_rootDefaultStyle; 0679 0680 // try to sort out most style rules as early as possible. 0681 quint16 cssTagId = localNamePart(element->id()); 0682 int smatch = 0; 0683 int schecked = 0; 0684 0685 // do aggressive selection of selectors to check 0686 // instead of going over whole constructed list, 0687 // skip selectors that won't match for sure (e.g. with different id or class) 0688 QVarLengthArray<int> selectorsForCheck; 0689 // add unknown selectors to always be checked 0690 for (unsigned int i = otherSelector; i < selectors_size; i = nextSimilarSelector[i]) { 0691 selectorsForCheck.append(i); 0692 } 0693 // check if we got class attribute on element: add selectors with it to the list 0694 if (e->hasClass()) { 0695 const ClassNames &classNames = element->classNames(); 0696 for (unsigned int i = 0; i < classNames.size(); ++i) { 0697 WTF::HashMap<quintptr, int>::iterator it = classSelector.find((quintptr)classNames[i].impl()); 0698 if (it != classSelector.end()) 0699 for (unsigned int j = it->second; j < selectors_size; j = nextSimilarSelector[j]) { 0700 selectorsForCheck.append(j); 0701 } 0702 } 0703 } 0704 // check if we got id attribute on element: add selectors with it to the list 0705 DOMStringImpl *idValue = element->getAttributeImplById(ATTR_ID); 0706 if (idValue && idValue->length()) { 0707 bool caseSensitive = (e->document()->htmlMode() == DocumentImpl::XHtml) || strictParsing; 0708 AtomicString elementId = caseSensitive ? idValue : idValue->lower(); 0709 WTF::HashMap<quintptr, int>::iterator it = idSelector.find((quintptr)elementId.impl()); 0710 if (it != idSelector.end()) 0711 for (unsigned int j = it->second; j < selectors_size; j = nextSimilarSelector[j]) { 0712 selectorsForCheck.append(j); 0713 } 0714 } 0715 // add all selectors with given local tag 0716 WTF::HashMap<unsigned, int>::iterator it = tagSelector.find(cssTagId); 0717 if (it != tagSelector.end()) 0718 for (unsigned int j = it->second; j < selectors_size; j = nextSimilarSelector[j]) { 0719 selectorsForCheck.append(j); 0720 } 0721 0722 // build per-element cache summaries. 0723 prepareToMatchElement(element, true); 0724 0725 propsToApply.clear(); 0726 pseudoProps.clear(); 0727 // now go over selectors that we prepared for check 0728 // selectors yet in random order, so we store only matched selector indexes to sort after 0729 unsigned amountOfMatchedSelectors = 0; 0730 for (int k = 0; k < selectorsForCheck.size(); ++k) { 0731 unsigned i = selectorsForCheck[k]; 0732 quint16 tag = selectors[i]->tagLocalName.id(); 0733 if (cssTagId == tag || tag == anyLocalName) { 0734 ++schecked; 0735 checkSelector(i, e); 0736 if (selectorCache[i].state == Applies || selectorCache[i].state == AppliesPseudo) { 0737 selectorsForCheck[amountOfMatchedSelectors++] = i; 0738 } 0739 } else { 0740 selectorCache[i].state = Invalid; 0741 } 0742 } 0743 0744 // sort only matched selectors and then collect properties 0745 std::sort(selectorsForCheck.data(), selectorsForCheck.data() + amountOfMatchedSelectors); 0746 for (unsigned k = 0; k < amountOfMatchedSelectors; ++k) { 0747 unsigned i = selectorsForCheck[k]; 0748 if (selectorCache[i].state == Applies) { 0749 ++smatch; 0750 for (unsigned p = selectorCache[i].firstPropertyIndex; p < properties_size; p = nextPropertyIndexes[p]) { 0751 propsToApply.append(propertiesBuffer + p); 0752 } 0753 } else if (selectorCache[i].state == AppliesPseudo) { 0754 for (unsigned p = selectorCache[i].firstPropertyIndex; p < properties_size; p = nextPropertyIndexes[p]) { 0755 pseudoProps.append(propertiesBuffer + p); 0756 propertiesBuffer[p].pseudoId = (RenderStyle::PseudoId) selectors[i]->pseudoId; 0757 } 0758 } 0759 } 0760 // clear selectorsForCheck, it shouldn't be used after 0761 selectorsForCheck.clear(); 0762 0763 // Inline style declarations, after all others. 0764 // Non-css hints from presentational attributes will also be collected here 0765 // receiving the proper priority so has to cascade from before author rules (cf.CSS 2.1-6.4.4). 0766 addInlineDeclarations(e); 0767 0768 // qDebug( "styleForElement( %s )", e->tagName().string().toLatin1().constData() ); 0769 // qDebug( "%d selectors, %d checked, %d match, %d properties ( of %d )", 0770 // selectors_size, schecked, smatch, numPropsToApply, properties_size ); 0771 0772 if (propsToApply.size()) { 0773 bubbleSort(propsToApply.data(), propsToApply.data() + propsToApply.size() - 1); 0774 } 0775 if (pseudoProps.size()) { 0776 bubbleSort(pseudoProps.data(), pseudoProps.data() + pseudoProps.size() - 1); 0777 } 0778 0779 // we can't apply style rules without a view() and a part. This 0780 // tends to happen on delayed destruction of widget Renderobjects 0781 if (part) { 0782 fontDirty = false; 0783 0784 if (propsToApply.size()) { 0785 for (unsigned int i = 0; i < propsToApply.size(); ++i) { 0786 if (fontDirty && propsToApply[i]->priority >= (1 << 30)) { 0787 // we are past the font properties, time to update to the 0788 // correct font 0789 #ifdef APPLE_CHANGES 0790 checkForGenericFamilyChange(style, parentStyle); 0791 #endif 0792 style->htmlFont().update(logicalDpiY); 0793 fontDirty = false; 0794 } 0795 DOM::CSSProperty *prop = propsToApply[i]->prop; 0796 // if (prop->m_id == CSS_PROP__KONQ_USER_INPUT) qCDebug(KHTML_LOG) << "El: "<<e->nodeName().string() << " user-input: "<<((CSSPrimitiveValueImpl *)prop->value())->getIdent(); 0797 // if (prop->m_id == CSS_PROP_TEXT_TRANSFORM) qCDebug(KHTML_LOG) << "El: "<<e->nodeName().string(); 0798 applyRule(prop->m_id, prop->value()); 0799 } 0800 if (fontDirty) { 0801 #ifdef APPLE_CHANGES 0802 checkForGenericFamilyChange(style, parentStyle); 0803 #endif 0804 style->htmlFont().update(logicalDpiY); 0805 } 0806 } 0807 0808 // Clean up our style object's display and text decorations (among other fixups). 0809 adjustRenderStyle(style, e); 0810 0811 if (pseudoProps.size()) { 0812 fontDirty = false; 0813 //qDebug("%d applying %d pseudo props", e->cssTagId(), pseudoProps->count() ); 0814 for (unsigned int i = 0; i < pseudoProps.size(); ++i) { 0815 if (fontDirty && pseudoProps[i]->priority >= (1 << 30)) { 0816 // we are past the font properties, time to update to the 0817 // correct font 0818 //We have to do this for all pseudo styles 0819 RenderStyle *pseudoStyle = style->pseudoStyle; 0820 while (pseudoStyle) { 0821 pseudoStyle->htmlFont().update(logicalDpiY); 0822 pseudoStyle = pseudoStyle->pseudoStyle; 0823 } 0824 fontDirty = false; 0825 } 0826 0827 RenderStyle *pseudoStyle; 0828 pseudoStyle = style->getPseudoStyle(pseudoProps[i]->pseudoId); 0829 if (!pseudoStyle) { 0830 pseudoStyle = style->addPseudoStyle(pseudoProps[i]->pseudoId); 0831 if (pseudoStyle) { 0832 pseudoStyle->inheritFrom(style); 0833 } 0834 } 0835 0836 RenderStyle *oldStyle = style; 0837 RenderStyle *oldParentStyle = parentStyle; 0838 parentStyle = style; 0839 style = pseudoStyle; 0840 if (pseudoStyle) { 0841 DOM::CSSProperty *prop = pseudoProps[i]->prop; 0842 applyRule(prop->m_id, prop->value()); 0843 } 0844 style = oldStyle; 0845 parentStyle = oldParentStyle; 0846 } 0847 0848 if (fontDirty) { 0849 RenderStyle *pseudoStyle = style->pseudoStyle; 0850 while (pseudoStyle) { 0851 pseudoStyle->htmlFont().update(logicalDpiY); 0852 pseudoStyle = pseudoStyle->pseudoStyle; 0853 } 0854 } 0855 } 0856 } 0857 0858 // Now adjust all our pseudo-styles. 0859 RenderStyle *pseudoStyle = style->pseudoStyle; 0860 while (pseudoStyle) { 0861 adjustRenderStyle(pseudoStyle, nullptr); 0862 pseudoStyle = pseudoStyle->pseudoStyle; 0863 } 0864 0865 // Try and share or partially share the style with our siblings 0866 RenderStyle *commonStyle = locateSimilarStyle(); 0867 if (commonStyle) { 0868 style->compactWith(commonStyle); 0869 } 0870 0871 // Now return the style. 0872 return style; 0873 } 0874 0875 void CSSStyleSelector::prepareToMatchElement(DOM::ElementImpl *e, bool withDeps) 0876 { 0877 rememberDependencies = withDeps; 0878 element = e; 0879 0880 // build caches for element so it could be used in heuristic for descendant selectors 0881 // go up the tree and cache possible tags, classes and ids 0882 tagCache.clear(); 0883 idCache.clear(); 0884 classCache.clear(); 0885 ElementImpl *current = element; 0886 while (true) { 0887 NodeImpl *parent = current->parentNode(); 0888 if (!parent || !parent->isElementNode()) { 0889 break; 0890 } 0891 current = static_cast<ElementImpl *>(parent); 0892 0893 if (current->hasClass()) { 0894 const ClassNames &classNames = current->classNames(); 0895 for (unsigned i = 0; i < classNames.size(); ++i) { 0896 classCache.add((quintptr)classNames[i].impl()); 0897 } 0898 } 0899 0900 DOMStringImpl *idValue = current->getAttributeImplById(ATTR_ID); 0901 if (idValue && idValue->length()) { 0902 bool caseSensitive = (current->document()->htmlMode() == DocumentImpl::XHtml) || strictParsing; 0903 AtomicString currentId = caseSensitive ? idValue : idValue->lower(); 0904 // though currentId is local and could be deleted from AtomicStringImpl cache right away 0905 // don't care about that, cause selector values are stable and only they will be checked later 0906 idCache.add((quintptr)currentId.impl()); 0907 } 0908 0909 tagCache.add(localNamePart(current->id())); 0910 } 0911 } 0912 0913 void CSSStyleSelector::adjustRenderStyle(RenderStyle *style, DOM::ElementImpl *e) 0914 { 0915 // Cache our original display. 0916 style->setOriginalDisplay(style->display()); 0917 0918 if (style->display() != NONE) { 0919 // If we have a <td> that specifies a float property, in quirks mode we just drop the float 0920 // property. 0921 // Sites also commonly use display:inline/block on <td>s and <table>s. In quirks mode we force 0922 // these tags to retain their display types. 0923 if (!strictParsing && e) { 0924 if (e->id() == ID_TD) { 0925 style->setDisplay(TABLE_CELL); 0926 style->setFloating(FNONE); 0927 } else if (e->id() == ID_TABLE) { 0928 style->setDisplay(style->isDisplayInlineType() ? INLINE_TABLE : TABLE); 0929 } 0930 } 0931 0932 // Table headers with a text-align of auto will change the text-align to center. 0933 if (e && e->id() == ID_TH && style->textAlign() == TAAUTO) { 0934 style->setTextAlign(CENTER); 0935 } 0936 0937 // Mutate the display to BLOCK or TABLE for certain cases, e.g., if someone attempts to 0938 // position or float an inline, compact, or run-in. Cache the original display, since it 0939 // may be needed for positioned elements that have to compute their static normal flow 0940 // positions. We also force inline-level roots to be block-level. 0941 if (style->display() != BLOCK && style->display() != TABLE /*&& style->display() != BOX*/ && 0942 (style->position() == PABSOLUTE || style->position() == PFIXED || style->floating() != FNONE || 0943 (e && e->document()->documentElement() == e))) { 0944 if (style->display() == INLINE_TABLE) { 0945 style->setDisplay(TABLE); 0946 } 0947 // else if (style->display() == INLINE_BOX) 0948 // style->setDisplay(BOX); 0949 else if (style->display() == LIST_ITEM) { 0950 // It is a WinIE bug that floated list items lose their bullets, so we'll emulate the quirk, 0951 // but only in quirks mode. 0952 if (!strictParsing && style->floating() != FNONE) { 0953 style->setDisplay(BLOCK); 0954 } 0955 } else { 0956 style->setDisplay(BLOCK); 0957 } 0958 } else if (e && e->id() == ID_BUTTON && style->isOriginalDisplayInlineType()) { 0959 // <button>s are supposed to be replaced elements; but we don't handle 0960 // them as such (as they are rendered as CSS contexts, not natives 0961 // with intrinsic sizes), so we must be careful not to make them fully 0962 // inline, as that will display stuff like width:; so mutate inline-like 0963 // display types into inline-block 0964 style->setDisplay(INLINE_BLOCK); 0965 } 0966 0967 // After performing the display mutation, check our position. We do not honor position:relative on 0968 // table rows and some other table displays. This is undefined behaviour in CSS2.1 (cf. 9.3.1) 0969 if (style->position() == PRELATIVE) { 0970 switch (style->display()) { 0971 case TABLE_ROW_GROUP: 0972 case TABLE_HEADER_GROUP: 0973 case TABLE_FOOTER_GROUP: 0974 case TABLE_ROW: 0975 style->setPosition(PSTATIC); 0976 default: 0977 break; 0978 } 0979 } 0980 } 0981 0982 // Frames and framesets never honor position:relative or position:absolute. This is necessary to 0983 // fix a crash where a site tries to position these objects. 0984 if (e) { 0985 // ignore display: none for <frame> 0986 if (e->id() == ID_FRAME) { 0987 style->setPosition(PSTATIC); 0988 style->setDisplay(BLOCK); 0989 } else if (e->id() == ID_FRAMESET) { 0990 style->setPosition(PSTATIC); 0991 } 0992 } 0993 0994 // Finally update our text decorations in effect, but don't allow text-decoration to percolate through 0995 // tables, inline blocks, inline tables, or run-ins. 0996 if (style->display() == TABLE || style->display() == INLINE_TABLE || style->display() == RUN_IN 0997 || style->display() == INLINE_BLOCK /*|| style->display() == INLINE_BOX*/) { 0998 style->setTextDecorationsInEffect(style->textDecoration()); 0999 } 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() 2295 : QList<CSSOrderedRule *>() 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()); 2325 QList<CSSOrderedRule *>::append(rule); 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; 2389 QListIterator<CSSOrderedRule *> tIt(*this); 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: 4339 f = QFontDatabase::systemFont(QFontDatabase::GeneralFont); 4340 break; 4341 4342 case CSS_VAL_MENU: 4343 f = QFontDatabase::systemFont(QFontDatabase::GeneralFont); 4344 break; 4345 4346 case CSS_VAL_SMALL_CAPTION: 4347 f = QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont); 4348 break; 4349 4350 case CSS_VAL_CAPTION: 4351 case CSS_VAL_MESSAGE_BOX: 4352 case CSS_VAL_STATUS_BAR: 4353 f = QFontDatabase::systemFont(QFontDatabase::GeneralFont); 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