2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4 * (C) 2006 Nicholas Shanks (webkit@nickshanks.com)
5 * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
25 #include "CSSStyleSelector.h"
27 #include "CSSBorderImageValue.h"
28 #include "CSSCursorImageValue.h"
29 #include "CSSFontFace.h"
30 #include "CSSFontFaceSource.h"
31 #include "CSSFontFaceRule.h"
32 #include "CSSImageValue.h"
33 #include "CSSImportRule.h"
34 #include "CSSMediaRule.h"
35 #include "CSSPrimitiveValueMappings.h"
36 #include "CSSProperty.h"
37 #include "CSSPropertyNames.h"
38 #include "CSSRuleList.h"
39 #include "CSSSelector.h"
40 #include "CSSStyleRule.h"
41 #include "CSSStyleSheet.h"
42 #include "CSSTimingFunctionValue.h"
43 #include "CSSValueList.h"
44 #include "CachedImage.h"
46 #include "DashboardRegion.h"
47 #include "FontFamilyValue.h"
48 #include "FontValue.h"
50 #include "FrameView.h"
51 #include "GlobalHistory.h"
52 #include "HTMLDocument.h"
53 #include "HTMLElement.h"
54 #include "HTMLInputElement.h"
55 #include "HTMLNames.h"
56 #include "MediaList.h"
57 #include "MediaQueryEvaluator.h"
60 #include "RenderTheme.h"
62 #include "ShadowValue.h"
63 #include "StyleSheetList.h"
64 #include "UserAgentStyleSheets.h"
68 #include "XLinkNames.h"
76 using namespace HTMLNames;
78 // #define STYLE_SHARING_STATS 1
80 #define HANDLE_INHERIT(prop, Prop) \
82 style->set##Prop(parentStyle->prop()); \
86 #define HANDLE_INHERIT_AND_INITIAL(prop, Prop) \
87 HANDLE_INHERIT(prop, Prop) \
89 style->set##Prop(RenderStyle::initial##Prop()); \
93 #define HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(prop, Prop, Value) \
94 HANDLE_INHERIT(prop, Prop) \
96 style->set##Prop(RenderStyle::initial##Value());\
100 #define HANDLE_MULTILAYER_INHERIT_AND_INITIAL(layerType, LayerType, prop, Prop) \
102 LayerType* currChild = style->access##LayerType##s(); \
103 LayerType* prevChild = 0; \
104 const LayerType* currParent = parentStyle->layerType##s(); \
105 while (currParent && currParent->is##Prop##Set()) { \
107 /* Need to make a new layer.*/ \
108 currChild = new LayerType(); \
109 prevChild->setNext(currChild); \
111 currChild->set##Prop(currParent->prop()); \
112 prevChild = currChild; \
113 currChild = prevChild->next(); \
114 currParent = currParent->next(); \
117 while (currChild) { \
118 /* Reset any remaining layers to not have the property set. */ \
119 currChild->clear##Prop(); \
120 currChild = currChild->next(); \
125 LayerType* currChild = style->access##LayerType##s(); \
126 currChild->set##Prop(RenderStyle::initial##Prop()); \
127 for (currChild = currChild->next(); currChild; currChild = currChild->next()) \
128 currChild->clear##Prop(); \
132 #define HANDLE_MULTILAYER_VALUE(layerType, LayerType, prop, Prop, value) { \
133 HANDLE_MULTILAYER_INHERIT_AND_INITIAL(layerType, LayerType, prop, Prop) \
134 LayerType* currChild = style->access##LayerType##s(); \
135 LayerType* prevChild = 0; \
136 if (value->isValueList()) { \
137 /* Walk each value and put it into a layer, creating new layers as needed. */ \
138 CSSValueList* valueList = static_cast<CSSValueList*>(value); \
139 for (unsigned int i = 0; i < valueList->length(); i++) { \
141 /* Need to make a new layer to hold this value */ \
142 currChild = new LayerType(); \
143 prevChild->setNext(currChild); \
145 map##Prop(currChild, valueList->item(i)); \
146 prevChild = currChild; \
147 currChild = currChild->next(); \
150 map##Prop(currChild, value); \
151 currChild = currChild->next(); \
153 while (currChild) { \
154 /* Reset all remaining layers to not have the property set. */ \
155 currChild->clear##Prop(); \
156 currChild = currChild->next(); \
159 #define HANDLE_BACKGROUND_INHERIT_AND_INITIAL(prop, Prop) \
160 HANDLE_MULTILAYER_INHERIT_AND_INITIAL(backgroundLayer, BackgroundLayer, prop, Prop)
162 #define HANDLE_BACKGROUND_VALUE(prop, Prop, value) \
163 HANDLE_MULTILAYER_VALUE(backgroundLayer, BackgroundLayer, prop, Prop, value)
165 #define HANDLE_TRANSITION_INHERIT_AND_INITIAL(prop, Prop) \
166 HANDLE_MULTILAYER_INHERIT_AND_INITIAL(transition, Transition, prop, Prop)
168 #define HANDLE_TRANSITION_VALUE(prop, Prop, value) \
169 HANDLE_MULTILAYER_VALUE(transition, Transition, prop, Prop, value)
171 #define HANDLE_INHERIT_COND(propID, prop, Prop) \
172 if (id == propID) { \
173 style->set##Prop(parentStyle->prop()); \
177 #define HANDLE_INITIAL_COND(propID, Prop) \
178 if (id == propID) { \
179 style->set##Prop(RenderStyle::initial##Prop()); \
183 #define HANDLE_INITIAL_COND_WITH_VALUE(propID, Prop, Value) \
184 if (id == propID) { \
185 style->set##Prop(RenderStyle::initial##Value()); \
195 typedef HashMap<AtomicStringImpl*, CSSRuleDataList*> AtomRuleMap;
197 void addRulesFromSheet(CSSStyleSheet*, const MediaQueryEvaluator&, CSSStyleSelector* = 0);
199 void addRule(CSSStyleRule* rule, CSSSelector* sel);
200 void addToRuleSet(AtomicStringImpl* key, AtomRuleMap& map,
201 CSSStyleRule* rule, CSSSelector* sel);
203 CSSRuleDataList* getIDRules(AtomicStringImpl* key) { return m_idRules.get(key); }
204 CSSRuleDataList* getClassRules(AtomicStringImpl* key) { return m_classRules.get(key); }
205 CSSRuleDataList* getTagRules(AtomicStringImpl* key) { return m_tagRules.get(key); }
206 CSSRuleDataList* getUniversalRules() { return m_universalRules; }
209 AtomRuleMap m_idRules;
210 AtomRuleMap m_classRules;
211 AtomRuleMap m_tagRules;
212 CSSRuleDataList* m_universalRules;
213 unsigned m_ruleCount;
216 CSSRuleSet* CSSStyleSelector::defaultStyle = 0;
217 CSSRuleSet* CSSStyleSelector::defaultQuirksStyle = 0;
218 CSSRuleSet* CSSStyleSelector::defaultPrintStyle = 0;
219 CSSRuleSet* CSSStyleSelector::defaultViewSourceStyle = 0;
221 CSSStyleSheet* CSSStyleSelector::defaultSheet = 0;
222 RenderStyle* CSSStyleSelector::styleNotYetAvailable = 0;
223 CSSStyleSheet* CSSStyleSelector::quirksSheet = 0;
224 CSSStyleSheet* CSSStyleSelector::viewSourceSheet = 0;
227 CSSStyleSheet *CSSStyleSelector::svgSheet = 0;
230 static CSSStyleSelector::Encodedurl *currentEncodedURL = 0;
231 static PseudoState pseudoState;
233 static const MediaQueryEvaluator& screenEval()
235 static const MediaQueryEvaluator staticScreenEval("screen");
236 return staticScreenEval;
239 static const MediaQueryEvaluator& printEval()
241 static const MediaQueryEvaluator staticPrintEval("print");
242 return staticPrintEval;
245 CSSStyleSelector::CSSStyleSelector(Document* doc, const String& userStyleSheet, StyleSheetList *styleSheets, CSSStyleSheet* mappedElementSheet, bool _strictParsing, bool matchAuthorAndUserStyles)
251 m_matchAuthorAndUserStyles = matchAuthorAndUserStyles;
253 strictParsing = _strictParsing;
259 // construct document root element default style. this is needed
260 // to evaluate media queries that contain relative constraints, like "screen and (max-width: 10em)"
261 // This is here instead of constructor, because when constructor is run,
262 // document doesn't have documentElement
263 // NOTE: this assumes that element that gets passed to styleForElement -call
264 // is always from the document that owns the style selector
265 FrameView* view = m_document->view();
267 m_medium = new MediaQueryEvaluator(view->mediaType());
269 m_medium = new MediaQueryEvaluator("all");
271 Element* root = doc->documentElement();
274 m_rootDefaultStyle = styleForElement(root, 0, false, true); // dont ref, because the RenderStyle is allocated from global heap
276 if (m_rootDefaultStyle && view) {
278 m_medium = new MediaQueryEvaluator(view->mediaType(), view->frame()->page(), m_rootDefaultStyle);
281 // FIXME: This sucks! The user sheet is reparsed every time!
282 if (!userStyleSheet.isEmpty()) {
283 m_userSheet = new CSSStyleSheet(doc);
284 m_userSheet->parseString(userStyleSheet, strictParsing);
286 m_userStyle = new CSSRuleSet();
287 m_userStyle->addRulesFromSheet(m_userSheet.get(), *m_medium, this);
290 // add stylesheets from document
291 m_authorStyle = new CSSRuleSet();
293 // Add rules from elments like SVG's <font-face>
294 if (mappedElementSheet)
295 m_authorStyle->addRulesFromSheet(mappedElementSheet, *m_medium, this);
297 DeprecatedPtrListIterator<StyleSheet> it(styleSheets->styleSheets);
298 for (; it.current(); ++it)
299 if (it.current()->isCSSStyleSheet() && !it.current()->disabled())
300 m_authorStyle->addRulesFromSheet(static_cast<CSSStyleSheet*>(it.current()), *m_medium, this);
302 // Just delete our font selector if we end up with nothing but invalid @font-face rules.
303 if (m_fontSelector && m_fontSelector->isEmpty())
307 void CSSStyleSelector::init()
310 m_matchedDecls.clear();
312 m_collectRulesOnly = false;
313 m_rootDefaultStyle = 0;
317 void CSSStyleSelector::setEncodedURL(const KURL& url)
321 u.setQuery(DeprecatedString::null);
322 u.setRef(DeprecatedString::null);
323 encodedurl.file = u.deprecatedString();
324 int pos = encodedurl.file.findRev('/');
325 encodedurl.path = encodedurl.file;
327 encodedurl.path.truncate(pos);
328 encodedurl.path += '/';
330 u.setPath(DeprecatedString::null);
331 encodedurl.host = u.deprecatedString();
334 CSSStyleSelector::~CSSStyleSelector()
337 ::delete m_rootDefaultStyle;
339 delete m_authorStyle;
343 static CSSStyleSheet* parseUASheet(const char* characters, unsigned size)
345 CSSStyleSheet* const parent = 0;
346 CSSStyleSheet* sheet = new CSSStyleSheet(parent);
347 sheet->ref(); // leak the sheet on purpose since it will be stored in a global variable
348 sheet->parseString(String(characters, size));
352 template<typename T> CSSStyleSheet* parseUASheet(const T& array)
354 return parseUASheet(array, sizeof(array));
357 void CSSStyleSelector::loadDefaultStyle()
362 defaultStyle = new CSSRuleSet;
363 defaultPrintStyle = new CSSRuleSet;
364 defaultQuirksStyle = new CSSRuleSet;
365 defaultViewSourceStyle = new CSSRuleSet;
367 // Strict-mode rules.
368 defaultSheet = parseUASheet(html4UserAgentStyleSheet);
369 defaultStyle->addRulesFromSheet(defaultSheet, screenEval());
370 defaultPrintStyle->addRulesFromSheet(defaultSheet, printEval());
372 // Quirks-mode rules.
373 quirksSheet = parseUASheet(quirksUserAgentStyleSheet);
374 defaultQuirksStyle->addRulesFromSheet(quirksSheet, screenEval());
376 // View source rules.
377 viewSourceSheet = parseUASheet(sourceUserAgentStyleSheet);
378 defaultViewSourceStyle->addRulesFromSheet(viewSourceSheet, screenEval());
381 void CSSStyleSelector::matchRules(CSSRuleSet* rules, int& firstRuleIndex, int& lastRuleIndex)
383 m_matchedRules.clear();
385 if (!rules || !element)
388 // We need to collect the rules for id, class, tag, and everything else into a buffer and
389 // then sort the buffer.
390 if (element->hasID())
391 matchRulesForList(rules->getIDRules(element->getIDAttribute().impl()), firstRuleIndex, lastRuleIndex);
392 if (element->hasClass()) {
393 const ClassNames& classNames = *element->getClassNames();
394 for (size_t i = 0; i < classNames.size(); ++i)
395 matchRulesForList(rules->getClassRules(classNames[i].impl()), firstRuleIndex, lastRuleIndex);
397 matchRulesForList(rules->getTagRules(element->localName().impl()), firstRuleIndex, lastRuleIndex);
398 matchRulesForList(rules->getUniversalRules(), firstRuleIndex, lastRuleIndex);
400 // If we didn't match any rules, we're done.
401 if (m_matchedRules.isEmpty())
404 // Sort the set of matched rules.
405 sortMatchedRules(0, m_matchedRules.size());
407 // Now transfer the set of matched rules over to our list of decls.
408 if (!m_collectRulesOnly) {
409 for (unsigned i = 0; i < m_matchedRules.size(); i++)
410 addMatchedDeclaration(m_matchedRules[i]->rule()->declaration());
412 for (unsigned i = 0; i < m_matchedRules.size(); i++) {
414 m_ruleList = new CSSRuleList();
415 m_ruleList->append(m_matchedRules[i]->rule());
420 void CSSStyleSelector::matchRulesForList(CSSRuleDataList* rules, int& firstRuleIndex, int& lastRuleIndex)
425 for (CSSRuleData* d = rules->first(); d; d = d->next()) {
426 CSSStyleRule* rule = d->rule();
427 const AtomicString& localName = element->localName();
428 const AtomicString& selectorLocalName = d->selector()->m_tag.localName();
429 if ((localName == selectorLocalName || selectorLocalName == starAtom) && checkSelector(d->selector())) {
430 // If the rule has no properties to apply, then ignore it.
431 CSSMutableStyleDeclaration* decl = rule->declaration();
432 if (!decl || !decl->length())
435 // If we're matching normal rules, set a pseudo bit if
436 // we really just matched a pseudo-element.
437 if (dynamicPseudo != RenderStyle::NOPSEUDO && pseudoStyle == RenderStyle::NOPSEUDO) {
438 if (m_collectRulesOnly)
440 if (dynamicPseudo < RenderStyle::FIRST_INTERNAL_PSEUDOID)
441 style->setHasPseudoStyle(dynamicPseudo);
443 // Update our first/last rule indices in the matched rules array.
444 lastRuleIndex = m_matchedDecls.size() + m_matchedRules.size();
445 if (firstRuleIndex == -1)
446 firstRuleIndex = lastRuleIndex;
448 // Add this rule to our list of matched rules.
455 bool operator >(CSSRuleData& r1, CSSRuleData& r2)
457 int spec1 = r1.selector()->specificity();
458 int spec2 = r2.selector()->specificity();
459 return (spec1 == spec2) ? r1.position() > r2.position() : spec1 > spec2;
461 bool operator <=(CSSRuleData& r1, CSSRuleData& r2)
466 void CSSStyleSelector::sortMatchedRules(unsigned start, unsigned end)
468 if (start >= end || (end - start == 1))
469 return; // Sanity check.
471 if (end - start <= 6) {
472 // Apply a bubble sort for smaller lists.
473 for (unsigned i = end - 1; i > start; i--) {
475 for (unsigned j = start; j < i; j++) {
476 CSSRuleData* elt = m_matchedRules[j];
477 CSSRuleData* elt2 = m_matchedRules[j + 1];
480 m_matchedRules[j] = elt2;
481 m_matchedRules[j + 1] = elt;
490 // Peform a merge sort for larger lists.
491 unsigned mid = (start + end) / 2;
492 sortMatchedRules(start, mid);
493 sortMatchedRules(mid, end);
495 CSSRuleData* elt = m_matchedRules[mid - 1];
496 CSSRuleData* elt2 = m_matchedRules[mid];
498 // Handle the fast common case (of equal specificity). The list may already
499 // be completely sorted.
503 // We have to merge sort. Ensure our merge buffer is big enough to hold
505 Vector<CSSRuleData*> rulesMergeBuffer;
506 rulesMergeBuffer.reserveCapacity(end - start);
511 elt = m_matchedRules[i1];
512 elt2 = m_matchedRules[i2];
514 while (i1 < mid || i2 < end) {
515 if (i1 < mid && (i2 == end || *elt <= *elt2)) {
516 rulesMergeBuffer.append(elt);
518 elt = m_matchedRules[i1];
520 rulesMergeBuffer.append(elt2);
522 elt2 = m_matchedRules[i2];
526 for (unsigned i = start; i < end; i++)
527 m_matchedRules[i] = rulesMergeBuffer[i - start];
530 void CSSStyleSelector::initElementAndPseudoState(Element* e)
533 if (element && element->isStyledElement())
534 styledElement = static_cast<StyledElement*>(element);
537 currentEncodedURL = &encodedurl;
538 pseudoState = PseudoUnknown;
541 void CSSStyleSelector::initForStyleResolve(Element* e, RenderStyle* defaultParent)
543 // set some variables we will need
544 pseudoStyle = RenderStyle::NOPSEUDO;
546 parentNode = e->parentNode();
549 if (!parentNode && e->isSVGElement() && e->isShadowNode())
550 parentNode = e->shadowParentNode();
554 parentStyle = defaultParent;
556 parentStyle = parentNode ? parentNode->renderStyle() : 0;
557 isXMLDoc = !element->document()->isHTMLDocument();
561 m_matchedDecls.clear();
568 static int findHash(const DeprecatedString& string)
570 const ::UChar* ptr = reinterpret_cast<const ::UChar*>(string.unicode());
571 unsigned length = string.length();
572 for (unsigned i = 0; i < length; ++i) {
579 static inline int findSlashDotDotSlash(const DeprecatedString& string)
581 const ::UChar* ptr = reinterpret_cast<const ::UChar*>(string.unicode());
582 unsigned length = string.length();
583 unsigned loopLimit = length < 4 ? 0 : length - 3;
584 for (unsigned i = 0; i < loopLimit; ++i) {
585 if (ptr[i] == '/' && ptr[i + 1] == '.' && ptr[i + 2] == '.' && ptr[i + 3] == '/')
591 static inline int findSlashSlash(const DeprecatedString& string, int position)
593 const ::UChar* ptr = reinterpret_cast<const ::UChar*>(string.unicode());
594 unsigned length = string.length();
595 unsigned loopLimit = length < 2 ? 0 : length - 1;
596 for (unsigned i = position; i < loopLimit; ++i) {
597 if (ptr[i] == '/' && ptr[i + 1] == '/')
603 static inline int findSlashDotSlash(const DeprecatedString& string)
605 const ::UChar* ptr = reinterpret_cast<const ::UChar*>(string.unicode());
606 unsigned length = string.length();
607 unsigned loopLimit = length < 3 ? 0 : length - 2;
608 for (unsigned i = 0; i < loopLimit; ++i) {
609 if (ptr[i] == '/' && ptr[i + 1] == '.' && ptr[i + 2] == '/')
615 static void cleanpath(DeprecatedString& path)
619 while ((pos = findSlashDotDotSlash(path)) != -1) {
622 prev = path.findRev("/", pos - 1);
623 // don't remove the host, i.e. http://foo.org/../foo.html
624 if (prev < 0 || (prev > 3 && path.findRev("://", prev - 1) == prev - 2))
627 // matching directory found ?
628 path.remove(prev, pos - prev + 3);
631 // Don't remove "//" from an anchor identifier. -rjw
632 // Set refPos to -2 to mean "I haven't looked for the anchor yet".
633 // We don't want to waste a function call on the search for the the anchor
634 // in the vast majority of cases where there is no "//" in the path.
637 while ((pos = findSlashSlash(path, pos)) != -1) {
639 refPos = findHash(path);
640 if (refPos > 0 && pos >= refPos)
643 if (pos == 0 || path[pos - 1] != ':')
649 // FIXME: We don't want to remove "/./" from an anchor identifier either.
650 while ((pos = findSlashDotSlash(path)) != -1)
654 static inline bool containsColonSlashSlash(const UChar* characters, unsigned length)
656 unsigned loopLimit = length < 3 ? 0 : length - 2;
657 for (unsigned i = 0; i < loopLimit; ++i)
658 if (characters[i] == ':' && characters[i + 1] == '/' && characters[i + 2] == '/')
663 static void checkPseudoState(Element *e, bool checkVisited = true)
666 pseudoState = PseudoNone;
670 const AtomicString* attr;
671 if (e->isHTMLElement())
672 attr = &e->getAttribute(hrefAttr);
674 else if (e->isSVGElement())
675 attr = &e->getAttribute(XLinkNames::hrefAttr);
678 pseudoState = PseudoNone;
682 if (attr->isNull()) {
683 pseudoState = PseudoNone;
688 pseudoState = PseudoAnyLink;
692 const UChar* characters = attr->characters();
693 unsigned length = attr->length();
695 if (containsColonSlashSlash(characters, length)) {
696 // FIXME: Strange to not clean the path just beacause it has "://" in it.
697 pseudoState = historyContains(characters, length) ? PseudoVisited : PseudoLink;
701 DeprecatedConstString cu(reinterpret_cast<const DeprecatedChar*>(characters), length);
702 DeprecatedString u = cu.string();
703 if (length && characters[0] == '/')
704 u.prepend(currentEncodedURL->host);
705 else if (length && characters[0] == '#')
706 u.prepend(currentEncodedURL->file);
708 u.prepend(currentEncodedURL->path);
710 pseudoState = historyContains(reinterpret_cast<const UChar*>(u.unicode()), u.length())
711 ? PseudoVisited : PseudoLink;
714 #ifdef STYLE_SHARING_STATS
715 static int fraction = 0;
716 static int total = 0;
719 static const unsigned cStyleSearchThreshold = 10;
721 Node* CSSStyleSelector::locateCousinList(Element* parent, unsigned depth)
723 if (parent && parent->isStyledElement()) {
724 StyledElement* p = static_cast<StyledElement*>(parent);
725 if (!p->inlineStyleDecl() && !p->hasID()) {
726 Node* r = p->previousSibling();
727 unsigned subcount = 0;
728 RenderStyle* st = p->renderStyle();
730 if (r->renderStyle() == st)
731 return r->lastChild();
732 if (subcount++ == cStyleSearchThreshold)
734 r = r->previousSibling();
736 if (!r && depth < cStyleSearchThreshold)
737 r = locateCousinList(static_cast<Element*>(parent->parentNode()), depth + 1);
739 if (r->renderStyle() == st)
740 return r->lastChild();
741 if (subcount++ == cStyleSearchThreshold)
743 r = r->previousSibling();
750 bool CSSStyleSelector::canShareStyleWithElement(Node* n)
752 if (n->isStyledElement()) {
753 StyledElement* s = static_cast<StyledElement*>(n);
754 RenderStyle* style = s->renderStyle();
755 if (style && !style->unique() &&
756 (s->tagQName() == element->tagQName()) && !s->hasID() &&
757 (s->hasClass() == element->hasClass()) && !s->inlineStyleDecl() &&
758 (s->hasMappedAttributes() == styledElement->hasMappedAttributes()) &&
759 (s->isLink() == element->isLink()) &&
760 !style->affectedByAttributeSelectors() &&
761 (s->hovered() == element->hovered()) &&
762 (s->active() == element->active()) &&
763 (s->focused() == element->focused()) &&
764 (s != s->document()->getCSSTarget() && element != element->document()->getCSSTarget()) &&
765 (s->getAttribute(typeAttr) == element->getAttribute(typeAttr)) &&
766 (s->getAttribute(readonlyAttr) == element->getAttribute(readonlyAttr))) {
767 bool isControl = s->isControl();
768 if (isControl != element->isControl())
770 if (isControl && (s->isEnabled() != element->isEnabled()) ||
771 (s->isIndeterminate() != element->isIndeterminate()) ||
772 (s->isChecked() != element->isChecked()))
775 if (style->transitions())
778 bool classesMatch = true;
780 const AtomicString& class1 = element->getAttribute(classAttr);
781 const AtomicString& class2 = s->getAttribute(classAttr);
782 classesMatch = (class1 == class2);
786 bool mappedAttrsMatch = true;
787 if (s->hasMappedAttributes())
788 mappedAttrsMatch = s->mappedAttributes()->mapsEquivalent(styledElement->mappedAttributes());
789 if (mappedAttrsMatch) {
790 bool linksMatch = true;
792 // We need to check to see if the visited state matches.
793 Color linkColor = element->document()->linkColor();
794 Color visitedColor = element->document()->visitedLinkColor();
795 if (pseudoState == PseudoUnknown)
796 checkPseudoState(element, style->pseudoState() != PseudoAnyLink || linkColor != visitedColor);
797 linksMatch = (pseudoState == style->pseudoState());
809 RenderStyle* CSSStyleSelector::locateSharedStyle()
811 if (styledElement && !styledElement->inlineStyleDecl() && !styledElement->hasID() &&
812 !styledElement->document()->usesSiblingRules()) {
813 // Check previous siblings.
816 for (n = element->previousSibling(); n && !n->isElementNode(); n = n->previousSibling()) { }
818 if (canShareStyleWithElement(n))
819 return n->renderStyle();
820 if (count++ == cStyleSearchThreshold)
822 for (n = n->previousSibling(); n && !n->isElementNode(); n = n->previousSibling()) { }
825 n = locateCousinList(static_cast<Element*>(element->parentNode()));
827 if (canShareStyleWithElement(n))
828 return n->renderStyle();
829 if (count++ == cStyleSearchThreshold)
831 for (n = n->previousSibling(); n && !n->isElementNode(); n = n->previousSibling()) { }
837 void CSSStyleSelector::matchUARules(int& firstUARule, int& lastUARule)
839 // First we match rules from the user agent sheet.
840 CSSRuleSet* userAgentStyleSheet = m_medium->mediaTypeMatchSpecific("print")
841 ? defaultPrintStyle : defaultStyle;
842 matchRules(userAgentStyleSheet, firstUARule, lastUARule);
844 // In quirks mode, we match rules from the quirks user agent sheet.
846 matchRules(defaultQuirksStyle, firstUARule, lastUARule);
848 // If we're in view source mode, then we match rules from the view source style sheet.
849 if (m_document->frame() && m_document->frame()->inViewSourceMode())
850 matchRules(defaultViewSourceStyle, firstUARule, lastUARule);
853 // If resolveForRootDefault is true, style based on user agent style sheet only. This is used in media queries, where
854 // relative units are interpreted according to document root element style, styled only with UA stylesheet
856 RenderStyle* CSSStyleSelector::styleForElement(Element* e, RenderStyle* defaultParent, bool allowSharing, bool resolveForRootDefault)
858 // Once an element has a renderer, we don't try to destroy it, since otherwise the renderer
859 // will vanish if a style recalc happens during loading.
860 if (allowSharing && !e->document()->haveStylesheetsLoaded() && !e->renderer()) {
861 if (!styleNotYetAvailable) {
862 styleNotYetAvailable = ::new RenderStyle;
863 styleNotYetAvailable->ref();
864 styleNotYetAvailable->setDisplay(NONE);
865 styleNotYetAvailable->font().update(m_fontSelector);
867 styleNotYetAvailable->ref();
868 e->document()->setHasNodesWithPlaceholderStyle();
869 return styleNotYetAvailable;
872 initElementAndPseudoState(e);
874 style = locateSharedStyle();
875 #ifdef STYLE_SHARING_STATS
876 fraction += style != 0;
878 printf("Sharing %d out of %d\n", fraction, total);
885 initForStyleResolve(e, defaultParent);
887 if (resolveForRootDefault) {
888 style = ::new RenderStyle();
889 // don't ref, because we want to delete this, but we cannot unref it
891 style = new (e->document()->renderArena()) RenderStyle();
895 style->inheritFrom(parentStyle);
900 if (e->isSVGElement() && !svgSheet) {
902 svgSheet = parseUASheet(svgUserAgentStyleSheet);
903 defaultStyle->addRulesFromSheet(svgSheet, screenEval());
904 defaultPrintStyle->addRulesFromSheet(svgSheet, printEval());
908 int firstUARule = -1, lastUARule = -1;
909 int firstUserRule = -1, lastUserRule = -1;
910 int firstAuthorRule = -1, lastAuthorRule = -1;
911 matchUARules(firstUARule, lastUARule);
913 if (!resolveForRootDefault) {
914 // 4. Now we check user sheet rules.
915 if (m_matchAuthorAndUserStyles)
916 matchRules(m_userStyle, firstUserRule, lastUserRule);
918 // 5. Now check author rules, beginning first with presentational attributes
921 // Ask if the HTML element has mapped attributes.
922 if (styledElement->hasMappedAttributes()) {
923 // Walk our attribute list and add in each decl.
924 const NamedMappedAttrMap* map = styledElement->mappedAttributes();
925 for (unsigned i = 0; i < map->length(); i++) {
926 MappedAttribute* attr = map->attributeItem(i);
928 lastAuthorRule = m_matchedDecls.size();
929 if (firstAuthorRule == -1)
930 firstAuthorRule = lastAuthorRule;
931 addMatchedDeclaration(attr->decl());
936 // Now we check additional mapped declarations.
937 // Tables and table cells share an additional mapped rule that must be applied
938 // after all attributes, since their mapped style depends on the values of multiple attributes.
939 CSSMutableStyleDeclaration* attributeDecl = styledElement->additionalAttributeStyleDecl();
941 lastAuthorRule = m_matchedDecls.size();
942 if (firstAuthorRule == -1)
943 firstAuthorRule = lastAuthorRule;
944 addMatchedDeclaration(attributeDecl);
948 // 6. Check the rules in author sheets next.
949 if (m_matchAuthorAndUserStyles)
950 matchRules(m_authorStyle, firstAuthorRule, lastAuthorRule);
952 // 7. Now check our inline style attribute.
953 if (m_matchAuthorAndUserStyles && styledElement) {
954 CSSMutableStyleDeclaration* inlineDecl = styledElement->inlineStyleDecl();
956 lastAuthorRule = m_matchedDecls.size();
957 if (firstAuthorRule == -1)
958 firstAuthorRule = lastAuthorRule;
959 addMatchedDeclaration(inlineDecl);
964 // Now we have all of the matched rules in the appropriate order. Walk the rules and apply
965 // high-priority properties first, i.e., those properties that other properties depend on.
966 // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important
967 // and (4) normal important.
968 m_lineHeightValue = 0;
969 applyDeclarations(true, false, 0, m_matchedDecls.size() - 1);
970 if (!resolveForRootDefault) {
971 applyDeclarations(true, true, firstAuthorRule, lastAuthorRule);
972 applyDeclarations(true, true, firstUserRule, lastUserRule);
974 applyDeclarations(true, true, firstUARule, lastUARule);
976 // If our font got dirtied, go ahead and update it now.
980 // Line-height is set when we are sure we decided on the font-size
981 if (m_lineHeightValue)
982 applyProperty(CSS_PROP_LINE_HEIGHT, m_lineHeightValue);
984 // Now do the normal priority UA properties.
985 applyDeclarations(false, false, firstUARule, lastUARule);
987 // Cache our border and background so that we can examine them later.
988 cacheBorderAndBackground();
990 // Now do the author and user normal priority properties and all the !important properties.
991 if (!resolveForRootDefault) {
992 applyDeclarations(false, false, lastUARule + 1, m_matchedDecls.size() - 1);
993 applyDeclarations(false, true, firstAuthorRule, lastAuthorRule);
994 applyDeclarations(false, true, firstUserRule, lastUserRule);
996 applyDeclarations(false, true, firstUARule, lastUARule);
998 // If our font got dirtied by one of the non-essential font props,
999 // go ahead and update it a second time.
1003 // Clean up our style object's display and text decorations (among other fixups).
1004 adjustRenderStyle(style, e);
1006 // If we are a link, cache the determined pseudo-state.
1008 style->setPseudoState(pseudoState);
1010 // If we have first-letter pseudo style, do not share this style
1011 if (style->hasPseudoStyle(RenderStyle::FIRST_LETTER))
1014 // Now return the style.
1018 RenderStyle* CSSStyleSelector::pseudoStyleForElement(RenderStyle::PseudoId pseudo, Element* e, RenderStyle* parentStyle)
1023 initElementAndPseudoState(e);
1024 initForStyleResolve(e, parentStyle);
1025 pseudoStyle = pseudo;
1027 // Since we don't use pseudo-elements in any of our quirk/print user agent rules, don't waste time walking
1030 // Check UA, user and author rules.
1031 int firstUARule = -1, lastUARule = -1, firstUserRule = -1, lastUserRule = -1, firstAuthorRule = -1, lastAuthorRule = -1;
1032 matchUARules(firstUARule, lastUARule);
1034 if (m_matchAuthorAndUserStyles) {
1035 matchRules(m_userStyle, firstUserRule, lastUserRule);
1036 matchRules(m_authorStyle, firstAuthorRule, lastAuthorRule);
1039 if (m_matchedDecls.isEmpty())
1042 style = new (e->document()->renderArena()) RenderStyle();
1045 style->inheritFrom(parentStyle);
1047 parentStyle = style;
1048 style->noninherited_flags._styleType = pseudoStyle;
1050 m_lineHeightValue = 0;
1051 // High-priority properties.
1052 applyDeclarations(true, false, 0, m_matchedDecls.size() - 1);
1053 applyDeclarations(true, true, firstAuthorRule, lastAuthorRule);
1054 applyDeclarations(true, true, firstUserRule, lastUserRule);
1055 applyDeclarations(true, true, firstUARule, lastUARule);
1057 // If our font got dirtied, go ahead and update it now.
1061 // Line-height is set when we are sure we decided on the font-size
1062 if (m_lineHeightValue)
1063 applyProperty(CSS_PROP_LINE_HEIGHT, m_lineHeightValue);
1065 // Now do the normal priority properties.
1066 applyDeclarations(false, false, firstUARule, lastUARule);
1068 // Cache our border and background so that we can examine them later.
1069 cacheBorderAndBackground();
1071 applyDeclarations(false, false, lastUARule + 1, m_matchedDecls.size() - 1);
1072 applyDeclarations(false, true, firstAuthorRule, lastAuthorRule);
1073 applyDeclarations(false, true, firstUserRule, lastUserRule);
1074 applyDeclarations(false, true, firstUARule, lastUARule);
1076 // If our font got dirtied by one of the non-essential font props,
1077 // go ahead and update it a second time.
1080 // Clean up our style object's display and text decorations (among other fixups).
1081 adjustRenderStyle(style, 0);
1083 // Now return the style.
1087 static void addIntrinsicMargins(RenderStyle* style)
1089 // Intrinsic margin value.
1090 const int intrinsicMargin = 2;
1092 // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed.
1093 // FIXME: Using "quirk" to decide the margin wasn't set is kind of lame.
1094 if (style->width().isIntrinsicOrAuto()) {
1095 if (style->marginLeft().quirk())
1096 style->setMarginLeft(Length(intrinsicMargin, Fixed));
1097 if (style->marginRight().quirk())
1098 style->setMarginRight(Length(intrinsicMargin, Fixed));
1101 if (style->height().isAuto()) {
1102 if (style->marginTop().quirk())
1103 style->setMarginTop(Length(intrinsicMargin, Fixed));
1104 if (style->marginBottom().quirk())
1105 style->setMarginBottom(Length(intrinsicMargin, Fixed));
1109 void CSSStyleSelector::adjustRenderStyle(RenderStyle* style, Element *e)
1111 // Cache our original display.
1112 style->setOriginalDisplay(style->display());
1114 if (style->display() != NONE) {
1115 // If we have a <td> that specifies a float property, in quirks mode we just drop the float
1117 // Sites also commonly use display:inline/block on <td>s and <table>s. In quirks mode we force
1118 // these tags to retain their display types.
1119 if (!strictParsing && e) {
1120 if (e->hasTagName(tdTag)) {
1121 style->setDisplay(TABLE_CELL);
1122 style->setFloating(FNONE);
1124 else if (e->hasTagName(tableTag))
1125 style->setDisplay(style->isDisplayInlineType() ? INLINE_TABLE : TABLE);
1128 // Tables never support the -webkit-* values for text-align and will reset back to the default.
1129 if (e && e->hasTagName(tableTag) && (style->textAlign() == WEBKIT_LEFT || style->textAlign() == WEBKIT_CENTER || style->textAlign() == WEBKIT_RIGHT))
1130 style->setTextAlign(TAAUTO);
1132 // Frames and framesets never honor position:relative or position:absolute. This is necessary to
1133 // fix a crash where a site tries to position these objects. They also never honor display.
1134 if (e && (e->hasTagName(frameTag) || e->hasTagName(framesetTag))) {
1135 style->setPosition(StaticPosition);
1136 style->setDisplay(BLOCK);
1139 // Table headers with a text-align of auto will change the text-align to center.
1140 if (e && e->hasTagName(thTag) && style->textAlign() == TAAUTO)
1141 style->setTextAlign(CENTER);
1143 // Mutate the display to BLOCK or TABLE for certain cases, e.g., if someone attempts to
1144 // position or float an inline, compact, or run-in. Cache the original display, since it
1145 // may be needed for positioned elements that have to compute their static normal flow
1146 // positions. We also force inline-level roots to be block-level.
1147 if (style->display() != BLOCK && style->display() != TABLE && style->display() != BOX &&
1148 (style->position() == AbsolutePosition || style->position() == FixedPosition || style->floating() != FNONE ||
1149 (e && e->document()->documentElement() == e))) {
1150 if (style->display() == INLINE_TABLE)
1151 style->setDisplay(TABLE);
1152 else if (style->display() == INLINE_BOX)
1153 style->setDisplay(BOX);
1154 else if (style->display() == LIST_ITEM) {
1155 // It is a WinIE bug that floated list items lose their bullets, so we'll emulate the quirk,
1156 // but only in quirks mode.
1157 if (!strictParsing && style->floating() != FNONE)
1158 style->setDisplay(BLOCK);
1161 style->setDisplay(BLOCK);
1164 // After performing the display mutation, check table rows. We do not honor position:relative on
1165 // table rows or cells. This has been established in CSS2.1 (and caused a crash in containingBlock()
1167 if ((style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_ROW_GROUP ||
1168 style->display() == TABLE_FOOTER_GROUP || style->display() == TABLE_ROW || style->display() == TABLE_CELL) &&
1169 style->position() == RelativePosition)
1170 style->setPosition(StaticPosition);
1173 // Make sure our z-index value is only applied if the object is positioned,
1174 // relatively positioned, transparent, or has a transform.
1175 if (style->position() == StaticPosition && style->opacity() == 1.0f && !style->hasTransform())
1176 style->setHasAutoZIndex();
1178 // Auto z-index becomes 0 for the root element and transparent objects. This prevents
1179 // cases where objects that should be blended as a single unit end up with a non-transparent
1180 // object wedged in between them. Auto z-index also becomes 0 for objects that specify transforms.
1181 if (style->hasAutoZIndex() && ((e && e->document()->documentElement() == e) || style->opacity() < 1.0f || style->hasTransform()))
1182 style->setZIndex(0);
1184 // Button, legend, input, select and textarea all consider width values of 'auto' to be 'intrinsic'.
1185 // This will be important when we use block flows for all form controls.
1186 if (e && (e->hasTagName(legendTag) || e->hasTagName(buttonTag) || e->hasTagName(inputTag) ||
1187 e->hasTagName(selectTag) || e->hasTagName(textareaTag))) {
1188 if (style->width().isAuto())
1189 style->setWidth(Length(Intrinsic));
1192 // Finally update our text decorations in effect, but don't allow text-decoration to percolate through
1193 // tables, inline blocks, inline tables, or run-ins.
1194 if (style->display() == TABLE || style->display() == INLINE_TABLE || style->display() == RUN_IN
1195 || style->display() == INLINE_BLOCK || style->display() == INLINE_BOX)
1196 style->setTextDecorationsInEffect(style->textDecoration());
1198 style->addToTextDecorationsInEffect(style->textDecoration());
1200 // If either overflow value is not visible, change to auto.
1201 if (style->overflowX() == OMARQUEE && style->overflowY() != OMARQUEE)
1202 style->setOverflowY(OMARQUEE);
1203 else if (style->overflowY() == OMARQUEE && style->overflowX() != OMARQUEE)
1204 style->setOverflowX(OMARQUEE);
1205 else if (style->overflowX() == OVISIBLE && style->overflowY() != OVISIBLE)
1206 style->setOverflowX(OAUTO);
1207 else if (style->overflowY() == OVISIBLE && style->overflowX() != OVISIBLE)
1208 style->setOverflowY(OAUTO);
1210 // Table rows, sections and the table itself will support overflow:hidden and will ignore scroll/auto.
1211 // FIXME: Eventually table sections will support auto and scroll.
1212 if (style->display() == TABLE || style->display() == INLINE_TABLE ||
1213 style->display() == TABLE_ROW_GROUP || style->display() == TABLE_ROW) {
1214 if (style->overflowX() != OVISIBLE && style->overflowX() != OHIDDEN)
1215 style->setOverflowX(OVISIBLE);
1216 if (style->overflowY() != OVISIBLE && style->overflowY() != OHIDDEN)
1217 style->setOverflowY(OVISIBLE);
1220 // Cull out any useless layers and also repeat patterns into additional layers.
1221 style->adjustBackgroundLayers();
1223 // Do the same for transitions.
1224 style->adjustTransitions();
1226 // Important: Intrinsic margins get added to controls before the theme has adjusted the style, since the theme will
1227 // alter fonts and heights/widths.
1228 if (e && e->isControl() && style->fontSize() >= 11) {
1229 // Don't apply intrinsic margins to image buttons. The designer knows how big the images are,
1230 // so we have to treat all image buttons as though they were explicitly sized.
1231 if (!e->hasTagName(inputTag) || static_cast<HTMLInputElement*>(e)->inputType() != HTMLInputElement::IMAGE)
1232 addIntrinsicMargins(style);
1235 // Let the theme also have a crack at adjusting the style.
1236 if (style->hasAppearance())
1237 theme()->adjustStyle(this, style, e, m_hasUAAppearance, m_borderData, m_backgroundData, m_backgroundColor);
1240 if (e && e->isSVGElement()) {
1241 // Spec: http://www.w3.org/TR/SVG/masking.html#OverflowProperty
1242 if (style->overflowY() == OSCROLL)
1243 style->setOverflowY(OHIDDEN);
1244 else if (style->overflowY() == OAUTO)
1245 style->setOverflowY(OVISIBLE);
1247 if (style->overflowX() == OSCROLL)
1248 style->setOverflowX(OHIDDEN);
1249 else if (style->overflowX() == OAUTO)
1250 style->setOverflowX(OVISIBLE);
1252 // Only the root <svg> element in an SVG document fragment tree honors css position
1253 if (!(e->hasTagName(SVGNames::svgTag) && e->parentNode() && !e->parentNode()->isSVGElement()))
1254 style->setPosition(RenderStyle::initialPosition());
1259 void CSSStyleSelector::updateFont()
1261 checkForTextSizeAdjust();
1262 checkForGenericFamilyChange(style, parentStyle);
1263 style->font().update(m_fontSelector);
1267 void CSSStyleSelector::cacheBorderAndBackground()
1269 m_hasUAAppearance = style->hasAppearance();
1270 if (m_hasUAAppearance) {
1271 m_borderData = style->border();
1272 m_backgroundData = *style->backgroundLayers();
1273 m_backgroundColor = style->backgroundColor();
1277 RefPtr<CSSRuleList> CSSStyleSelector::styleRulesForElement(Element* e, bool authorOnly)
1279 if (!e || !e->document()->haveStylesheetsLoaded())
1282 m_collectRulesOnly = true;
1284 initElementAndPseudoState(e);
1285 initForStyleResolve(e, 0);
1288 int firstUARule = -1, lastUARule = -1;
1289 // First we match rules from the user agent sheet.
1290 matchUARules(firstUARule, lastUARule);
1292 // Now we check user sheet rules.
1293 if (m_matchAuthorAndUserStyles) {
1294 int firstUserRule = -1, lastUserRule = -1;
1295 matchRules(m_userStyle, firstUserRule, lastUserRule);
1299 if (m_matchAuthorAndUserStyles) {
1300 // Check the rules in author sheets.
1301 int firstAuthorRule = -1, lastAuthorRule = -1;
1302 matchRules(m_authorStyle, firstAuthorRule, lastAuthorRule);
1305 m_collectRulesOnly = false;
1310 RefPtr<CSSRuleList> CSSStyleSelector::pseudoStyleRulesForElement(Element* e, StringImpl* pseudoStyle, bool authorOnly)
1312 // FIXME: Implement this.
1316 bool CSSStyleSelector::checkSelector(CSSSelector* sel)
1318 dynamicPseudo = RenderStyle::NOPSEUDO;
1320 // Check the selector
1321 SelectorMatch match = checkSelector(sel, element, true, false);
1322 if (match != SelectorMatches)
1325 if (pseudoStyle != RenderStyle::NOPSEUDO && pseudoStyle != dynamicPseudo)
1331 // Recursive check of selectors and combinators
1332 // It can return 3 different values:
1333 // * SelectorMatches - the selector matches the element e
1334 // * SelectorFailsLocally - the selector fails for the element e
1335 // * SelectorFailsCompletely - the selector fails for e and any sibling or ancestor of e
1336 CSSStyleSelector::SelectorMatch CSSStyleSelector::checkSelector(CSSSelector* sel, Element* e, bool isAncestor, bool isSubSelector)
1339 // Spec: CSS2 selectors cannot be applied to the (conceptually) cloned DOM tree
1340 // because its contents are not part of the formal document structure.
1341 if (e->isSVGElement() && e->isShadowNode())
1342 return SelectorFailsCompletely;
1345 // first selector has to match
1346 if (!checkOneSelector(sel, e, isAncestor, isSubSelector))
1347 return SelectorFailsLocally;
1349 // The rest of the selectors has to match
1350 CSSSelector::Relation relation = sel->relation();
1353 sel = sel->m_tagHistory;
1355 return SelectorMatches;
1357 if (relation != CSSSelector::SubSelector)
1358 // Bail-out if this selector is irrelevant for the pseudoStyle
1359 if (pseudoStyle != RenderStyle::NOPSEUDO && pseudoStyle != dynamicPseudo)
1360 return SelectorFailsCompletely;
1363 case CSSSelector::Descendant:
1365 Node* n = e->parentNode();
1366 if (!n || !n->isElementNode())
1367 return SelectorFailsCompletely;
1368 e = static_cast<Element*>(n);
1369 SelectorMatch match = checkSelector(sel, e, true, false);
1370 if (match != SelectorFailsLocally)
1374 case CSSSelector::Child:
1376 Node* n = e->parentNode();
1377 if (!n || !n->isElementNode())
1378 return SelectorFailsCompletely;
1379 e = static_cast<Element*>(n);
1380 return checkSelector(sel, e, true, false);
1382 case CSSSelector::DirectAdjacent:
1384 Node* n = e->previousSibling();
1385 while (n && !n->isElementNode())
1386 n = n->previousSibling();
1388 return SelectorFailsLocally;
1389 e = static_cast<Element*>(n);
1390 return checkSelector(sel, e, false, false);
1392 case CSSSelector::IndirectAdjacent:
1394 Node* n = e->previousSibling();
1395 while (n && !n->isElementNode())
1396 n = n->previousSibling();
1398 return SelectorFailsLocally;
1399 e = static_cast<Element*>(n);
1400 SelectorMatch match = checkSelector(sel, e, false, false);
1401 if (match != SelectorFailsLocally)
1405 case CSSSelector::SubSelector:
1406 // a selector is invalid if something follows a pseudo-element
1407 if (e == element && dynamicPseudo != RenderStyle::NOPSEUDO)
1408 return SelectorFailsCompletely;
1409 return checkSelector(sel, e, isAncestor, true);
1412 return SelectorFailsCompletely;
1415 bool CSSStyleSelector::checkOneSelector(CSSSelector* sel, Element* e, bool isAncestor, bool isSubSelector)
1420 if (sel->hasTag()) {
1421 const AtomicString& localName = e->localName();
1422 const AtomicString& ns = e->namespaceURI();
1423 const AtomicString& selLocalName = sel->m_tag.localName();
1424 const AtomicString& selNS = sel->m_tag.namespaceURI();
1426 if ((selLocalName != starAtom && localName != selLocalName) ||
1427 (selNS != starAtom && ns != selNS))
1431 if (sel->hasAttribute()) {
1432 if (sel->m_match == CSSSelector::Class) {
1435 const ClassNames& classNames = *e->getClassNames();
1436 for (size_t i = 0; i < classNames.size(); ++i) {
1437 if (classNames[i] == sel->m_value)
1441 } else if (sel->m_match == CSSSelector::Id)
1442 return e->hasID() && e->getIDAttribute() == sel->m_value;
1443 else if (style && (e != element || !styledElement || (!styledElement->isMappedAttribute(sel->m_attr) && sel->m_attr != typeAttr && sel->m_attr != readonlyAttr))) {
1444 style->setAffectedByAttributeSelectors(); // Special-case the "type" and "readonly" attributes so input form controls can share style.
1445 m_selectorAttrs.add(sel->m_attr.localName().impl());
1448 const AtomicString& value = e->getAttribute(sel->m_attr);
1450 return false; // attribute is not set
1452 switch (sel->m_match) {
1453 case CSSSelector::Exact:
1454 if ((isXMLDoc && sel->m_value != value) || (!isXMLDoc && !equalIgnoringCase(sel->m_value, value)))
1457 case CSSSelector::List:
1459 // The selector's value can't contain a space, or it's totally bogus.
1460 if (sel->m_value.contains(' '))
1463 int startSearchAt = 0;
1465 int foundPos = value.find(sel->m_value, startSearchAt, isXMLDoc);
1468 if (foundPos == 0 || value[foundPos-1] == ' ') {
1469 unsigned endStr = foundPos + sel->m_value.length();
1470 if (endStr == value.length() || value[endStr] == ' ')
1471 break; // We found a match.
1474 // No match. Keep looking.
1475 startSearchAt = foundPos + 1;
1479 case CSSSelector::Contain:
1480 if (!value.contains(sel->m_value, isXMLDoc))
1483 case CSSSelector::Begin:
1484 if (!value.startsWith(sel->m_value, isXMLDoc))
1487 case CSSSelector::End:
1488 if (!value.endsWith(sel->m_value, isXMLDoc))
1491 case CSSSelector::Hyphen:
1492 if (value.length() < sel->m_value.length())
1494 if (!value.startsWith(sel->m_value, isXMLDoc))
1496 // It they start the same, check for exact match or following '-':
1497 if (value.length() != sel->m_value.length() && value[sel->m_value.length()] != '-')
1500 case CSSSelector::PseudoClass:
1501 case CSSSelector::PseudoElement:
1506 if (sel->m_match == CSSSelector::PseudoClass)
1508 switch (sel->pseudoType()) {
1510 case CSSSelector::PseudoEmpty:
1511 if (!e->firstChild())
1514 case CSSSelector::PseudoFirstChild: {
1515 // first-child matches the first child that is an element!
1516 if (e->parentNode() && e->parentNode()->isElementNode()) {
1517 Node *n = e->previousSibling();
1518 while (n && !n->isElementNode())
1519 n = n->previousSibling();
1525 case CSSSelector::PseudoFirstOfType: {
1526 // first-of-type matches the first element of its type!
1527 if (e->parentNode() && e->parentNode()->isElementNode()) {
1528 const QualifiedName& type = e->tagQName();
1529 Node *n = e->previousSibling();
1531 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
1533 n = n->previousSibling();
1540 case CSSSelector::PseudoTarget:
1541 if (e == e->document()->getCSSTarget())
1544 case CSSSelector::PseudoAnyLink:
1545 if (pseudoState == PseudoUnknown)
1546 checkPseudoState(e, false);
1547 if (pseudoState == PseudoAnyLink || pseudoState == PseudoLink || pseudoState == PseudoVisited)
1550 case CSSSelector::PseudoAutofill:
1551 if (e && e->hasTagName(inputTag))
1552 return static_cast<HTMLInputElement*>(e)->autofilled();
1554 case CSSSelector::PseudoLink:
1555 if (pseudoState == PseudoUnknown || pseudoState == PseudoAnyLink)
1556 checkPseudoState(e);
1557 if (pseudoState == PseudoLink)
1560 case CSSSelector::PseudoVisited:
1561 if (pseudoState == PseudoUnknown || pseudoState == PseudoAnyLink)
1562 checkPseudoState(e);
1563 if (pseudoState == PseudoVisited)
1566 case CSSSelector::PseudoDrag: {
1567 if (element == e && style)
1568 style->setAffectedByDragRules(true);
1569 if (element != e && e->renderStyle())
1570 e->renderStyle()->setAffectedByDragRules(true);
1571 if (e->renderer() && e->renderer()->isDragging())
1575 case CSSSelector::PseudoFocus:
1576 if (e && e->focused() && e->document()->frame()->isActive())
1579 case CSSSelector::PseudoHover: {
1580 // If we're in quirks mode, then hover should never match anchors with no
1581 // href and *:hover should not match anything. This is important for sites like wsj.com.
1582 if (strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {
1583 if (element == e && style)
1584 style->setAffectedByHoverRules(true);
1585 if (element != e && e->renderStyle())
1586 e->renderStyle()->setAffectedByHoverRules(true);
1592 case CSSSelector::PseudoActive:
1593 // If we're in quirks mode, then :active should never match anchors with no
1594 // href and *:active should not match anything.
1595 if (strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {
1596 if (element == e && style)
1597 style->setAffectedByActiveRules(true);
1598 else if (e->renderStyle())
1599 e->renderStyle()->setAffectedByActiveRules(true);
1604 case CSSSelector::PseudoEnabled:
1605 if (e && e->isControl())
1606 // The UI spec states that you can't match :enabled unless you are an object that can
1607 // "receive focus and be activated." We will limit matching of this pseudo-class to elements
1608 // that are controls.
1609 return e->isEnabled();
1611 case CSSSelector::PseudoDisabled:
1612 if (e && e->isControl())
1613 // The UI spec states that you can't match :enabled unless you are an object that can
1614 // "receive focus and be activated." We will limit matching of this pseudo-class to elements
1615 // that are controls.
1616 return !e->isEnabled();
1618 case CSSSelector::PseudoChecked:
1619 // Even though WinIE allows checked and indeterminate to co-exist, the CSS selector spec says that
1620 // you can't be both checked and indeterminate. We will behave like WinIE behind the scenes and just
1621 // obey the CSS spec here in the test for matching the pseudo.
1622 if (e && e->isChecked() && !e->isIndeterminate())
1625 case CSSSelector::PseudoIndeterminate:
1626 if (e && e->isIndeterminate())
1629 case CSSSelector::PseudoRoot:
1630 if (e == e->document()->documentElement())
1633 case CSSSelector::PseudoLang: {
1634 const AtomicString& value = e->getAttribute(langAttr);
1635 if (value.isEmpty() || !value.startsWith(sel->m_argument, false))
1637 if (value.length() != sel->m_argument.length() && value[sel->m_argument.length()] != '-')
1641 case CSSSelector::PseudoNot: {
1642 // check the simple selector
1643 for (CSSSelector* subSel = sel->m_simpleSelector; subSel; subSel = subSel->m_tagHistory) {
1644 // :not cannot nest. I don't really know why this is a
1645 // restriction in CSS3, but it is, so let's honour it.
1646 if (subSel->m_simpleSelector)
1648 if (!checkOneSelector(subSel, e, isAncestor, true))
1653 case CSSSelector::PseudoUnknown:
1654 case CSSSelector::PseudoNotParsed:
1656 ASSERT_NOT_REACHED();
1661 if (sel->m_match == CSSSelector::PseudoElement) {
1662 if (e != element) return false;
1664 switch (sel->pseudoType()) {
1666 case CSSSelector::PseudoFirstLine:
1667 dynamicPseudo = RenderStyle::FIRST_LINE;
1669 case CSSSelector::PseudoFirstLetter:
1670 dynamicPseudo = RenderStyle::FIRST_LETTER;
1671 if (Document* doc = e->document())
1672 doc->setUsesFirstLetterRules(true);
1674 case CSSSelector::PseudoSelection:
1675 dynamicPseudo = RenderStyle::SELECTION;
1677 case CSSSelector::PseudoBefore:
1678 dynamicPseudo = RenderStyle::BEFORE;
1680 case CSSSelector::PseudoAfter:
1681 dynamicPseudo = RenderStyle::AFTER;
1683 case CSSSelector::PseudoFileUploadButton:
1684 dynamicPseudo = RenderStyle::FILE_UPLOAD_BUTTON;
1686 case CSSSelector::PseudoSliderThumb:
1687 dynamicPseudo = RenderStyle::SLIDER_THUMB;
1689 case CSSSelector::PseudoSearchCancelButton:
1690 dynamicPseudo = RenderStyle::SEARCH_CANCEL_BUTTON;
1692 case CSSSelector::PseudoSearchDecoration:
1693 dynamicPseudo = RenderStyle::SEARCH_DECORATION;
1695 case CSSSelector::PseudoSearchResultsDecoration:
1696 dynamicPseudo = RenderStyle::SEARCH_RESULTS_DECORATION;
1698 case CSSSelector::PseudoSearchResultsButton:
1699 dynamicPseudo = RenderStyle::SEARCH_RESULTS_BUTTON;
1701 case CSSSelector::PseudoMediaControlsPanel:
1702 dynamicPseudo = RenderStyle::MEDIA_CONTROLS_PANEL;
1704 case CSSSelector::PseudoMediaControlsMuteButton:
1705 dynamicPseudo = RenderStyle::MEDIA_CONTROLS_MUTE_BUTTON;
1707 case CSSSelector::PseudoMediaControlsPlayButton:
1708 dynamicPseudo = RenderStyle::MEDIA_CONTROLS_PLAY_BUTTON;
1710 case CSSSelector::PseudoMediaControlsTimeDisplay:
1711 dynamicPseudo = RenderStyle::MEDIA_CONTROLS_TIME_DISPLAY;
1713 case CSSSelector::PseudoMediaControlsTimeline:
1714 dynamicPseudo = RenderStyle::MEDIA_CONTROLS_TIMELINE;
1716 case CSSSelector::PseudoUnknown:
1717 case CSSSelector::PseudoNotParsed:
1719 ASSERT_NOT_REACHED();
1724 // ### add the rest of the checks...
1728 // -----------------------------------------------------------------
1730 CSSRuleSet::CSSRuleSet()
1732 m_universalRules = 0;
1736 CSSRuleSet::~CSSRuleSet()
1738 deleteAllValues(m_idRules);
1739 deleteAllValues(m_classRules);
1740 deleteAllValues(m_tagRules);
1742 delete m_universalRules;
1746 void CSSRuleSet::addToRuleSet(AtomicStringImpl* key, AtomRuleMap& map,
1747 CSSStyleRule* rule, CSSSelector* sel)
1750 CSSRuleDataList* rules = map.get(key);
1752 rules = new CSSRuleDataList(m_ruleCount++, rule, sel);
1753 map.set(key, rules);
1755 rules->append(m_ruleCount++, rule, sel);
1758 void CSSRuleSet::addRule(CSSStyleRule* rule, CSSSelector* sel)
1760 if (sel->m_match == CSSSelector::Id) {
1761 addToRuleSet(sel->m_value.impl(), m_idRules, rule, sel);
1764 if (sel->m_match == CSSSelector::Class) {
1765 addToRuleSet(sel->m_value.impl(), m_classRules, rule, sel);
1769 const AtomicString& localName = sel->m_tag.localName();
1770 if (localName != starAtom) {
1771 addToRuleSet(localName.impl(), m_tagRules, rule, sel);
1775 // Just put it in the universal rule set.
1776 if (!m_universalRules)
1777 m_universalRules = new CSSRuleDataList(m_ruleCount++, rule, sel);
1779 m_universalRules->append(m_ruleCount++, rule, sel);
1782 void CSSRuleSet::addRulesFromSheet(CSSStyleSheet* sheet, const MediaQueryEvaluator& medium, CSSStyleSelector* styleSelector)
1784 if (!sheet || !sheet->isCSSStyleSheet())
1787 // No media implies "all", but if a media list exists it must
1788 // contain our current medium
1789 if (sheet->media() && !medium.eval(sheet->media()))
1790 return; // the style sheet doesn't apply
1792 int len = sheet->length();
1794 for (int i = 0; i < len; i++) {
1795 StyleBase* item = sheet->item(i);
1796 if (item->isStyleRule()) {
1797 CSSStyleRule* rule = static_cast<CSSStyleRule*>(item);
1798 for (CSSSelector* s = rule->selector(); s; s = s->next())
1801 else if (item->isImportRule()) {
1802 CSSImportRule* import = static_cast<CSSImportRule*>(item);
1803 if (!import->media() || medium.eval(import->media()))
1804 addRulesFromSheet(import->styleSheet(), medium, styleSelector);
1806 else if (item->isMediaRule()) {
1807 CSSMediaRule* r = static_cast<CSSMediaRule*>(item);
1808 CSSRuleList* rules = r->cssRules();
1810 if ((!r->media() || medium.eval(r->media())) && rules) {
1811 // Traverse child elements of the @media rule.
1812 for (unsigned j = 0; j < rules->length(); j++) {
1813 CSSRule *childItem = rules->item(j);
1814 if (childItem->isStyleRule()) {
1815 // It is a StyleRule, so append it to our list
1816 CSSStyleRule* rule = static_cast<CSSStyleRule*>(childItem);
1817 for (CSSSelector* s = rule->selector(); s; s = s->next())
1819 } else if (item->isFontFaceRule() && styleSelector) {
1820 // Add this font face to our set.
1821 const CSSFontFaceRule* fontFaceRule = static_cast<CSSFontFaceRule*>(item);
1822 styleSelector->ensureFontSelector()->addFontFaceRule(fontFaceRule);
1826 } else if (item->isFontFaceRule() && styleSelector) {
1827 // Add this font face to our set.
1828 const CSSFontFaceRule* fontFaceRule = static_cast<CSSFontFaceRule*>(item);
1829 styleSelector->ensureFontSelector()->addFontFaceRule(fontFaceRule);
1834 // -------------------------------------------------------------------------------------
1835 // this is mostly boring stuff on how to apply a certain rule to the renderstyle...
1837 static Length convertToLength(CSSPrimitiveValue *primitiveValue, RenderStyle *style, bool *ok = 0)
1840 if (!primitiveValue) {
1844 int type = primitiveValue->primitiveType();
1845 if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
1846 l = Length(primitiveValue->computeLengthIntForLength(style), Fixed);
1847 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
1848 l = Length(primitiveValue->getDoubleValue(), Percent);
1849 else if (type == CSSPrimitiveValue::CSS_NUMBER)
1850 l = Length(primitiveValue->getDoubleValue() * 100.0, Percent);
1857 void CSSStyleSelector::applyDeclarations(bool applyFirst, bool isImportant,
1858 int startIndex, int endIndex)
1860 if (startIndex == -1) return;
1861 for (int i = startIndex; i <= endIndex; i++) {
1862 CSSMutableStyleDeclaration* decl = m_matchedDecls[i];
1863 DeprecatedValueListConstIterator<CSSProperty> end;
1864 for (DeprecatedValueListConstIterator<CSSProperty> it = decl->valuesIterator(); it != end; ++it) {
1865 const CSSProperty& current = *it;
1866 // give special priority to font-xxx, color properties
1867 if (isImportant == current.isImportant()) {
1869 switch (current.id()) {
1870 case CSS_PROP_LINE_HEIGHT:
1871 m_lineHeightValue = current.value();
1872 first = !applyFirst; // we apply line-height later
1874 case CSS_PROP_COLOR:
1875 case CSS_PROP_DIRECTION:
1876 case CSS_PROP_DISPLAY:
1878 case CSS_PROP_FONT_SIZE:
1879 case CSS_PROP_FONT_STYLE:
1880 case CSS_PROP_FONT_FAMILY:
1881 case CSS_PROP_FONT_WEIGHT:
1882 case CSS_PROP__WEBKIT_TEXT_SIZE_ADJUST:
1883 case CSS_PROP_FONT_VARIANT:
1884 // these have to be applied first, because other properties use the computed
1885 // values of these porperties.
1892 if (first == applyFirst)
1893 applyProperty(current.id(), current.value());
1899 static void applyCounterList(RenderStyle* style, CSSValueList* list, bool isReset)
1901 CounterDirectiveMap& map = style->accessCounterDirectives();
1902 typedef CounterDirectiveMap::iterator Iterator;
1904 Iterator end = map.end();
1905 for (Iterator it = map.begin(); it != end; ++it)
1907 it->second.m_reset = false;
1909 it->second.m_increment = false;
1911 int length = list ? list->length() : 0;
1912 for (int i = 0; i < length; ++i) {
1913 Pair* pair = static_cast<CSSPrimitiveValue*>(list->item(i))->getPairValue();
1914 AtomicString identifier = static_cast<CSSPrimitiveValue*>(pair->first())->getStringValue();
1915 // FIXME: What about overflow?
1916 int value = static_cast<CSSPrimitiveValue*>(pair->second())->getIntValue();
1917 CounterDirectives& directives = map.add(identifier.impl(), CounterDirectives()).first->second;
1919 directives.m_reset = true;
1920 directives.m_resetValue = value;
1922 if (directives.m_increment)
1923 directives.m_incrementValue += value;
1925 directives.m_increment = true;
1926 directives.m_incrementValue = value;
1932 void CSSStyleSelector::applyProperty(int id, CSSValue *value)
1934 CSSPrimitiveValue* primitiveValue = 0;
1935 if (value->isPrimitiveValue())
1936 primitiveValue = static_cast<CSSPrimitiveValue*>(value);
1941 unsigned short valueType = value->cssValueType();
1943 bool isInherit = parentNode && valueType == CSSValue::CSS_INHERIT;
1944 bool isInitial = valueType == CSSValue::CSS_INITIAL || (!parentNode && valueType == CSSValue::CSS_INHERIT);
1946 // These properties are used to set the correct margins/padding on RTL lists.
1947 if (id == CSS_PROP__WEBKIT_MARGIN_START)
1948 id = style->direction() == LTR ? CSS_PROP_MARGIN_LEFT : CSS_PROP_MARGIN_RIGHT;
1949 else if (id == CSS_PROP__WEBKIT_PADDING_START)
1950 id = style->direction() == LTR ? CSS_PROP_PADDING_LEFT : CSS_PROP_PADDING_RIGHT;
1952 // What follows is a list that maps the CSS properties into their corresponding front-end
1953 // RenderStyle values. Shorthands (e.g. border, background) occur in this list as well and
1954 // are only hit when mapping "inherit" or "initial" into front-end values.
1955 switch (static_cast<CSSPropertyID>(id)) {
1956 // ident only properties
1957 case CSS_PROP_BACKGROUND_ATTACHMENT:
1958 HANDLE_BACKGROUND_VALUE(backgroundAttachment, BackgroundAttachment, value)
1960 case CSS_PROP__WEBKIT_BACKGROUND_CLIP:
1961 HANDLE_BACKGROUND_VALUE(backgroundClip, BackgroundClip, value)
1963 case CSS_PROP__WEBKIT_BACKGROUND_COMPOSITE:
1964 HANDLE_BACKGROUND_VALUE(backgroundComposite, BackgroundComposite, value)
1966 case CSS_PROP__WEBKIT_BACKGROUND_ORIGIN:
1967 HANDLE_BACKGROUND_VALUE(backgroundOrigin, BackgroundOrigin, value)
1969 case CSS_PROP_BACKGROUND_REPEAT:
1970 HANDLE_BACKGROUND_VALUE(backgroundRepeat, BackgroundRepeat, value)
1972 case CSS_PROP__WEBKIT_BACKGROUND_SIZE:
1973 HANDLE_BACKGROUND_VALUE(backgroundSize, BackgroundSize, value)
1975 case CSS_PROP_BORDER_COLLAPSE:
1976 HANDLE_INHERIT_AND_INITIAL(borderCollapse, BorderCollapse)
1977 if (!primitiveValue)
1979 switch (primitiveValue->getIdent()) {
1980 case CSS_VAL_COLLAPSE:
1981 style->setBorderCollapse(true);
1983 case CSS_VAL_SEPARATE:
1984 style->setBorderCollapse(false);
1991 case CSS_PROP_BORDER_TOP_STYLE:
1992 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderTopStyle, BorderTopStyle, BorderStyle)
1994 style->setBorderTopStyle(*primitiveValue);
1996 case CSS_PROP_BORDER_RIGHT_STYLE:
1997 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderRightStyle, BorderRightStyle, BorderStyle)
1999 style->setBorderRightStyle(*primitiveValue);
2001 case CSS_PROP_BORDER_BOTTOM_STYLE:
2002 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderBottomStyle, BorderBottomStyle, BorderStyle)
2004 style->setBorderBottomStyle(*primitiveValue);
2006 case CSS_PROP_BORDER_LEFT_STYLE:
2007 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderLeftStyle, BorderLeftStyle, BorderStyle)
2009 style->setBorderLeftStyle(*primitiveValue);
2011 case CSS_PROP_OUTLINE_STYLE:
2012 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(outlineStyle, OutlineStyle, BorderStyle)
2013 if (primitiveValue) {
2014 if (primitiveValue->getIdent() == CSS_VAL_AUTO)
2015 style->setOutlineStyle(DOTTED, true);
2017 style->setOutlineStyle(*primitiveValue);
2020 case CSS_PROP_CAPTION_SIDE:
2022 HANDLE_INHERIT_AND_INITIAL(captionSide, CaptionSide)
2024 style->setCaptionSide(*primitiveValue);
2027 case CSS_PROP_CLEAR:
2029 HANDLE_INHERIT_AND_INITIAL(clear, Clear)
2031 style->setClear(*primitiveValue);
2034 case CSS_PROP_DIRECTION:
2036 HANDLE_INHERIT_AND_INITIAL(direction, Direction)
2038 style->setDirection(*primitiveValue);
2041 case CSS_PROP_DISPLAY:
2043 HANDLE_INHERIT_AND_INITIAL(display, Display)
2045 style->setDisplay(*primitiveValue);
2049 case CSS_PROP_EMPTY_CELLS:
2051 HANDLE_INHERIT_AND_INITIAL(emptyCells, EmptyCells)
2053 style->setEmptyCells(*primitiveValue);
2056 case CSS_PROP_FLOAT:
2058 HANDLE_INHERIT_AND_INITIAL(floating, Floating)
2060 style->setFloating(*primitiveValue);
2064 case CSS_PROP_FONT_STYLE:
2066 FontDescription fontDescription = style->fontDescription();
2068 fontDescription.setItalic(parentStyle->fontDescription().italic());
2070 fontDescription.setItalic(false);
2072 if (!primitiveValue)
2074 switch (primitiveValue->getIdent()) {
2075 case CSS_VAL_OBLIQUE:
2076 // FIXME: oblique is the same as italic for the moment...
2077 case CSS_VAL_ITALIC:
2078 fontDescription.setItalic(true);
2080 case CSS_VAL_NORMAL:
2081 fontDescription.setItalic(false);
2087 if (style->setFontDescription(fontDescription))
2092 case CSS_PROP_FONT_VARIANT:
2094 FontDescription fontDescription = style->fontDescription();
2096 fontDescription.setSmallCaps(parentStyle->fontDescription().smallCaps());
2098 fontDescription.setSmallCaps(false);
2100 if (!primitiveValue)
2102 int id = primitiveValue->getIdent();
2103 if (id == CSS_VAL_NORMAL)
2104 fontDescription.setSmallCaps(false);
2105 else if (id == CSS_VAL_SMALL_CAPS)
2106 fontDescription.setSmallCaps(true);
2110 if (style->setFontDescription(fontDescription))
2115 case CSS_PROP_FONT_WEIGHT:
2117 FontDescription fontDescription = style->fontDescription();
2119 fontDescription.setWeight(parentStyle->fontDescription().weight());
2121 fontDescription.setWeight(cNormalWeight);
2123 if (!primitiveValue)
2125 if (primitiveValue->getIdent()) {
2126 switch (primitiveValue->getIdent()) {
2127 // FIXME: We aren't genuinely supporting specific weight values.
2129 case CSS_VAL_BOLDER:
2134 fontDescription.setWeight(cBoldWeight);
2136 case CSS_VAL_NORMAL:
2137 case CSS_VAL_LIGHTER:
2143 fontDescription.setWeight(cNormalWeight);
2151 // ### fix parsing of 100-900 values in parser, apply them here
2154 if (style->setFontDescription(fontDescription))
2159 case CSS_PROP_LIST_STYLE_POSITION:
2161 HANDLE_INHERIT_AND_INITIAL(listStylePosition, ListStylePosition)
2163 style->setListStylePosition(*primitiveValue);
2167 case CSS_PROP_LIST_STYLE_TYPE:
2169 HANDLE_INHERIT_AND_INITIAL(listStyleType, ListStyleType)
2171 style->setListStyleType(*primitiveValue);
2175 case CSS_PROP_OVERFLOW:
2178 style->setOverflowX(parentStyle->overflowX());
2179 style->setOverflowY(parentStyle->overflowY());
2184 style->setOverflowX(RenderStyle::initialOverflowX());
2185 style->setOverflowY(RenderStyle::initialOverflowY());
2189 EOverflow o = *primitiveValue;
2191 style->setOverflowX(o);
2192 style->setOverflowY(o);
2196 case CSS_PROP_OVERFLOW_X:
2198 HANDLE_INHERIT_AND_INITIAL(overflowX, OverflowX)
2199 style->setOverflowX(*primitiveValue);
2203 case CSS_PROP_OVERFLOW_Y:
2205 HANDLE_INHERIT_AND_INITIAL(overflowY, OverflowY)
2206 style->setOverflowY(*primitiveValue);
2210 case CSS_PROP_PAGE_BREAK_BEFORE:
2212 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(pageBreakBefore, PageBreakBefore, PageBreak)
2214 style->setPageBreakBefore(*primitiveValue);
2218 case CSS_PROP_PAGE_BREAK_AFTER:
2220 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(pageBreakAfter, PageBreakAfter, PageBreak)
2222 style->setPageBreakAfter(*primitiveValue);
2226 case CSS_PROP_PAGE_BREAK_INSIDE: {
2227 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(pageBreakInside, PageBreakInside, PageBreak)
2228 if (!primitiveValue)
2230 EPageBreak pageBreak = *primitiveValue;
2231 if (pageBreak != PBALWAYS)
2232 style->setPageBreakInside(pageBreak);
2236 case CSS_PROP_POSITION:
2238 HANDLE_INHERIT_AND_INITIAL(position, Position)
2240 style->setPosition(*primitiveValue);
2244 case CSS_PROP_TABLE_LAYOUT: {
2245 HANDLE_INHERIT_AND_INITIAL(tableLayout, TableLayout)
2247 ETableLayout l = *primitiveValue;
2249 l = RenderStyle::initialTableLayout();
2251 style->setTableLayout(l);
2255 case CSS_PROP_UNICODE_BIDI: {
2256 HANDLE_INHERIT_AND_INITIAL(unicodeBidi, UnicodeBidi)
2257 style->setUnicodeBidi(*primitiveValue);
2260 case CSS_PROP_TEXT_TRANSFORM: {
2261 HANDLE_INHERIT_AND_INITIAL(textTransform, TextTransform)
2262 style->setTextTransform(*primitiveValue);
2266 case CSS_PROP_VISIBILITY:
2268 HANDLE_INHERIT_AND_INITIAL(visibility, Visibility)
2269 style->setVisibility(*primitiveValue);
2272 case CSS_PROP_WHITE_SPACE:
2273 HANDLE_INHERIT_AND_INITIAL(whiteSpace, WhiteSpace)
2274 style->setWhiteSpace(*primitiveValue);
2277 case CSS_PROP_BACKGROUND_POSITION:
2278 HANDLE_BACKGROUND_INHERIT_AND_INITIAL(backgroundXPosition, BackgroundXPosition);
2279 HANDLE_BACKGROUND_INHERIT_AND_INITIAL(backgroundYPosition, BackgroundYPosition);
2281 case CSS_PROP_BACKGROUND_POSITION_X: {
2282 HANDLE_BACKGROUND_VALUE(backgroundXPosition, BackgroundXPosition, value)
2285 case CSS_PROP_BACKGROUND_POSITION_Y: {
2286 HANDLE_BACKGROUND_VALUE(backgroundYPosition, BackgroundYPosition, value)
2289 case CSS_PROP_BORDER_SPACING: {
2291 style->setHorizontalBorderSpacing(parentStyle->horizontalBorderSpacing());
2292 style->setVerticalBorderSpacing(parentStyle->verticalBorderSpacing());
2294 else if (isInitial) {
2295 style->setHorizontalBorderSpacing(0);
2296 style->setVerticalBorderSpacing(0);
2300 case CSS_PROP__WEBKIT_BORDER_HORIZONTAL_SPACING: {
2301 HANDLE_INHERIT_AND_INITIAL(horizontalBorderSpacing, HorizontalBorderSpacing)
2302 if (!primitiveValue)
2304 short spacing = primitiveValue->computeLengthShort(style);
2305 style->setHorizontalBorderSpacing(spacing);
2308 case CSS_PROP__WEBKIT_BORDER_VERTICAL_SPACING: {
2309 HANDLE_INHERIT_AND_INITIAL(verticalBorderSpacing, VerticalBorderSpacing)
2310 if (!primitiveValue)
2312 short spacing = primitiveValue->computeLengthShort(style);
2313 style->setVerticalBorderSpacing(spacing);
2316 case CSS_PROP_CURSOR:
2318 style->setCursor(parentStyle->cursor());
2319 style->setCursorList(parentStyle->cursors());
2322 style->clearCursorList();
2324 style->setCursor(RenderStyle::initialCursor());
2327 if (value->isValueList()) {
2328 CSSValueList* list = static_cast<CSSValueList*>(value);
2329 int len = list->length();
2330 style->setCursor(CURSOR_AUTO);
2331 for (int i = 0; i < len; i++) {
2332 CSSValue* item = list->item(i);
2333 if (!item->isPrimitiveValue())
2335 primitiveValue = static_cast<CSSPrimitiveValue*>(item);
2336 int type = primitiveValue->primitiveType();
2337 if (type == CSSPrimitiveValue::CSS_URI) {
2339 if (primitiveValue->getStringValue().find("#") == 0)
2340 style->addSVGCursor(primitiveValue->getStringValue().substring(1));
2344 CSSCursorImageValue* image = static_cast<CSSCursorImageValue*>(primitiveValue);
2345 style->addCursor(image->image(element->document()->docLoader()), image->hotspot());
2347 } else if (type == CSSPrimitiveValue::CSS_IDENT)
2348 style->setCursor(*primitiveValue);
2350 } else if (primitiveValue) {
2351 int type = primitiveValue->primitiveType();
2352 if (type == CSSPrimitiveValue::CSS_IDENT)
2353 style->setCursor(*primitiveValue);
2356 // colors || inherit
2357 case CSS_PROP_BACKGROUND_COLOR:
2358 case CSS_PROP_BORDER_TOP_COLOR:
2359 case CSS_PROP_BORDER_RIGHT_COLOR:
2360 case CSS_PROP_BORDER_BOTTOM_COLOR:
2361 case CSS_PROP_BORDER_LEFT_COLOR:
2362 case CSS_PROP_COLOR:
2363 case CSS_PROP_OUTLINE_COLOR:
2364 case CSS_PROP__WEBKIT_COLUMN_RULE_COLOR:
2365 case CSS_PROP__WEBKIT_TEXT_STROKE_COLOR:
2366 case CSS_PROP__WEBKIT_TEXT_FILL_COLOR: {
2369 HANDLE_INHERIT_COND(CSS_PROP_BACKGROUND_COLOR, backgroundColor, BackgroundColor)
2370 HANDLE_INHERIT_COND(CSS_PROP_BORDER_TOP_COLOR, borderTopColor, BorderTopColor)
2371 HANDLE_INHERIT_COND(CSS_PROP_BORDER_BOTTOM_COLOR, borderBottomColor, BorderBottomColor)
2372 HANDLE_INHERIT_COND(CSS_PROP_BORDER_RIGHT_COLOR, borderRightColor, BorderRightColor)
2373 HANDLE_INHERIT_COND(CSS_PROP_BORDER_LEFT_COLOR, borderLeftColor, BorderLeftColor)
2374 HANDLE_INHERIT_COND(CSS_PROP_COLOR, color, Color)
2375 HANDLE_INHERIT_COND(CSS_PROP_OUTLINE_COLOR, outlineColor, OutlineColor)
2376 HANDLE_INHERIT_COND(CSS_PROP__WEBKIT_COLUMN_RULE_COLOR, columnRuleColor, ColumnRuleColor)
2377 HANDLE_INHERIT_COND(CSS_PROP__WEBKIT_TEXT_STROKE_COLOR, textStrokeColor, TextStrokeColor)
2378 HANDLE_INHERIT_COND(CSS_PROP__WEBKIT_TEXT_FILL_COLOR, textFillColor, TextFillColor)
2382 // The border/outline colors will just map to the invalid color |col| above. This will have the
2383 // effect of forcing the use of the currentColor when it comes time to draw the borders (and of
2384 // not painting the background since the color won't be valid).
2385 if (id == CSS_PROP_COLOR)
2386 col = RenderStyle::initialColor();
2388 if (!primitiveValue)
2390 col = getColorFromPrimitiveValue(primitiveValue);
2394 case CSS_PROP_BACKGROUND_COLOR:
2395 style->setBackgroundColor(col); break;
2396 case CSS_PROP_BORDER_TOP_COLOR:
2397 style->setBorderTopColor(col); break;
2398 case CSS_PROP_BORDER_RIGHT_COLOR:
2399 style->setBorderRightColor(col); break;
2400 case CSS_PROP_BORDER_BOTTOM_COLOR:
2401 style->setBorderBottomColor(col); break;
2402 case CSS_PROP_BORDER_LEFT_COLOR:
2403 style->setBorderLeftColor(col); break;
2404 case CSS_PROP_COLOR:
2405 style->setColor(col); break;
2406 case CSS_PROP_OUTLINE_COLOR:
2407 style->setOutlineColor(col); break;
2408 case CSS_PROP__WEBKIT_COLUMN_RULE_COLOR:
2409 style->setColumnRuleColor(col);
2411 case CSS_PROP__WEBKIT_TEXT_STROKE_COLOR:
2412 style->setTextStrokeColor(col);
2414 case CSS_PROP__WEBKIT_TEXT_FILL_COLOR:
2415 style->setTextFillColor(col);
2423 case CSS_PROP_BACKGROUND_IMAGE:
2424 HANDLE_BACKGROUND_VALUE(backgroundImage, BackgroundImage, value)
2426 case CSS_PROP_LIST_STYLE_IMAGE:
2428 HANDLE_INHERIT_AND_INITIAL(listStyleImage, ListStyleImage)
2429 if (!primitiveValue)
2431 style->setListStyleImage(static_cast<CSSImageValue*>(primitiveValue)->image(element->document()->docLoader()));
2436 case CSS_PROP_BORDER_TOP_WIDTH:
2437 case CSS_PROP_BORDER_RIGHT_WIDTH:
2438 case CSS_PROP_BORDER_BOTTOM_WIDTH:
2439 case CSS_PROP_BORDER_LEFT_WIDTH:
2440 case CSS_PROP_OUTLINE_WIDTH:
2441 case CSS_PROP__WEBKIT_COLUMN_RULE_WIDTH:
2444 HANDLE_INHERIT_COND(CSS_PROP_BORDER_TOP_WIDTH, borderTopWidth, BorderTopWidth)
2445 HANDLE_INHERIT_COND(CSS_PROP_BORDER_RIGHT_WIDTH, borderRightWidth, BorderRightWidth)
2446 HANDLE_INHERIT_COND(CSS_PROP_BORDER_BOTTOM_WIDTH, borderBottomWidth, BorderBottomWidth)
2447 HANDLE_INHERIT_COND(CSS_PROP_BORDER_LEFT_WIDTH, borderLeftWidth, BorderLeftWidth)
2448 HANDLE_INHERIT_COND(CSS_PROP_OUTLINE_WIDTH, outlineWidth, OutlineWidth)
2449 HANDLE_INHERIT_COND(CSS_PROP__WEBKIT_COLUMN_RULE_WIDTH, columnRuleWidth, ColumnRuleWidth)
2452 else if (isInitial) {
2453 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_TOP_WIDTH, BorderTopWidth, BorderWidth)
2454 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_RIGHT_WIDTH, BorderRightWidth, BorderWidth)
2455 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_BOTTOM_WIDTH, BorderBottomWidth, BorderWidth)
2456 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_LEFT_WIDTH, BorderLeftWidth, BorderWidth)
2457 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_OUTLINE_WIDTH, OutlineWidth, BorderWidth)
2458 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP__WEBKIT_COLUMN_RULE_WIDTH, ColumnRuleWidth, BorderWidth)
2462 if (!primitiveValue)
2465 switch (primitiveValue->getIdent()) {
2469 case CSS_VAL_MEDIUM:
2475 case CSS_VAL_INVALID:
2476 width = primitiveValue->computeLengthShort(style);
2482 if (width < 0) return;
2484 case CSS_PROP_BORDER_TOP_WIDTH:
2485 style->setBorderTopWidth(width);
2487 case CSS_PROP_BORDER_RIGHT_WIDTH:
2488 style->setBorderRightWidth(width);
2490 case CSS_PROP_BORDER_BOTTOM_WIDTH:
2491 style->setBorderBottomWidth(width);
2493 case CSS_PROP_BORDER_LEFT_WIDTH:
2494 style->setBorderLeftWidth(width);
2496 case CSS_PROP_OUTLINE_WIDTH:
2497 style->setOutlineWidth(width);
2499 case CSS_PROP__WEBKIT_COLUMN_RULE_WIDTH:
2500 style->setColumnRuleWidth(width);
2508 case CSS_PROP_LETTER_SPACING:
2509 case CSS_PROP_WORD_SPACING:
2513 HANDLE_INHERIT_COND(CSS_PROP_LETTER_SPACING, letterSpacing, LetterSpacing)
2514 HANDLE_INHERIT_COND(CSS_PROP_WORD_SPACING, wordSpacing, WordSpacing)
2517 else if (isInitial) {
2518 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_LETTER_SPACING, LetterSpacing, LetterWordSpacing)
2519 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_WORD_SPACING, WordSpacing, LetterWordSpacing)
2524 if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_NORMAL){
2527 if (!primitiveValue)
2529 width = primitiveValue->computeLengthInt(style);
2532 case CSS_PROP_LETTER_SPACING:
2533 style->setLetterSpacing(width);
2535 case CSS_PROP_WORD_SPACING:
2536 style->setWordSpacing(width);
2538 // ### needs the definitions in renderstyle
2544 case CSS_PROP_WORD_BREAK: {
2545 HANDLE_INHERIT_AND_INITIAL(wordBreak, WordBreak)
2546 style->setWordBreak(*primitiveValue);
2550 case CSS_PROP_WORD_WRAP: {
2551 HANDLE_INHERIT_AND_INITIAL(wordWrap, WordWrap)
2552 style->setWordWrap(*primitiveValue);
2556 case CSS_PROP__WEBKIT_NBSP_MODE:
2558 HANDLE_INHERIT_AND_INITIAL(nbspMode, NBSPMode)
2559 style->setNBSPMode(*primitiveValue);
2563 case CSS_PROP__WEBKIT_LINE_BREAK:
2565 HANDLE_INHERIT_AND_INITIAL(khtmlLineBreak, KHTMLLineBreak)
2566 style->setKHTMLLineBreak(*primitiveValue);
2570 case CSS_PROP__WEBKIT_MATCH_NEAREST_MAIL_BLOCKQUOTE_COLOR:
2572 HANDLE_INHERIT_AND_INITIAL(matchNearestMailBlockquoteColor, MatchNearestMailBlockquoteColor)
2573 style->setMatchNearestMailBlockquoteColor(*primitiveValue);
2577 case CSS_PROP_RESIZE:
2579 HANDLE_INHERIT_AND_INITIAL(resize, Resize)
2581 if (!primitiveValue->getIdent())
2584 EResize r = RESIZE_NONE;
2585 if (primitiveValue->getIdent() == CSS_VAL_AUTO) {
2586 if (Settings* settings = m_document->settings())
2587 r = settings->textAreasAreResizable() ? RESIZE_BOTH : RESIZE_NONE;
2589 r = *primitiveValue;
2591 style->setResize(r);
2596 case CSS_PROP_MAX_WIDTH:
2598 if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_NONE)
2602 case CSS_PROP_RIGHT:
2603 case CSS_PROP_BOTTOM:
2604 case CSS_PROP_WIDTH:
2605 case CSS_PROP_MIN_WIDTH:
2606 case CSS_PROP_MARGIN_TOP:
2607 case CSS_PROP_MARGIN_RIGHT:
2608 case CSS_PROP_MARGIN_BOTTOM:
2609 case CSS_PROP_MARGIN_LEFT:
2611 if (id == CSS_PROP_WIDTH || id == CSS_PROP_MIN_WIDTH || id == CSS_PROP_MAX_WIDTH) {
2612 if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_INTRINSIC) {
2613 l = Length(Intrinsic);
2616 else if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_MIN_INTRINSIC) {
2617 l = Length(MinIntrinsic);
2621 if (id != CSS_PROP_MAX_WIDTH && primitiveValue && primitiveValue->getIdent() == CSS_VAL_AUTO)
2623 case CSS_PROP_PADDING_TOP:
2624 case CSS_PROP_PADDING_RIGHT:
2625 case CSS_PROP_PADDING_BOTTOM:
2626 case CSS_PROP_PADDING_LEFT:
2627 case CSS_PROP_TEXT_INDENT:
2631 HANDLE_INHERIT_COND(CSS_PROP_MAX_WIDTH, maxWidth, MaxWidth)
2632 HANDLE_INHERIT_COND(CSS_PROP_BOTTOM, bottom, Bottom)
2633 HANDLE_INHERIT_COND(CSS_PROP_TOP, top, Top)
2634 HANDLE_INHERIT_COND(CSS_PROP_LEFT, left, Left)
2635 HANDLE_INHERIT_COND(CSS_PROP_RIGHT, right, Right)
2636 HANDLE_INHERIT_COND(CSS_PROP_WIDTH, width, Width)
2637 HANDLE_INHERIT_COND(CSS_PROP_MIN_WIDTH, minWidth, MinWidth)
2638 HANDLE_INHERIT_COND(CSS_PROP_PADDING_TOP, paddingTop, PaddingTop)
2639 HANDLE_INHERIT_COND(CSS_PROP_PADDING_RIGHT, paddingRight, PaddingRight)
2640 HANDLE_INHERIT_COND(CSS_PROP_PADDING_BOTTOM, paddingBottom, PaddingBottom)
2641 HANDLE_INHERIT_COND(CSS_PROP_PADDING_LEFT, paddingLeft, PaddingLeft)
2642 HANDLE_INHERIT_COND(CSS_PROP_MARGIN_TOP, marginTop, MarginTop)
2643 HANDLE_INHERIT_COND(CSS_PROP_MARGIN_RIGHT, marginRight, MarginRight)
2644 HANDLE_INHERIT_COND(CSS_PROP_MARGIN_BOTTOM, marginBottom, MarginBottom)
2645 HANDLE_INHERIT_COND(CSS_PROP_MARGIN_LEFT, marginLeft, MarginLeft)
2646 HANDLE_INHERIT_COND(CSS_PROP_TEXT_INDENT, textIndent, TextIndent)
2649 else if (isInitial) {
2650 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MAX_WIDTH, MaxWidth, MaxSize)
2651 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BOTTOM, Bottom, Offset)
2652 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_TOP, Top, Offset)
2653 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_LEFT, Left, Offset)
2654 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_RIGHT, Right, Offset)
2655 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_WIDTH, Width, Size)
2656 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MIN_WIDTH, MinWidth, MinSize)
2657 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_PADDING_TOP, PaddingTop, Padding)
2658 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_PADDING_RIGHT, PaddingRight, Padding)
2659 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_PADDING_BOTTOM, PaddingBottom, Padding)
2660 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_PADDING_LEFT, PaddingLeft, Padding)
2661 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MARGIN_TOP, MarginTop, Margin)
2662 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MARGIN_RIGHT, MarginRight, Margin)
2663 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MARGIN_BOTTOM, MarginBottom, Margin)
2664 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MARGIN_LEFT, MarginLeft, Margin)
2665 HANDLE_INITIAL_COND(CSS_PROP_TEXT_INDENT, TextIndent)
2669 if (primitiveValue && !apply) {
2670 int type = primitiveValue->primitiveType();
2671 if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
2672 // Handle our quirky margin units if we have them.
2673 l = Length(primitiveValue->computeLengthIntForLength(style), Fixed,
2674 primitiveValue->isQuirkValue());
2675 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
2676 l = Length(primitiveValue->getDoubleValue(), Percent);
2679 if (id == CSS_PROP_PADDING_LEFT || id == CSS_PROP_PADDING_RIGHT ||
2680 id == CSS_PROP_PADDING_TOP || id == CSS_PROP_PADDING_BOTTOM)
2681 // Padding can't be negative
2682 apply = !((l.isFixed() || l.isPercent()) && l.calcValue(100) < 0);
2688 case CSS_PROP_MAX_WIDTH:
2689 style->setMaxWidth(l); break;
2690 case CSS_PROP_BOTTOM:
2691 style->setBottom(l); break;
2693 style->setTop(l); break;
2695 style->setLeft(l); break;
2696 case CSS_PROP_RIGHT:
2697 style->setRight(l); break;
2698 case CSS_PROP_WIDTH:
2699 style->setWidth(l); break;
2700 case CSS_PROP_MIN_WIDTH:
2701 style->setMinWidth(l); break;
2702 case CSS_PROP_PADDING_TOP:
2703 style->setPaddingTop(l); break;
2704 case CSS_PROP_PADDING_RIGHT:
2705 style->setPaddingRight(l); break;
2706 case CSS_PROP_PADDING_BOTTOM:
2707 style->setPaddingBottom(l); break;
2708 case CSS_PROP_PADDING_LEFT:
2709 style->setPaddingLeft(l); break;
2710 case CSS_PROP_MARGIN_TOP:
2711 style->setMarginTop(l); break;
2712 case CSS_PROP_MARGIN_RIGHT:
2713 style->setMarginRight(l); break;
2714 case CSS_PROP_MARGIN_BOTTOM:
2715 style->setMarginBottom(l); break;
2716 case CSS_PROP_MARGIN_LEFT:
2717 style->setMarginLeft(l); break;
2718 case CSS_PROP_TEXT_INDENT:
2719 style->setTextIndent(l); break;
2725 case CSS_PROP_MAX_HEIGHT:
2726 if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_NONE) {
2727 l = Length(undefinedLength, Fixed);
2730 case CSS_PROP_HEIGHT:
2731 case CSS_PROP_MIN_HEIGHT:
2732 if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_INTRINSIC) {
2733 l = Length(Intrinsic);
2735 } else if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_MIN_INTRINSIC) {
2736 l = Length(MinIntrinsic);
2738 } else if (id != CSS_PROP_MAX_HEIGHT && primitiveValue && primitiveValue->getIdent() == CSS_VAL_AUTO)
2741 HANDLE_INHERIT_COND(CSS_PROP_MAX_HEIGHT, maxHeight, MaxHeight)
2742 HANDLE_INHERIT_COND(CSS_PROP_HEIGHT, height, Height)
2743 HANDLE_INHERIT_COND(CSS_PROP_MIN_HEIGHT, minHeight, MinHeight)
2747 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MAX_HEIGHT, MaxHeight, MaxSize)
2748 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_HEIGHT, Height, Size)
2749 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MIN_HEIGHT, MinHeight, MinSize)
2753 if (primitiveValue && !apply) {
2754 unsigned short type = primitiveValue->primitiveType();
2755 if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
2756 l = Length(primitiveValue->computeLengthIntForLength(style), Fixed);
2757 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
2758 l = Length(primitiveValue->getDoubleValue(), Percent);
2765 case CSS_PROP_MAX_HEIGHT:
2766 style->setMaxHeight(l);
2768 case CSS_PROP_HEIGHT:
2769 style->setHeight(l);
2771 case CSS_PROP_MIN_HEIGHT:
2772 style->setMinHeight(l);
2777 case CSS_PROP_VERTICAL_ALIGN:
2778 HANDLE_INHERIT_AND_INITIAL(verticalAlign, VerticalAlign)
2779 if (!primitiveValue)
2781 if (primitiveValue->getIdent()) {
2782 EVerticalAlign align;
2784 switch (primitiveValue->getIdent()) {
2787 case CSS_VAL_BOTTOM:
2788 align = BOTTOM; break;
2789 case CSS_VAL_MIDDLE:
2790 align = MIDDLE; break;
2791 case CSS_VAL_BASELINE:
2792 align = BASELINE; break;
2793 case CSS_VAL_TEXT_BOTTOM:
2794 align = TEXT_BOTTOM; break;
2795 case CSS_VAL_TEXT_TOP:
2796 align = TEXT_TOP; break;
2800 align = SUPER; break;
2801 case CSS_VAL__WEBKIT_BASELINE_MIDDLE:
2802 align = BASELINE_MIDDLE; break;
2806 style->setVerticalAlign(align);
2809 int type = primitiveValue->primitiveType();
2811 if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
2812 l = Length(primitiveValue->computeLengthIntForLength(style), Fixed);
2813 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
2814 l = Length(primitiveValue->getDoubleValue(), Percent);
2816 style->setVerticalAlign(LENGTH);
2817 style->setVerticalAlignLength(l);
2821 case CSS_PROP_FONT_SIZE:
2823 FontDescription fontDescription = style->fontDescription();
2824 fontDescription.setKeywordSize(0);
2825 bool familyIsFixed = fontDescription.genericFamily() == FontDescription::MonospaceFamily;
2829 bool parentIsAbsoluteSize = false;
2831 oldSize = parentStyle->fontDescription().specifiedSize();
2832 parentIsAbsoluteSize = parentStyle->fontDescription().isAbsoluteSize();
2838 fontDescription.setKeywordSize(parentStyle->fontDescription().keywordSize());
2839 } else if (isInitial) {
2840 size = fontSizeForKeyword(CSS_VAL_MEDIUM, style->htmlHacks(), familyIsFixed);
2841 fontDescription.setKeywordSize(CSS_VAL_MEDIUM - CSS_VAL_XX_SMALL + 1);
2842 } else if (primitiveValue->getIdent()) {
2843 // Keywords are being used.
2844 switch (primitiveValue->getIdent()) {
2845 case CSS_VAL_XX_SMALL:
2846 case CSS_VAL_X_SMALL:
2848 case CSS_VAL_MEDIUM:
2850 case CSS_VAL_X_LARGE:
2851 case CSS_VAL_XX_LARGE:
2852 case CSS_VAL__WEBKIT_XXX_LARGE:
2853 size = fontSizeForKeyword(primitiveValue->getIdent(), style->htmlHacks(), familyIsFixed);
2854 fontDescription.setKeywordSize(primitiveValue->getIdent() - CSS_VAL_XX_SMALL + 1);
2856 case CSS_VAL_LARGER:
2857 size = largerFontSize(oldSize, style->htmlHacks());
2859 case CSS_VAL_SMALLER:
2860 size = smallerFontSize(oldSize, style->htmlHacks());
2866 fontDescription.setIsAbsoluteSize(parentIsAbsoluteSize &&
2867 (primitiveValue->getIdent() == CSS_VAL_LARGER ||
2868 primitiveValue->getIdent() == CSS_VAL_SMALLER));
2870 int type = primitiveValue->primitiveType();
2871 fontDescription.setIsAbsoluteSize(parentIsAbsoluteSize ||
2872 (type != CSSPrimitiveValue::CSS_PERCENTAGE &&
2873 type != CSSPrimitiveValue::CSS_EMS &&
2874 type != CSSPrimitiveValue::CSS_EXS));
2875 if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
2876 size = primitiveValue->computeLengthFloat(parentStyle, false);
2877 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
2878 size = (primitiveValue->getFloatValue() * oldSize) / 100.0f;
2886 setFontSize(fontDescription, size);
2887 if (style->setFontDescription(fontDescription))
2892 case CSS_PROP_Z_INDEX: {
2894 if (parentStyle->hasAutoZIndex())
2895 style->setHasAutoZIndex();
2897 style->setZIndex(parentStyle->zIndex());
2899 } else if (isInitial || primitiveValue->getIdent() == CSS_VAL_AUTO) {
2900 style->setHasAutoZIndex();
2904 // FIXME: Should clamp all sorts of other integer properties too.
2905 const double minIntAsDouble = INT_MIN;
2906 const double maxIntAsDouble = INT_MAX;
2907 style->setZIndex(static_cast<int>(max(minIntAsDouble, min(primitiveValue->getDoubleValue(), maxIntAsDouble))));
2910 case CSS_PROP_WIDOWS:
2912 HANDLE_INHERIT_AND_INITIAL(widows, Widows)
2913 if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER)
2915 style->setWidows(primitiveValue->getIntValue());
2919 case CSS_PROP_ORPHANS:
2921 HANDLE_INHERIT_AND_INITIAL(orphans, Orphans)
2922 if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER)
2924 style->setOrphans(primitiveValue->getIntValue());
2928 // length, percent, number
2929 case CSS_PROP_LINE_HEIGHT:
2931 HANDLE_INHERIT_AND_INITIAL(lineHeight, LineHeight)
2932 if (!primitiveValue)
2935 int type = primitiveValue->primitiveType();
2936 if (primitiveValue->getIdent() == CSS_VAL_NORMAL)
2937 lineHeight = Length(-100.0, Percent);
2938 else if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) {
2939 double multiplier = 1.0;
2940 // Scale for the font zoom factor only for types other than "em" and "ex", since those are
2941 // already based on the font size.
2942 if (type != CSSPrimitiveValue::CSS_EMS && type != CSSPrimitiveValue::CSS_EXS && style->textSizeAdjust() && m_document->frame()) {
2943 multiplier = m_document->frame()->zoomFactor() / 100.0;
2945 lineHeight = Length(primitiveValue->computeLengthIntForLength(style, multiplier), Fixed);
2946 } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
2947 lineHeight = Length((style->fontSize() * primitiveValue->getIntValue()) / 100, Fixed);
2948 else if (type == CSSPrimitiveValue::CSS_NUMBER)
2949 lineHeight = Length(primitiveValue->getDoubleValue() * 100.0, Percent);
2952 style->setLineHeight(lineHeight);
2957 case CSS_PROP_TEXT_ALIGN:
2959 HANDLE_INHERIT_AND_INITIAL(textAlign, TextAlign)
2960 if (!primitiveValue)
2962 int id = primitiveValue->getIdent();
2963 if (id == CSS_VAL_START)
2964 style->setTextAlign(style->direction() == LTR ? LEFT : RIGHT);
2965 else if (id == CSS_VAL_END)
2966 style->setTextAlign(style->direction() == LTR ? RIGHT : LEFT);
2968 style->setTextAlign(*primitiveValue);
2979 bool hasClip = true;
2981 if (parentStyle->hasClip()) {
2982 top = parentStyle->clipTop();
2983 right = parentStyle->clipRight();
2984 bottom = parentStyle->clipBottom();
2985 left = parentStyle->clipLeft();
2989 top = right = bottom = left = Length();
2991 } else if (isInitial) {
2993 top = right = bottom = left = Length();
2994 } else if (!primitiveValue) {
2996 } else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_RECT) {
2997 Rect* rect = primitiveValue->getRectValue();
3000 top = convertToLength(rect->top(), style);
3001 right = convertToLength(rect->right(), style);
3002 bottom = convertToLength(rect->bottom(), style);
3003 left = convertToLength(rect->left(), style);
3005 } else if (primitiveValue->getIdent() != CSS_VAL_AUTO) {
3008 style->setClip(top, right, bottom, left);
3009 style->setHasClip(hasClip);
3016 case CSS_PROP_CONTENT:
3017 // list of string, uri, counter, attr, i
3019 // FIXME: In CSS3, it will be possible to inherit content. In CSS2 it is not. This
3020 // note is a reminder that eventually "inherit" needs to be supported.
3023 style->clearContent();
3027 if (!value->isValueList())
3030 CSSValueList* list = static_cast<CSSValueList*>(value);
3031 int len = list->length();
3033 bool didSet = false;
3034 for (int i = 0; i < len; i++) {
3035 CSSValue* item = list->item(i);
3036 if (!item->isPrimitiveValue())
3039 CSSPrimitiveValue* val = static_cast<CSSPrimitiveValue*>(item);
3040 switch (val->primitiveType()) {
3041 case CSSPrimitiveValue::CSS_STRING:
3042 style->setContent(val->getStringValue().impl(), didSet);
3045 case CSSPrimitiveValue::CSS_ATTR: {
3046 // FIXME: Can a namespace be specified for an attr(foo)?
3047 if (style->styleType() == RenderStyle::NOPSEUDO)
3050 parentStyle->setUnique();
3051 QualifiedName attr(nullAtom, val->getStringValue().impl(), nullAtom);
3052 style->setContent(element->getAttribute(attr).impl(), didSet);
3054 // register the fact that the attribute value affects the style
3055 m_selectorAttrs.add(attr.localName().impl());
3058 case CSSPrimitiveValue::CSS_URI: {
3059 CSSImageValue *image = static_cast<CSSImageValue*>(val);
3060 style->setContent(image->image(element->document()->docLoader()), didSet);
3064 case CSSPrimitiveValue::CSS_COUNTER: {
3065 Counter* counterValue = val->getCounterValue();
3066 CounterContent* counter = new CounterContent(counterValue->identifier(),
3067 (EListStyleType)counterValue->listStyleNumber(), counterValue->separator());
3068 style->setContent(counter, didSet);
3074 style->clearContent();
3078 case CSS_PROP_COUNTER_INCREMENT:
3079 applyCounterList(style, value->isValueList() ? static_cast<CSSValueList*>(value) : 0, false);
3081 case CSS_PROP_COUNTER_RESET:
3082 applyCounterList(style, value->isValueList() ? static_cast<CSSValueList*>(value) : 0, true);
3085 case CSS_PROP_FONT_FAMILY: {
3086 // list of strings and ids
3088 FontDescription parentFontDescription = parentStyle->fontDescription();
3089 FontDescription fontDescription = style->fontDescription();
3090 fontDescription.setGenericFamily(parentFontDescription.genericFamily());
3091 fontDescription.setFamily(parentFontDescription.firstFamily());
3092 if (style->setFontDescription(fontDescription))
3096 else if (isInitial) {
3097 FontDescription initialDesc = FontDescription();
3098 FontDescription fontDescription = style->fontDescription();
3099 // We need to adjust the size to account for the generic family change from monospace
3100 // to non-monospace.
3101 if (fontDescription.keywordSize() && fontDescription.genericFamily() == FontDescription::MonospaceFamily)
3102 setFontSize(fontDescription, fontSizeForKeyword(CSS_VAL_XX_SMALL + fontDescription.keywordSize() - 1, style->htmlHacks(), false));
3103 fontDescription.setGenericFamily(initialDesc.genericFamily());
3104 fontDescription.setFamily(initialDesc.firstFamily());
3105 if (style->setFontDescription(fontDescription))
3110 if (!value->isValueList()) return;
3111 FontDescription fontDescription = style->fontDescription();
3112 CSSValueList *list = static_cast<CSSValueList*>(value);
3113 int len = list->length();
3114 FontFamily& firstFamily = fontDescription.firstFamily();
3115 FontFamily *currFamily = 0;
3117 // Before mapping in a new font-family property, we should reset the generic family.
3118 bool oldFamilyIsMonospace = fontDescription.genericFamily() == FontDescription::MonospaceFamily;
3119 fontDescription.setGenericFamily(FontDescription::NoFamily);
3121 for (int i = 0; i < len; i++) {
3122 CSSValue *item = list->item(i);
3123 if (!item->isPrimitiveValue()) continue;
3124 CSSPrimitiveValue *val = static_cast<CSSPrimitiveValue*>(item);
3126 Settings* settings = m_document->settings();
3127 if (val->primitiveType() == CSSPrimitiveValue::CSS_STRING)
3128 face = static_cast<FontFamilyValue*>(val)->fontName();
3129 else if (val->primitiveType() == CSSPrimitiveValue::CSS_IDENT && settings) {
3130 switch (val->getIdent()) {
3131 case CSS_VAL__WEBKIT_BODY:
3132 face = settings->standardFontFamily();
3135 face = m_fontSelector ? "-webkit-serif" : settings->serifFontFamily();
3136 fontDescription.setGenericFamily(FontDescription::SerifFamily);
3138 case CSS_VAL_SANS_SERIF:
3139 face = m_fontSelector ? "-webkit-sans-serif" : settings->sansSerifFontFamily();
3140 fontDescription.setGenericFamily(FontDescription::SansSerifFamily);
3142 case CSS_VAL_CURSIVE:
3143 face = m_fontSelector ? "-webkit-cursive" : settings->cursiveFontFamily();
3144 fontDescription.setGenericFamily(FontDescription::CursiveFamily);
3146 case CSS_VAL_FANTASY:
3147 face = m_fontSelector ? "-webkit-fantasy" : settings->fantasyFontFamily();
3148 fontDescription.setGenericFamily(FontDescription::FantasyFamily);
3150 case CSS_VAL_MONOSPACE:
3151 face = m_fontSelector ? "-webkit-monospace" : settings->fixedFontFamily();
3152 fontDescription.setGenericFamily(FontDescription::MonospaceFamily);
3157 if (!face.isEmpty()) {
3159 // Filling in the first family.
3160 firstFamily.setFamily(face);
3161 currFamily = &firstFamily;
3164 FontFamily *newFamily = new FontFamily;
3165 newFamily->setFamily(face);
3166 currFamily->appendFamily(newFamily);
3167 currFamily = newFamily;
3170 if (fontDescription.keywordSize() && (fontDescription.genericFamily() == FontDescription::MonospaceFamily) != oldFamilyIsMonospace)
3171 setFontSize(fontDescription, fontSizeForKeyword(CSS_VAL_XX_SMALL + fontDescription.keywordSize() - 1, style->htmlHacks(), !oldFamilyIsMonospace));
3173 if (style->setFontDescription(fontDescription))
3179 case CSS_PROP_TEXT_DECORATION: {
3181 HANDLE_INHERIT_AND_INITIAL(textDecoration, TextDecoration)
3182 int t = RenderStyle::initialTextDecoration();
3183 if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_NONE) {
3186 if (!value->isValueList()) return;
3187 CSSValueList *list = static_cast<CSSValueList*>(value);
3188 int len = list->length();
3189 for (int i = 0; i < len; i++)
3191 CSSValue *item = list->item(i);
3192 if (!item->isPrimitiveValue()) continue;
3193 primitiveValue = static_cast<CSSPrimitiveValue*>(item);
3194 switch (primitiveValue->getIdent()) {
3197 case CSS_VAL_UNDERLINE:
3198 t |= UNDERLINE; break;
3199 case CSS_VAL_OVERLINE:
3200 t |= OVERLINE; break;
3201 case CSS_VAL_LINE_THROUGH:
3202 t |= LINE_THROUGH; break;
3211 style->setTextDecoration(t);
3215 // shorthand properties
3216 case CSS_PROP_BACKGROUND:
3218 style->clearBackgroundLayers();
3219 style->setBackgroundColor(Color());
3222 else if (isInherit) {
3223 style->inheritBackgroundLayers(*parentStyle->backgroundLayers());
3224 style->setBackgroundColor(parentStyle->backgroundColor());
3227 case CSS_PROP_BORDER:
3228 case CSS_PROP_BORDER_STYLE:
3229 case CSS_PROP_BORDER_WIDTH:
3230 case CSS_PROP_BORDER_COLOR:
3231 if (id == CSS_PROP_BORDER || id == CSS_PROP_BORDER_COLOR)
3234 style->setBorderTopColor(parentStyle->borderTopColor());
3235 style->setBorderBottomColor(parentStyle->borderBottomColor());
3236 style->setBorderLeftColor(parentStyle->borderLeftColor());
3237 style->setBorderRightColor(parentStyle->borderRightColor());
3239 else if (isInitial) {
3240 style->setBorderTopColor(Color()); // Reset to invalid color so currentColor is used instead.
3241 style->setBorderBottomColor(Color());
3242 style->setBorderLeftColor(Color());
3243 style->setBorderRightColor(Color());
3246 if (id == CSS_PROP_BORDER || id == CSS_PROP_BORDER_STYLE)
3249 style->setBorderTopStyle(parentStyle->borderTopStyle());
3250 style->setBorderBottomStyle(parentStyle->borderBottomStyle());
3251 style->setBorderLeftStyle(parentStyle->borderLeftStyle());
3252 style->setBorderRightStyle(parentStyle->borderRightStyle());
3254 else if (isInitial) {
3255 style->setBorderTopStyle(RenderStyle::initialBorderStyle());
3256 style->setBorderBottomStyle(RenderStyle::initialBorderStyle());
3257 style->setBorderLeftStyle(RenderStyle::initialBorderStyle());
3258 style->setBorderRightStyle(RenderStyle::initialBorderStyle());
3261 if (id == CSS_PROP_BORDER || id == CSS_PROP_BORDER_WIDTH)
3264 style->setBorderTopWidth(parentStyle->borderTopWidth());
3265 style->setBorderBottomWidth(parentStyle->borderBottomWidth());
3266 style->setBorderLeftWidth(parentStyle->borderLeftWidth());
3267 style->setBorderRightWidth(parentStyle->borderRightWidth());
3269 else if (isInitial) {
3270 style->setBorderTopWidth(RenderStyle::initialBorderWidth());
3271 style->setBorderBottomWidth(RenderStyle::initialBorderWidth());
3272 style->setBorderLeftWidth(RenderStyle::initialBorderWidth());
3273 style->setBorderRightWidth(RenderStyle::initialBorderWidth());
3277 case CSS_PROP_BORDER_TOP:
3279 style->setBorderTopColor(parentStyle->borderTopColor());
3280 style->setBorderTopStyle(parentStyle->borderTopStyle());
3281 style->setBorderTopWidth(parentStyle->borderTopWidth());
3284 style->resetBorderTop();
3286 case CSS_PROP_BORDER_RIGHT: