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)
250 m_fontSelector = new CSSFontSelector(doc);
252 m_matchAuthorAndUserStyles = matchAuthorAndUserStyles;
254 strictParsing = _strictParsing;
260 // construct document root element default style. this is needed
261 // to evaluate media queries that contain relative constraints, like "screen and (max-width: 10em)"
262 // This is here instead of constructor, because when constructor is run,
263 // document doesn't have documentElement
264 // NOTE: this assumes that element that gets passed to styleForElement -call
265 // is always from the document that owns the style selector
266 FrameView* view = m_document->view();
268 m_medium = new MediaQueryEvaluator(view->mediaType());
270 m_medium = new MediaQueryEvaluator("all");
272 Element* root = doc->documentElement();
275 m_rootDefaultStyle = styleForElement(root, 0, false, true); // dont ref, because the RenderStyle is allocated from global heap
277 if (m_rootDefaultStyle && view) {
279 m_medium = new MediaQueryEvaluator(view->mediaType(), view->frame()->page(), m_rootDefaultStyle);
282 // FIXME: This sucks! The user sheet is reparsed every time!
283 if (!userStyleSheet.isEmpty()) {
284 m_userSheet = new CSSStyleSheet(doc);
285 m_userSheet->parseString(userStyleSheet, strictParsing);
287 m_userStyle = new CSSRuleSet();
288 m_userStyle->addRulesFromSheet(m_userSheet.get(), *m_medium, this);
291 // add stylesheets from document
292 m_authorStyle = new CSSRuleSet();
294 // Add rules from elments like SVG's <font-face>
295 if (mappedElementSheet)
296 m_authorStyle->addRulesFromSheet(mappedElementSheet, *m_medium, this);
298 DeprecatedPtrListIterator<StyleSheet> it(styleSheets->styleSheets);
299 for (; it.current(); ++it)
300 if (it.current()->isCSSStyleSheet() && !it.current()->disabled())
301 m_authorStyle->addRulesFromSheet(static_cast<CSSStyleSheet*>(it.current()), *m_medium, this);
304 void CSSStyleSelector::init()
307 m_matchedDecls.clear();
309 m_collectRulesOnly = false;
310 m_rootDefaultStyle = 0;
314 void CSSStyleSelector::setEncodedURL(const KURL& url)
318 u.setQuery(DeprecatedString::null);
319 u.setRef(DeprecatedString::null);
320 encodedurl.file = u.deprecatedString();
321 int pos = encodedurl.file.findRev('/');
322 encodedurl.path = encodedurl.file;
324 encodedurl.path.truncate(pos);
325 encodedurl.path += '/';
327 u.setPath(DeprecatedString::null);
328 encodedurl.host = u.deprecatedString();
331 CSSStyleSelector::~CSSStyleSelector()
334 ::delete m_rootDefaultStyle;
336 delete m_authorStyle;
340 static CSSStyleSheet* parseUASheet(const char* characters, unsigned size)
342 CSSStyleSheet* const parent = 0;
343 CSSStyleSheet* sheet = new CSSStyleSheet(parent);
344 sheet->ref(); // leak the sheet on purpose since it will be stored in a global variable
345 sheet->parseString(String(characters, size));
349 template<typename T> CSSStyleSheet* parseUASheet(const T& array)
351 return parseUASheet(array, sizeof(array));
354 void CSSStyleSelector::loadDefaultStyle()
359 defaultStyle = new CSSRuleSet;
360 defaultPrintStyle = new CSSRuleSet;
361 defaultQuirksStyle = new CSSRuleSet;
362 defaultViewSourceStyle = new CSSRuleSet;
364 // Strict-mode rules.
365 defaultSheet = parseUASheet(html4UserAgentStyleSheet);
366 defaultStyle->addRulesFromSheet(defaultSheet, screenEval());
367 defaultPrintStyle->addRulesFromSheet(defaultSheet, printEval());
369 // Quirks-mode rules.
370 quirksSheet = parseUASheet(quirksUserAgentStyleSheet);
371 defaultQuirksStyle->addRulesFromSheet(quirksSheet, screenEval());
373 // View source rules.
374 viewSourceSheet = parseUASheet(sourceUserAgentStyleSheet);
375 defaultViewSourceStyle->addRulesFromSheet(viewSourceSheet, screenEval());
378 void CSSStyleSelector::matchRules(CSSRuleSet* rules, int& firstRuleIndex, int& lastRuleIndex)
380 m_matchedRules.clear();
382 if (!rules || !element)
385 // We need to collect the rules for id, class, tag, and everything else into a buffer and
386 // then sort the buffer.
387 if (element->hasID())
388 matchRulesForList(rules->getIDRules(element->getIDAttribute().impl()), firstRuleIndex, lastRuleIndex);
389 if (element->hasClass()) {
390 const ClassNames& classNames = *element->getClassNames();
391 for (size_t i = 0; i < classNames.size(); ++i)
392 matchRulesForList(rules->getClassRules(classNames[i].impl()), firstRuleIndex, lastRuleIndex);
394 matchRulesForList(rules->getTagRules(element->localName().impl()), firstRuleIndex, lastRuleIndex);
395 matchRulesForList(rules->getUniversalRules(), firstRuleIndex, lastRuleIndex);
397 // If we didn't match any rules, we're done.
398 if (m_matchedRules.isEmpty())
401 // Sort the set of matched rules.
402 sortMatchedRules(0, m_matchedRules.size());
404 // Now transfer the set of matched rules over to our list of decls.
405 if (!m_collectRulesOnly) {
406 for (unsigned i = 0; i < m_matchedRules.size(); i++)
407 addMatchedDeclaration(m_matchedRules[i]->rule()->declaration());
409 for (unsigned i = 0; i < m_matchedRules.size(); i++) {
411 m_ruleList = new CSSRuleList();
412 m_ruleList->append(m_matchedRules[i]->rule());
417 void CSSStyleSelector::matchRulesForList(CSSRuleDataList* rules, int& firstRuleIndex, int& lastRuleIndex)
422 for (CSSRuleData* d = rules->first(); d; d = d->next()) {
423 CSSStyleRule* rule = d->rule();
424 const AtomicString& localName = element->localName();
425 const AtomicString& selectorLocalName = d->selector()->m_tag.localName();
426 if ((localName == selectorLocalName || selectorLocalName == starAtom) && checkSelector(d->selector())) {
427 // If the rule has no properties to apply, then ignore it.
428 CSSMutableStyleDeclaration* decl = rule->declaration();
429 if (!decl || !decl->length())
432 // If we're matching normal rules, set a pseudo bit if
433 // we really just matched a pseudo-element.
434 if (dynamicPseudo != RenderStyle::NOPSEUDO && pseudoStyle == RenderStyle::NOPSEUDO) {
435 if (m_collectRulesOnly)
437 if (dynamicPseudo < RenderStyle::FIRST_INTERNAL_PSEUDOID)
438 style->setHasPseudoStyle(dynamicPseudo);
440 // Update our first/last rule indices in the matched rules array.
441 lastRuleIndex = m_matchedDecls.size() + m_matchedRules.size();
442 if (firstRuleIndex == -1)
443 firstRuleIndex = lastRuleIndex;
445 // Add this rule to our list of matched rules.
452 bool operator >(CSSRuleData& r1, CSSRuleData& r2)
454 int spec1 = r1.selector()->specificity();
455 int spec2 = r2.selector()->specificity();
456 return (spec1 == spec2) ? r1.position() > r2.position() : spec1 > spec2;
458 bool operator <=(CSSRuleData& r1, CSSRuleData& r2)
463 void CSSStyleSelector::sortMatchedRules(unsigned start, unsigned end)
465 if (start >= end || (end - start == 1))
466 return; // Sanity check.
468 if (end - start <= 6) {
469 // Apply a bubble sort for smaller lists.
470 for (unsigned i = end - 1; i > start; i--) {
472 for (unsigned j = start; j < i; j++) {
473 CSSRuleData* elt = m_matchedRules[j];
474 CSSRuleData* elt2 = m_matchedRules[j + 1];
477 m_matchedRules[j] = elt2;
478 m_matchedRules[j + 1] = elt;
487 // Peform a merge sort for larger lists.
488 unsigned mid = (start + end) / 2;
489 sortMatchedRules(start, mid);
490 sortMatchedRules(mid, end);
492 CSSRuleData* elt = m_matchedRules[mid - 1];
493 CSSRuleData* elt2 = m_matchedRules[mid];
495 // Handle the fast common case (of equal specificity). The list may already
496 // be completely sorted.
500 // We have to merge sort. Ensure our merge buffer is big enough to hold
502 Vector<CSSRuleData*> rulesMergeBuffer;
503 rulesMergeBuffer.reserveCapacity(end - start);
508 elt = m_matchedRules[i1];
509 elt2 = m_matchedRules[i2];
511 while (i1 < mid || i2 < end) {
512 if (i1 < mid && (i2 == end || *elt <= *elt2)) {
513 rulesMergeBuffer.append(elt);
515 elt = m_matchedRules[i1];
517 rulesMergeBuffer.append(elt2);
519 elt2 = m_matchedRules[i2];
523 for (unsigned i = start; i < end; i++)
524 m_matchedRules[i] = rulesMergeBuffer[i - start];
527 void CSSStyleSelector::initElementAndPseudoState(Element* e)
530 if (element && element->isStyledElement())
531 styledElement = static_cast<StyledElement*>(element);
534 currentEncodedURL = &encodedurl;
535 pseudoState = PseudoUnknown;
538 void CSSStyleSelector::initForStyleResolve(Element* e, RenderStyle* defaultParent)
540 // set some variables we will need
541 pseudoStyle = RenderStyle::NOPSEUDO;
543 parentNode = e->parentNode();
546 if (!parentNode && e->isSVGElement() && e->isShadowNode())
547 parentNode = e->shadowParentNode();
551 parentStyle = defaultParent;
553 parentStyle = parentNode ? parentNode->renderStyle() : 0;
554 isXMLDoc = !element->document()->isHTMLDocument();
558 m_matchedDecls.clear();
565 static int findHash(const DeprecatedString& string)
567 const ::UChar* ptr = reinterpret_cast<const ::UChar*>(string.unicode());
568 unsigned length = string.length();
569 for (unsigned i = 0; i < length; ++i) {
576 static inline int findSlashDotDotSlash(const DeprecatedString& string)
578 const ::UChar* ptr = reinterpret_cast<const ::UChar*>(string.unicode());
579 unsigned length = string.length();
580 unsigned loopLimit = length < 4 ? 0 : length - 3;
581 for (unsigned i = 0; i < loopLimit; ++i) {
582 if (ptr[i] == '/' && ptr[i + 1] == '.' && ptr[i + 2] == '.' && ptr[i + 3] == '/')
588 static inline int findSlashSlash(const DeprecatedString& string, int position)
590 const ::UChar* ptr = reinterpret_cast<const ::UChar*>(string.unicode());
591 unsigned length = string.length();
592 unsigned loopLimit = length < 2 ? 0 : length - 1;
593 for (unsigned i = position; i < loopLimit; ++i) {
594 if (ptr[i] == '/' && ptr[i + 1] == '/')
600 static inline int findSlashDotSlash(const DeprecatedString& string)
602 const ::UChar* ptr = reinterpret_cast<const ::UChar*>(string.unicode());
603 unsigned length = string.length();
604 unsigned loopLimit = length < 3 ? 0 : length - 2;
605 for (unsigned i = 0; i < loopLimit; ++i) {
606 if (ptr[i] == '/' && ptr[i + 1] == '.' && ptr[i + 2] == '/')
612 static void cleanpath(DeprecatedString& path)
616 while ((pos = findSlashDotDotSlash(path)) != -1) {
619 prev = path.findRev("/", pos - 1);
620 // don't remove the host, i.e. http://foo.org/../foo.html
621 if (prev < 0 || (prev > 3 && path.findRev("://", prev - 1) == prev - 2))
624 // matching directory found ?
625 path.remove(prev, pos - prev + 3);
628 // Don't remove "//" from an anchor identifier. -rjw
629 // Set refPos to -2 to mean "I haven't looked for the anchor yet".
630 // We don't want to waste a function call on the search for the the anchor
631 // in the vast majority of cases where there is no "//" in the path.
634 while ((pos = findSlashSlash(path, pos)) != -1) {
636 refPos = findHash(path);
637 if (refPos > 0 && pos >= refPos)
640 if (pos == 0 || path[pos - 1] != ':')
646 // FIXME: We don't want to remove "/./" from an anchor identifier either.
647 while ((pos = findSlashDotSlash(path)) != -1)
651 static inline bool containsColonSlashSlash(const UChar* characters, unsigned length)
653 unsigned loopLimit = length < 3 ? 0 : length - 2;
654 for (unsigned i = 0; i < loopLimit; ++i)
655 if (characters[i] == ':' && characters[i + 1] == '/' && characters[i + 2] == '/')
660 static void checkPseudoState(Element *e, bool checkVisited = true)
663 pseudoState = PseudoNone;
667 const AtomicString* attr;
668 if (e->isHTMLElement())
669 attr = &e->getAttribute(hrefAttr);
671 else if (e->isSVGElement())
672 attr = &e->getAttribute(XLinkNames::hrefAttr);
675 pseudoState = PseudoNone;
679 if (attr->isNull()) {
680 pseudoState = PseudoNone;
685 pseudoState = PseudoAnyLink;
689 const UChar* characters = attr->characters();
690 unsigned length = attr->length();
692 if (containsColonSlashSlash(characters, length)) {
693 // FIXME: Strange to not clean the path just beacause it has "://" in it.
694 pseudoState = historyContains(characters, length) ? PseudoVisited : PseudoLink;
698 DeprecatedConstString cu(reinterpret_cast<const DeprecatedChar*>(characters), length);
699 DeprecatedString u = cu.string();
700 if (length && characters[0] == '/')
701 u.prepend(currentEncodedURL->host);
702 else if (length && characters[0] == '#')
703 u.prepend(currentEncodedURL->file);
705 u.prepend(currentEncodedURL->path);
707 pseudoState = historyContains(reinterpret_cast<const UChar*>(u.unicode()), u.length())
708 ? PseudoVisited : PseudoLink;
711 #ifdef STYLE_SHARING_STATS
712 static int fraction = 0;
713 static int total = 0;
716 static const unsigned cStyleSearchThreshold = 10;
718 Node* CSSStyleSelector::locateCousinList(Element* parent, unsigned depth)
720 if (parent && parent->isStyledElement()) {
721 StyledElement* p = static_cast<StyledElement*>(parent);
722 if (!p->inlineStyleDecl() && !p->hasID()) {
723 Node* r = p->previousSibling();
724 unsigned subcount = 0;
725 RenderStyle* st = p->renderStyle();
727 if (r->renderStyle() == st)
728 return r->lastChild();
729 if (subcount++ == cStyleSearchThreshold)
731 r = r->previousSibling();
733 if (!r && depth < cStyleSearchThreshold)
734 r = locateCousinList(static_cast<Element*>(parent->parentNode()), depth + 1);
736 if (r->renderStyle() == st)
737 return r->lastChild();
738 if (subcount++ == cStyleSearchThreshold)
740 r = r->previousSibling();
747 bool CSSStyleSelector::canShareStyleWithElement(Node* n)
749 if (n->isStyledElement()) {
750 StyledElement* s = static_cast<StyledElement*>(n);
751 RenderStyle* style = s->renderStyle();
752 if (style && !style->unique() &&
753 (s->tagQName() == element->tagQName()) && !s->hasID() &&
754 (s->hasClass() == element->hasClass()) && !s->inlineStyleDecl() &&
755 (s->hasMappedAttributes() == styledElement->hasMappedAttributes()) &&
756 (s->isLink() == element->isLink()) &&
757 !style->affectedByAttributeSelectors() &&
758 (s->hovered() == element->hovered()) &&
759 (s->active() == element->active()) &&
760 (s->focused() == element->focused()) &&
761 (s != s->document()->getCSSTarget() && element != element->document()->getCSSTarget()) &&
762 (s->getAttribute(typeAttr) == element->getAttribute(typeAttr)) &&
763 (s->getAttribute(readonlyAttr) == element->getAttribute(readonlyAttr))) {
764 bool isControl = s->isControl();
765 if (isControl != element->isControl())
767 if (isControl && (s->isEnabled() != element->isEnabled()) ||
768 (s->isIndeterminate() != element->isIndeterminate()) ||
769 (s->isChecked() != element->isChecked()))
772 if (style->transitions())
775 bool classesMatch = true;
777 const AtomicString& class1 = element->getAttribute(classAttr);
778 const AtomicString& class2 = s->getAttribute(classAttr);
779 classesMatch = (class1 == class2);
783 bool mappedAttrsMatch = true;
784 if (s->hasMappedAttributes())
785 mappedAttrsMatch = s->mappedAttributes()->mapsEquivalent(styledElement->mappedAttributes());
786 if (mappedAttrsMatch) {
787 bool linksMatch = true;
789 // We need to check to see if the visited state matches.
790 Color linkColor = element->document()->linkColor();
791 Color visitedColor = element->document()->visitedLinkColor();
792 if (pseudoState == PseudoUnknown)
793 checkPseudoState(element, style->pseudoState() != PseudoAnyLink || linkColor != visitedColor);
794 linksMatch = (pseudoState == style->pseudoState());
806 RenderStyle* CSSStyleSelector::locateSharedStyle()
808 if (styledElement && !styledElement->inlineStyleDecl() && !styledElement->hasID() &&
809 !styledElement->document()->usesSiblingRules()) {
810 // Check previous siblings.
813 for (n = element->previousSibling(); n && !n->isElementNode(); n = n->previousSibling()) { }
815 if (canShareStyleWithElement(n))
816 return n->renderStyle();
817 if (count++ == cStyleSearchThreshold)
819 for (n = n->previousSibling(); n && !n->isElementNode(); n = n->previousSibling()) { }
822 n = locateCousinList(static_cast<Element*>(element->parentNode()));
824 if (canShareStyleWithElement(n))
825 return n->renderStyle();
826 if (count++ == cStyleSearchThreshold)
828 for (n = n->previousSibling(); n && !n->isElementNode(); n = n->previousSibling()) { }
834 void CSSStyleSelector::matchUARules(int& firstUARule, int& lastUARule)
836 // First we match rules from the user agent sheet.
837 CSSRuleSet* userAgentStyleSheet = m_medium->mediaTypeMatchSpecific("print")
838 ? defaultPrintStyle : defaultStyle;
839 matchRules(userAgentStyleSheet, firstUARule, lastUARule);
841 // In quirks mode, we match rules from the quirks user agent sheet.
843 matchRules(defaultQuirksStyle, firstUARule, lastUARule);
845 // If we're in view source mode, then we match rules from the view source style sheet.
846 if (m_document->frame() && m_document->frame()->inViewSourceMode())
847 matchRules(defaultViewSourceStyle, firstUARule, lastUARule);
850 // If resolveForRootDefault is true, style based on user agent style sheet only. This is used in media queries, where
851 // relative units are interpreted according to document root element style, styled only with UA stylesheet
853 RenderStyle* CSSStyleSelector::styleForElement(Element* e, RenderStyle* defaultParent, bool allowSharing, bool resolveForRootDefault)
855 // Once an element has a renderer, we don't try to destroy it, since otherwise the renderer
856 // will vanish if a style recalc happens during loading.
857 if (allowSharing && !e->document()->haveStylesheetsLoaded() && !e->renderer()) {
858 if (!styleNotYetAvailable) {
859 styleNotYetAvailable = ::new RenderStyle;
860 styleNotYetAvailable->ref();
861 styleNotYetAvailable->setDisplay(NONE);
862 styleNotYetAvailable->font().update(m_fontSelector);
864 styleNotYetAvailable->ref();
865 e->document()->setHasNodesWithPlaceholderStyle();
866 return styleNotYetAvailable;
869 initElementAndPseudoState(e);
871 style = locateSharedStyle();
872 #ifdef STYLE_SHARING_STATS
873 fraction += style != 0;
875 printf("Sharing %d out of %d\n", fraction, total);
882 initForStyleResolve(e, defaultParent);
884 if (resolveForRootDefault) {
885 style = ::new RenderStyle();
886 // don't ref, because we want to delete this, but we cannot unref it
888 style = new (e->document()->renderArena()) RenderStyle();
892 style->inheritFrom(parentStyle);
897 if (e->isSVGElement() && !svgSheet) {
899 svgSheet = parseUASheet(svgUserAgentStyleSheet);
900 defaultStyle->addRulesFromSheet(svgSheet, screenEval());
901 defaultPrintStyle->addRulesFromSheet(svgSheet, printEval());
905 int firstUARule = -1, lastUARule = -1;
906 int firstUserRule = -1, lastUserRule = -1;
907 int firstAuthorRule = -1, lastAuthorRule = -1;
908 matchUARules(firstUARule, lastUARule);
910 if (!resolveForRootDefault) {
911 // 4. Now we check user sheet rules.
912 if (m_matchAuthorAndUserStyles)
913 matchRules(m_userStyle, firstUserRule, lastUserRule);
915 // 5. Now check author rules, beginning first with presentational attributes
918 // Ask if the HTML element has mapped attributes.
919 if (styledElement->hasMappedAttributes()) {
920 // Walk our attribute list and add in each decl.
921 const NamedMappedAttrMap* map = styledElement->mappedAttributes();
922 for (unsigned i = 0; i < map->length(); i++) {
923 MappedAttribute* attr = map->attributeItem(i);
925 lastAuthorRule = m_matchedDecls.size();
926 if (firstAuthorRule == -1)
927 firstAuthorRule = lastAuthorRule;
928 addMatchedDeclaration(attr->decl());
933 // Now we check additional mapped declarations.
934 // Tables and table cells share an additional mapped rule that must be applied
935 // after all attributes, since their mapped style depends on the values of multiple attributes.
936 CSSMutableStyleDeclaration* attributeDecl = styledElement->additionalAttributeStyleDecl();
938 lastAuthorRule = m_matchedDecls.size();
939 if (firstAuthorRule == -1)
940 firstAuthorRule = lastAuthorRule;
941 addMatchedDeclaration(attributeDecl);
945 // 6. Check the rules in author sheets next.
946 if (m_matchAuthorAndUserStyles)
947 matchRules(m_authorStyle, firstAuthorRule, lastAuthorRule);
949 // 7. Now check our inline style attribute.
950 if (m_matchAuthorAndUserStyles && styledElement) {
951 CSSMutableStyleDeclaration* inlineDecl = styledElement->inlineStyleDecl();
953 lastAuthorRule = m_matchedDecls.size();
954 if (firstAuthorRule == -1)
955 firstAuthorRule = lastAuthorRule;
956 addMatchedDeclaration(inlineDecl);
961 // Now we have all of the matched rules in the appropriate order. Walk the rules and apply
962 // high-priority properties first, i.e., those properties that other properties depend on.
963 // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important
964 // and (4) normal important.
965 m_lineHeightValue = 0;
966 applyDeclarations(true, false, 0, m_matchedDecls.size() - 1);
967 if (!resolveForRootDefault) {
968 applyDeclarations(true, true, firstAuthorRule, lastAuthorRule);
969 applyDeclarations(true, true, firstUserRule, lastUserRule);
971 applyDeclarations(true, true, firstUARule, lastUARule);
973 // If our font got dirtied, go ahead and update it now.
977 // Line-height is set when we are sure we decided on the font-size
978 if (m_lineHeightValue)
979 applyProperty(CSS_PROP_LINE_HEIGHT, m_lineHeightValue);
981 // Now do the normal priority UA properties.
982 applyDeclarations(false, false, firstUARule, lastUARule);
984 // Cache our border and background so that we can examine them later.
985 cacheBorderAndBackground();
987 // Now do the author and user normal priority properties and all the !important properties.
988 if (!resolveForRootDefault) {
989 applyDeclarations(false, false, lastUARule + 1, m_matchedDecls.size() - 1);
990 applyDeclarations(false, true, firstAuthorRule, lastAuthorRule);
991 applyDeclarations(false, true, firstUserRule, lastUserRule);
993 applyDeclarations(false, true, firstUARule, lastUARule);
995 // If our font got dirtied by one of the non-essential font props,
996 // go ahead and update it a second time.
1000 // Clean up our style object's display and text decorations (among other fixups).
1001 adjustRenderStyle(style, e);
1003 // If we are a link, cache the determined pseudo-state.
1005 style->setPseudoState(pseudoState);
1007 // If we have first-letter pseudo style, do not share this style
1008 if (style->hasPseudoStyle(RenderStyle::FIRST_LETTER))
1011 // Now return the style.
1015 RenderStyle* CSSStyleSelector::pseudoStyleForElement(RenderStyle::PseudoId pseudo, Element* e, RenderStyle* parentStyle)
1020 initElementAndPseudoState(e);
1021 initForStyleResolve(e, parentStyle);
1022 pseudoStyle = pseudo;
1024 // Since we don't use pseudo-elements in any of our quirk/print user agent rules, don't waste time walking
1027 // Check UA, user and author rules.
1028 int firstUARule = -1, lastUARule = -1, firstUserRule = -1, lastUserRule = -1, firstAuthorRule = -1, lastAuthorRule = -1;
1029 matchUARules(firstUARule, lastUARule);
1031 if (m_matchAuthorAndUserStyles) {
1032 matchRules(m_userStyle, firstUserRule, lastUserRule);
1033 matchRules(m_authorStyle, firstAuthorRule, lastAuthorRule);
1036 if (m_matchedDecls.isEmpty())
1039 style = new (e->document()->renderArena()) RenderStyle();
1042 style->inheritFrom(parentStyle);
1044 parentStyle = style;
1045 style->noninherited_flags._styleType = pseudoStyle;
1047 m_lineHeightValue = 0;
1048 // High-priority properties.
1049 applyDeclarations(true, false, 0, m_matchedDecls.size() - 1);
1050 applyDeclarations(true, true, firstAuthorRule, lastAuthorRule);
1051 applyDeclarations(true, true, firstUserRule, lastUserRule);
1052 applyDeclarations(true, true, firstUARule, lastUARule);
1054 // If our font got dirtied, go ahead and update it now.
1058 // Line-height is set when we are sure we decided on the font-size
1059 if (m_lineHeightValue)
1060 applyProperty(CSS_PROP_LINE_HEIGHT, m_lineHeightValue);
1062 // Now do the normal priority properties.
1063 applyDeclarations(false, false, firstUARule, lastUARule);
1065 // Cache our border and background so that we can examine them later.
1066 cacheBorderAndBackground();
1068 applyDeclarations(false, false, lastUARule + 1, m_matchedDecls.size() - 1);
1069 applyDeclarations(false, true, firstAuthorRule, lastAuthorRule);
1070 applyDeclarations(false, true, firstUserRule, lastUserRule);
1071 applyDeclarations(false, true, firstUARule, lastUARule);
1073 // If our font got dirtied by one of the non-essential font props,
1074 // go ahead and update it a second time.
1077 // Clean up our style object's display and text decorations (among other fixups).
1078 adjustRenderStyle(style, 0);
1080 // Now return the style.
1084 static void addIntrinsicMargins(RenderStyle* style)
1086 // Intrinsic margin value.
1087 const int intrinsicMargin = 2;
1089 // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed.
1090 // FIXME: Using "quirk" to decide the margin wasn't set is kind of lame.
1091 if (style->width().isIntrinsicOrAuto()) {
1092 if (style->marginLeft().quirk())
1093 style->setMarginLeft(Length(intrinsicMargin, Fixed));
1094 if (style->marginRight().quirk())
1095 style->setMarginRight(Length(intrinsicMargin, Fixed));
1098 if (style->height().isAuto()) {
1099 if (style->marginTop().quirk())
1100 style->setMarginTop(Length(intrinsicMargin, Fixed));
1101 if (style->marginBottom().quirk())
1102 style->setMarginBottom(Length(intrinsicMargin, Fixed));
1106 void CSSStyleSelector::adjustRenderStyle(RenderStyle* style, Element *e)
1108 // Cache our original display.
1109 style->setOriginalDisplay(style->display());
1111 if (style->display() != NONE) {
1112 // If we have a <td> that specifies a float property, in quirks mode we just drop the float
1114 // Sites also commonly use display:inline/block on <td>s and <table>s. In quirks mode we force
1115 // these tags to retain their display types.
1116 if (!strictParsing && e) {
1117 if (e->hasTagName(tdTag)) {
1118 style->setDisplay(TABLE_CELL);
1119 style->setFloating(FNONE);
1121 else if (e->hasTagName(tableTag))
1122 style->setDisplay(style->isDisplayInlineType() ? INLINE_TABLE : TABLE);
1125 // Tables never support the -webkit-* values for text-align and will reset back to the default.
1126 if (e && e->hasTagName(tableTag) && (style->textAlign() == WEBKIT_LEFT || style->textAlign() == WEBKIT_CENTER || style->textAlign() == WEBKIT_RIGHT))
1127 style->setTextAlign(TAAUTO);
1129 // Frames and framesets never honor position:relative or position:absolute. This is necessary to
1130 // fix a crash where a site tries to position these objects. They also never honor display.
1131 if (e && (e->hasTagName(frameTag) || e->hasTagName(framesetTag))) {
1132 style->setPosition(StaticPosition);
1133 style->setDisplay(BLOCK);
1136 // Table headers with a text-align of auto will change the text-align to center.
1137 if (e && e->hasTagName(thTag) && style->textAlign() == TAAUTO)
1138 style->setTextAlign(CENTER);
1140 // Mutate the display to BLOCK or TABLE for certain cases, e.g., if someone attempts to
1141 // position or float an inline, compact, or run-in. Cache the original display, since it
1142 // may be needed for positioned elements that have to compute their static normal flow
1143 // positions. We also force inline-level roots to be block-level.
1144 if (style->display() != BLOCK && style->display() != TABLE && style->display() != BOX &&
1145 (style->position() == AbsolutePosition || style->position() == FixedPosition || style->floating() != FNONE ||
1146 (e && e->document()->documentElement() == e))) {
1147 if (style->display() == INLINE_TABLE)
1148 style->setDisplay(TABLE);
1149 else if (style->display() == INLINE_BOX)
1150 style->setDisplay(BOX);
1151 else if (style->display() == LIST_ITEM) {
1152 // It is a WinIE bug that floated list items lose their bullets, so we'll emulate the quirk,
1153 // but only in quirks mode.
1154 if (!strictParsing && style->floating() != FNONE)
1155 style->setDisplay(BLOCK);
1158 style->setDisplay(BLOCK);
1161 // After performing the display mutation, check table rows. We do not honor position:relative on
1162 // table rows or cells. This has been established in CSS2.1 (and caused a crash in containingBlock()
1164 if ((style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_ROW_GROUP ||
1165 style->display() == TABLE_FOOTER_GROUP || style->display() == TABLE_ROW || style->display() == TABLE_CELL) &&
1166 style->position() == RelativePosition)
1167 style->setPosition(StaticPosition);
1170 // Make sure our z-index value is only applied if the object is positioned,
1171 // relatively positioned, transparent, or has a transform.
1172 if (style->position() == StaticPosition && style->opacity() == 1.0f && !style->hasTransform())
1173 style->setHasAutoZIndex();
1175 // Auto z-index becomes 0 for the root element and transparent objects. This prevents
1176 // cases where objects that should be blended as a single unit end up with a non-transparent
1177 // object wedged in between them. Auto z-index also becomes 0 for objects that specify transforms.
1178 if (style->hasAutoZIndex() && ((e && e->document()->documentElement() == e) || style->opacity() < 1.0f || style->hasTransform()))
1179 style->setZIndex(0);
1181 // Button, legend, input, select and textarea all consider width values of 'auto' to be 'intrinsic'.
1182 // This will be important when we use block flows for all form controls.
1183 if (e && (e->hasTagName(legendTag) || e->hasTagName(buttonTag) || e->hasTagName(inputTag) ||
1184 e->hasTagName(selectTag) || e->hasTagName(textareaTag))) {
1185 if (style->width().isAuto())
1186 style->setWidth(Length(Intrinsic));
1189 // Finally update our text decorations in effect, but don't allow text-decoration to percolate through
1190 // tables, inline blocks, inline tables, or run-ins.
1191 if (style->display() == TABLE || style->display() == INLINE_TABLE || style->display() == RUN_IN
1192 || style->display() == INLINE_BLOCK || style->display() == INLINE_BOX)
1193 style->setTextDecorationsInEffect(style->textDecoration());
1195 style->addToTextDecorationsInEffect(style->textDecoration());
1197 // If either overflow value is not visible, change to auto.
1198 if (style->overflowX() == OMARQUEE && style->overflowY() != OMARQUEE)
1199 style->setOverflowY(OMARQUEE);
1200 else if (style->overflowY() == OMARQUEE && style->overflowX() != OMARQUEE)
1201 style->setOverflowX(OMARQUEE);
1202 else if (style->overflowX() == OVISIBLE && style->overflowY() != OVISIBLE)
1203 style->setOverflowX(OAUTO);
1204 else if (style->overflowY() == OVISIBLE && style->overflowX() != OVISIBLE)
1205 style->setOverflowY(OAUTO);
1207 // Table rows, sections and the table itself will support overflow:hidden and will ignore scroll/auto.
1208 // FIXME: Eventually table sections will support auto and scroll.
1209 if (style->display() == TABLE || style->display() == INLINE_TABLE ||
1210 style->display() == TABLE_ROW_GROUP || style->display() == TABLE_ROW) {
1211 if (style->overflowX() != OVISIBLE && style->overflowX() != OHIDDEN)
1212 style->setOverflowX(OVISIBLE);
1213 if (style->overflowY() != OVISIBLE && style->overflowY() != OHIDDEN)
1214 style->setOverflowY(OVISIBLE);
1217 // Cull out any useless layers and also repeat patterns into additional layers.
1218 style->adjustBackgroundLayers();
1220 // Do the same for transitions.
1221 style->adjustTransitions();
1223 // Important: Intrinsic margins get added to controls before the theme has adjusted the style, since the theme will
1224 // alter fonts and heights/widths.
1225 if (e && e->isControl() && style->fontSize() >= 11) {
1226 // Don't apply intrinsic margins to image buttons. The designer knows how big the images are,
1227 // so we have to treat all image buttons as though they were explicitly sized.
1228 if (!e->hasTagName(inputTag) || static_cast<HTMLInputElement*>(e)->inputType() != HTMLInputElement::IMAGE)
1229 addIntrinsicMargins(style);
1232 // Let the theme also have a crack at adjusting the style.
1233 if (style->hasAppearance())
1234 theme()->adjustStyle(this, style, e, m_hasUAAppearance, m_borderData, m_backgroundData, m_backgroundColor);
1237 if (e && e->isSVGElement()) {
1238 // Spec: http://www.w3.org/TR/SVG/masking.html#OverflowProperty
1239 if (style->overflowY() == OSCROLL)
1240 style->setOverflowY(OHIDDEN);
1241 else if (style->overflowY() == OAUTO)
1242 style->setOverflowY(OVISIBLE);
1244 if (style->overflowX() == OSCROLL)
1245 style->setOverflowX(OHIDDEN);
1246 else if (style->overflowX() == OAUTO)
1247 style->setOverflowX(OVISIBLE);
1249 // Only the root <svg> element in an SVG document fragment tree honors css position
1250 if (!(e->hasTagName(SVGNames::svgTag) && e->parentNode() && !e->parentNode()->isSVGElement()))
1251 style->setPosition(RenderStyle::initialPosition());
1256 void CSSStyleSelector::updateFont()
1258 checkForTextSizeAdjust();
1259 checkForGenericFamilyChange(style, parentStyle);
1260 style->font().update(m_fontSelector);
1264 void CSSStyleSelector::cacheBorderAndBackground()
1266 m_hasUAAppearance = style->hasAppearance();
1267 if (m_hasUAAppearance) {
1268 m_borderData = style->border();
1269 m_backgroundData = *style->backgroundLayers();
1270 m_backgroundColor = style->backgroundColor();
1274 RefPtr<CSSRuleList> CSSStyleSelector::styleRulesForElement(Element* e, bool authorOnly)
1276 if (!e || !e->document()->haveStylesheetsLoaded())
1279 m_collectRulesOnly = true;
1281 initElementAndPseudoState(e);
1282 initForStyleResolve(e, 0);
1285 int firstUARule = -1, lastUARule = -1;
1286 // First we match rules from the user agent sheet.
1287 matchUARules(firstUARule, lastUARule);
1289 // Now we check user sheet rules.
1290 if (m_matchAuthorAndUserStyles) {
1291 int firstUserRule = -1, lastUserRule = -1;
1292 matchRules(m_userStyle, firstUserRule, lastUserRule);
1296 if (m_matchAuthorAndUserStyles) {
1297 // Check the rules in author sheets.
1298 int firstAuthorRule = -1, lastAuthorRule = -1;
1299 matchRules(m_authorStyle, firstAuthorRule, lastAuthorRule);
1302 m_collectRulesOnly = false;
1307 RefPtr<CSSRuleList> CSSStyleSelector::pseudoStyleRulesForElement(Element* e, StringImpl* pseudoStyle, bool authorOnly)
1309 // FIXME: Implement this.
1313 bool CSSStyleSelector::checkSelector(CSSSelector* sel)
1315 dynamicPseudo = RenderStyle::NOPSEUDO;
1317 // Check the selector
1318 SelectorMatch match = checkSelector(sel, element, true, false);
1319 if (match != SelectorMatches)
1322 if (pseudoStyle != RenderStyle::NOPSEUDO && pseudoStyle != dynamicPseudo)
1328 // Recursive check of selectors and combinators
1329 // It can return 3 different values:
1330 // * SelectorMatches - the selector matches the element e
1331 // * SelectorFailsLocally - the selector fails for the element e
1332 // * SelectorFailsCompletely - the selector fails for e and any sibling or ancestor of e
1333 CSSStyleSelector::SelectorMatch CSSStyleSelector::checkSelector(CSSSelector* sel, Element* e, bool isAncestor, bool isSubSelector)
1336 // Spec: CSS2 selectors cannot be applied to the (conceptually) cloned DOM tree
1337 // because its contents are not part of the formal document structure.
1338 if (e->isSVGElement() && e->isShadowNode())
1339 return SelectorFailsCompletely;
1342 // first selector has to match
1343 if (!checkOneSelector(sel, e, isAncestor, isSubSelector))
1344 return SelectorFailsLocally;
1346 // The rest of the selectors has to match
1347 CSSSelector::Relation relation = sel->relation();
1350 sel = sel->m_tagHistory;
1352 return SelectorMatches;
1354 if (relation != CSSSelector::SubSelector)
1355 // Bail-out if this selector is irrelevant for the pseudoStyle
1356 if (pseudoStyle != RenderStyle::NOPSEUDO && pseudoStyle != dynamicPseudo)
1357 return SelectorFailsCompletely;
1360 case CSSSelector::Descendant:
1362 Node* n = e->parentNode();
1363 if (!n || !n->isElementNode())
1364 return SelectorFailsCompletely;
1365 e = static_cast<Element*>(n);
1366 SelectorMatch match = checkSelector(sel, e, true, false);
1367 if (match != SelectorFailsLocally)
1371 case CSSSelector::Child:
1373 Node* n = e->parentNode();
1374 if (!n || !n->isElementNode())
1375 return SelectorFailsCompletely;
1376 e = static_cast<Element*>(n);
1377 return checkSelector(sel, e, true, false);
1379 case CSSSelector::DirectAdjacent:
1381 Node* n = e->previousSibling();
1382 while (n && !n->isElementNode())
1383 n = n->previousSibling();
1385 return SelectorFailsLocally;
1386 e = static_cast<Element*>(n);
1387 return checkSelector(sel, e, false, false);
1389 case CSSSelector::IndirectAdjacent:
1391 Node* n = e->previousSibling();
1392 while (n && !n->isElementNode())
1393 n = n->previousSibling();
1395 return SelectorFailsLocally;
1396 e = static_cast<Element*>(n);
1397 SelectorMatch match = checkSelector(sel, e, false, false);
1398 if (match != SelectorFailsLocally)
1402 case CSSSelector::SubSelector:
1403 // a selector is invalid if something follows a pseudo-element
1404 if (e == element && dynamicPseudo != RenderStyle::NOPSEUDO)
1405 return SelectorFailsCompletely;
1406 return checkSelector(sel, e, isAncestor, true);
1409 return SelectorFailsCompletely;
1412 bool CSSStyleSelector::checkOneSelector(CSSSelector* sel, Element* e, bool isAncestor, bool isSubSelector)
1417 if (sel->hasTag()) {
1418 const AtomicString& localName = e->localName();
1419 const AtomicString& ns = e->namespaceURI();
1420 const AtomicString& selLocalName = sel->m_tag.localName();
1421 const AtomicString& selNS = sel->m_tag.namespaceURI();
1423 if ((selLocalName != starAtom && localName != selLocalName) ||
1424 (selNS != starAtom && ns != selNS))
1428 if (sel->hasAttribute()) {
1429 if (sel->m_match == CSSSelector::Class) {
1432 const ClassNames& classNames = *e->getClassNames();
1433 for (size_t i = 0; i < classNames.size(); ++i) {
1434 if (classNames[i] == sel->m_value)
1438 } else if (sel->m_match == CSSSelector::Id)
1439 return e->hasID() && e->getIDAttribute() == sel->m_value;
1440 else if (style && (e != element || !styledElement || (!styledElement->isMappedAttribute(sel->m_attr) && sel->m_attr != typeAttr && sel->m_attr != readonlyAttr))) {
1441 style->setAffectedByAttributeSelectors(); // Special-case the "type" and "readonly" attributes so input form controls can share style.
1442 m_selectorAttrs.add(sel->m_attr.localName().impl());
1445 const AtomicString& value = e->getAttribute(sel->m_attr);
1447 return false; // attribute is not set
1449 switch (sel->m_match) {
1450 case CSSSelector::Exact:
1451 if ((isXMLDoc && sel->m_value != value) || (!isXMLDoc && !equalIgnoringCase(sel->m_value, value)))
1454 case CSSSelector::List:
1456 // The selector's value can't contain a space, or it's totally bogus.
1457 if (sel->m_value.contains(' '))
1460 int startSearchAt = 0;
1462 int foundPos = value.find(sel->m_value, startSearchAt, isXMLDoc);
1465 if (foundPos == 0 || value[foundPos-1] == ' ') {
1466 unsigned endStr = foundPos + sel->m_value.length();
1467 if (endStr == value.length() || value[endStr] == ' ')
1468 break; // We found a match.
1471 // No match. Keep looking.
1472 startSearchAt = foundPos + 1;
1476 case CSSSelector::Contain:
1477 if (!value.contains(sel->m_value, isXMLDoc))
1480 case CSSSelector::Begin:
1481 if (!value.startsWith(sel->m_value, isXMLDoc))
1484 case CSSSelector::End:
1485 if (!value.endsWith(sel->m_value, isXMLDoc))
1488 case CSSSelector::Hyphen:
1489 if (value.length() < sel->m_value.length())
1491 if (!value.startsWith(sel->m_value, isXMLDoc))
1493 // It they start the same, check for exact match or following '-':
1494 if (value.length() != sel->m_value.length() && value[sel->m_value.length()] != '-')
1497 case CSSSelector::PseudoClass:
1498 case CSSSelector::PseudoElement:
1503 if (sel->m_match == CSSSelector::PseudoClass)
1505 switch (sel->pseudoType()) {
1507 case CSSSelector::PseudoEmpty:
1508 if (!e->firstChild())
1511 case CSSSelector::PseudoFirstChild: {
1512 // first-child matches the first child that is an element!
1513 if (e->parentNode() && e->parentNode()->isElementNode()) {
1514 Node *n = e->previousSibling();
1515 while (n && !n->isElementNode())
1516 n = n->previousSibling();
1522 case CSSSelector::PseudoFirstOfType: {
1523 // first-of-type matches the first element of its type!
1524 if (e->parentNode() && e->parentNode()->isElementNode()) {
1525 const QualifiedName& type = e->tagQName();
1526 Node *n = e->previousSibling();
1528 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
1530 n = n->previousSibling();
1537 case CSSSelector::PseudoTarget:
1538 if (e == e->document()->getCSSTarget())
1541 case CSSSelector::PseudoAnyLink:
1542 if (pseudoState == PseudoUnknown)
1543 checkPseudoState(e, false);
1544 if (pseudoState == PseudoAnyLink || pseudoState == PseudoLink || pseudoState == PseudoVisited)
1547 case CSSSelector::PseudoAutofill:
1548 if (e && e->hasTagName(inputTag))
1549 return static_cast<HTMLInputElement*>(e)->autofilled();
1551 case CSSSelector::PseudoLink:
1552 if (pseudoState == PseudoUnknown || pseudoState == PseudoAnyLink)
1553 checkPseudoState(e);
1554 if (pseudoState == PseudoLink)
1557 case CSSSelector::PseudoVisited:
1558 if (pseudoState == PseudoUnknown || pseudoState == PseudoAnyLink)
1559 checkPseudoState(e);
1560 if (pseudoState == PseudoVisited)
1563 case CSSSelector::PseudoDrag: {
1564 if (element == e && style)
1565 style->setAffectedByDragRules(true);
1566 if (element != e && e->renderStyle())
1567 e->renderStyle()->setAffectedByDragRules(true);
1568 if (e->renderer() && e->renderer()->isDragging())
1572 case CSSSelector::PseudoFocus:
1573 if (e && e->focused() && e->document()->frame()->isActive())
1576 case CSSSelector::PseudoHover: {
1577 // If we're in quirks mode, then hover should never match anchors with no
1578 // href and *:hover should not match anything. This is important for sites like wsj.com.
1579 if (strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {
1580 if (element == e && style)
1581 style->setAffectedByHoverRules(true);
1582 if (element != e && e->renderStyle())
1583 e->renderStyle()->setAffectedByHoverRules(true);
1589 case CSSSelector::PseudoActive:
1590 // If we're in quirks mode, then :active should never match anchors with no
1591 // href and *:active should not match anything.
1592 if (strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {
1593 if (element == e && style)
1594 style->setAffectedByActiveRules(true);
1595 else if (e->renderStyle())
1596 e->renderStyle()->setAffectedByActiveRules(true);
1601 case CSSSelector::PseudoEnabled:
1602 if (e && e->isControl() && !e->isInputTypeHidden())
1603 // The UI spec states that you can't match :enabled unless you are an object that can
1604 // "receive focus and be activated." We will limit matching of this pseudo-class to elements
1605 // that are non-"hidden" controls.
1606 return e->isEnabled();
1608 case CSSSelector::PseudoDisabled:
1609 if (e && e->isControl() && !e->isInputTypeHidden())
1610 // The UI spec states that you can't match :enabled unless you are an object that can
1611 // "receive focus and be activated." We will limit matching of this pseudo-class to elements
1612 // that are non-"hidden" controls.
1613 return !e->isEnabled();
1615 case CSSSelector::PseudoChecked:
1616 // Even though WinIE allows checked and indeterminate to co-exist, the CSS selector spec says that
1617 // you can't be both checked and indeterminate. We will behave like WinIE behind the scenes and just
1618 // obey the CSS spec here in the test for matching the pseudo.
1619 if (e && e->isChecked() && !e->isIndeterminate())
1622 case CSSSelector::PseudoIndeterminate:
1623 if (e && e->isIndeterminate())
1626 case CSSSelector::PseudoRoot:
1627 if (e == e->document()->documentElement())
1630 case CSSSelector::PseudoLang: {
1631 const AtomicString& value = e->getAttribute(langAttr);
1632 if (value.isEmpty() || !value.startsWith(sel->m_argument, false))
1634 if (value.length() != sel->m_argument.length() && value[sel->m_argument.length()] != '-')
1638 case CSSSelector::PseudoNot: {
1639 // check the simple selector
1640 for (CSSSelector* subSel = sel->m_simpleSelector; subSel; subSel = subSel->m_tagHistory) {
1641 // :not cannot nest. I don't really know why this is a
1642 // restriction in CSS3, but it is, so let's honour it.
1643 if (subSel->m_simpleSelector)
1645 if (!checkOneSelector(subSel, e, isAncestor, true))
1650 case CSSSelector::PseudoUnknown:
1651 case CSSSelector::PseudoNotParsed:
1653 ASSERT_NOT_REACHED();
1658 if (sel->m_match == CSSSelector::PseudoElement) {
1659 if (e != element) return false;
1661 switch (sel->pseudoType()) {
1663 case CSSSelector::PseudoFirstLine:
1664 dynamicPseudo = RenderStyle::FIRST_LINE;
1666 case CSSSelector::PseudoFirstLetter:
1667 dynamicPseudo = RenderStyle::FIRST_LETTER;
1668 if (Document* doc = e->document())
1669 doc->setUsesFirstLetterRules(true);
1671 case CSSSelector::PseudoSelection:
1672 dynamicPseudo = RenderStyle::SELECTION;
1674 case CSSSelector::PseudoBefore:
1675 dynamicPseudo = RenderStyle::BEFORE;
1677 case CSSSelector::PseudoAfter:
1678 dynamicPseudo = RenderStyle::AFTER;
1680 case CSSSelector::PseudoFileUploadButton:
1681 dynamicPseudo = RenderStyle::FILE_UPLOAD_BUTTON;
1683 case CSSSelector::PseudoSliderThumb:
1684 dynamicPseudo = RenderStyle::SLIDER_THUMB;
1686 case CSSSelector::PseudoSearchCancelButton:
1687 dynamicPseudo = RenderStyle::SEARCH_CANCEL_BUTTON;
1689 case CSSSelector::PseudoSearchDecoration:
1690 dynamicPseudo = RenderStyle::SEARCH_DECORATION;
1692 case CSSSelector::PseudoSearchResultsDecoration:
1693 dynamicPseudo = RenderStyle::SEARCH_RESULTS_DECORATION;
1695 case CSSSelector::PseudoSearchResultsButton:
1696 dynamicPseudo = RenderStyle::SEARCH_RESULTS_BUTTON;
1698 case CSSSelector::PseudoMediaControlsPanel:
1699 dynamicPseudo = RenderStyle::MEDIA_CONTROLS_PANEL;
1701 case CSSSelector::PseudoMediaControlsMuteButton:
1702 dynamicPseudo = RenderStyle::MEDIA_CONTROLS_MUTE_BUTTON;
1704 case CSSSelector::PseudoMediaControlsPlayButton:
1705 dynamicPseudo = RenderStyle::MEDIA_CONTROLS_PLAY_BUTTON;
1707 case CSSSelector::PseudoMediaControlsTimeDisplay:
1708 dynamicPseudo = RenderStyle::MEDIA_CONTROLS_TIME_DISPLAY;
1710 case CSSSelector::PseudoMediaControlsTimeline:
1711 dynamicPseudo = RenderStyle::MEDIA_CONTROLS_TIMELINE;
1713 case CSSSelector::PseudoUnknown:
1714 case CSSSelector::PseudoNotParsed:
1716 ASSERT_NOT_REACHED();
1721 // ### add the rest of the checks...
1725 // -----------------------------------------------------------------
1727 CSSRuleSet::CSSRuleSet()
1729 m_universalRules = 0;
1733 CSSRuleSet::~CSSRuleSet()
1735 deleteAllValues(m_idRules);
1736 deleteAllValues(m_classRules);
1737 deleteAllValues(m_tagRules);
1739 delete m_universalRules;
1743 void CSSRuleSet::addToRuleSet(AtomicStringImpl* key, AtomRuleMap& map,
1744 CSSStyleRule* rule, CSSSelector* sel)
1747 CSSRuleDataList* rules = map.get(key);
1749 rules = new CSSRuleDataList(m_ruleCount++, rule, sel);
1750 map.set(key, rules);
1752 rules->append(m_ruleCount++, rule, sel);
1755 void CSSRuleSet::addRule(CSSStyleRule* rule, CSSSelector* sel)
1757 if (sel->m_match == CSSSelector::Id) {
1758 addToRuleSet(sel->m_value.impl(), m_idRules, rule, sel);
1761 if (sel->m_match == CSSSelector::Class) {
1762 addToRuleSet(sel->m_value.impl(), m_classRules, rule, sel);
1766 const AtomicString& localName = sel->m_tag.localName();
1767 if (localName != starAtom) {
1768 addToRuleSet(localName.impl(), m_tagRules, rule, sel);
1772 // Just put it in the universal rule set.
1773 if (!m_universalRules)
1774 m_universalRules = new CSSRuleDataList(m_ruleCount++, rule, sel);
1776 m_universalRules->append(m_ruleCount++, rule, sel);
1779 void CSSRuleSet::addRulesFromSheet(CSSStyleSheet* sheet, const MediaQueryEvaluator& medium, CSSStyleSelector* styleSelector)
1781 if (!sheet || !sheet->isCSSStyleSheet())
1784 // No media implies "all", but if a media list exists it must
1785 // contain our current medium
1786 if (sheet->media() && !medium.eval(sheet->media()))
1787 return; // the style sheet doesn't apply
1789 int len = sheet->length();
1791 for (int i = 0; i < len; i++) {
1792 StyleBase* item = sheet->item(i);
1793 if (item->isStyleRule()) {
1794 CSSStyleRule* rule = static_cast<CSSStyleRule*>(item);
1795 for (CSSSelector* s = rule->selector(); s; s = s->next())
1798 else if (item->isImportRule()) {
1799 CSSImportRule* import = static_cast<CSSImportRule*>(item);
1800 if (!import->media() || medium.eval(import->media()))
1801 addRulesFromSheet(import->styleSheet(), medium, styleSelector);
1803 else if (item->isMediaRule()) {
1804 CSSMediaRule* r = static_cast<CSSMediaRule*>(item);
1805 CSSRuleList* rules = r->cssRules();
1807 if ((!r->media() || medium.eval(r->media())) && rules) {
1808 // Traverse child elements of the @media rule.
1809 for (unsigned j = 0; j < rules->length(); j++) {
1810 CSSRule *childItem = rules->item(j);
1811 if (childItem->isStyleRule()) {
1812 // It is a StyleRule, so append it to our list
1813 CSSStyleRule* rule = static_cast<CSSStyleRule*>(childItem);
1814 for (CSSSelector* s = rule->selector(); s; s = s->next())
1816 } else if (item->isFontFaceRule() && styleSelector) {
1817 // Add this font face to our set.
1818 const CSSFontFaceRule* fontFaceRule = static_cast<CSSFontFaceRule*>(item);
1819 styleSelector->fontSelector()->addFontFaceRule(fontFaceRule);
1823 } else if (item->isFontFaceRule() && styleSelector) {
1824 // Add this font face to our set.
1825 const CSSFontFaceRule* fontFaceRule = static_cast<CSSFontFaceRule*>(item);
1826 styleSelector->fontSelector()->addFontFaceRule(fontFaceRule);
1831 // -------------------------------------------------------------------------------------
1832 // this is mostly boring stuff on how to apply a certain rule to the renderstyle...
1834 static Length convertToLength(CSSPrimitiveValue *primitiveValue, RenderStyle *style, bool *ok = 0)
1837 if (!primitiveValue) {
1841 int type = primitiveValue->primitiveType();
1842 if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
1843 l = Length(primitiveValue->computeLengthIntForLength(style), Fixed);
1844 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
1845 l = Length(primitiveValue->getDoubleValue(), Percent);
1846 else if (type == CSSPrimitiveValue::CSS_NUMBER)
1847 l = Length(primitiveValue->getDoubleValue() * 100.0, Percent);
1854 void CSSStyleSelector::applyDeclarations(bool applyFirst, bool isImportant,
1855 int startIndex, int endIndex)
1857 if (startIndex == -1) return;
1858 for (int i = startIndex; i <= endIndex; i++) {
1859 CSSMutableStyleDeclaration* decl = m_matchedDecls[i];
1860 DeprecatedValueListConstIterator<CSSProperty> end;
1861 for (DeprecatedValueListConstIterator<CSSProperty> it = decl->valuesIterator(); it != end; ++it) {
1862 const CSSProperty& current = *it;
1863 // give special priority to font-xxx, color properties
1864 if (isImportant == current.isImportant()) {
1866 switch (current.id()) {
1867 case CSS_PROP_LINE_HEIGHT:
1868 m_lineHeightValue = current.value();
1869 first = !applyFirst; // we apply line-height later
1871 case CSS_PROP_COLOR:
1872 case CSS_PROP_DIRECTION:
1873 case CSS_PROP_DISPLAY:
1875 case CSS_PROP_FONT_SIZE:
1876 case CSS_PROP_FONT_STYLE:
1877 case CSS_PROP_FONT_FAMILY:
1878 case CSS_PROP_FONT_WEIGHT:
1879 case CSS_PROP__WEBKIT_TEXT_SIZE_ADJUST:
1880 case CSS_PROP_FONT_VARIANT:
1881 // these have to be applied first, because other properties use the computed
1882 // values of these porperties.
1889 if (first == applyFirst)
1890 applyProperty(current.id(), current.value());
1896 static void applyCounterList(RenderStyle* style, CSSValueList* list, bool isReset)
1898 CounterDirectiveMap& map = style->accessCounterDirectives();
1899 typedef CounterDirectiveMap::iterator Iterator;
1901 Iterator end = map.end();
1902 for (Iterator it = map.begin(); it != end; ++it)
1904 it->second.m_reset = false;
1906 it->second.m_increment = false;
1908 int length = list ? list->length() : 0;
1909 for (int i = 0; i < length; ++i) {
1910 Pair* pair = static_cast<CSSPrimitiveValue*>(list->item(i))->getPairValue();
1911 AtomicString identifier = static_cast<CSSPrimitiveValue*>(pair->first())->getStringValue();
1912 // FIXME: What about overflow?
1913 int value = static_cast<CSSPrimitiveValue*>(pair->second())->getIntValue();
1914 CounterDirectives& directives = map.add(identifier.impl(), CounterDirectives()).first->second;
1916 directives.m_reset = true;
1917 directives.m_resetValue = value;
1919 if (directives.m_increment)
1920 directives.m_incrementValue += value;
1922 directives.m_increment = true;
1923 directives.m_incrementValue = value;
1929 void CSSStyleSelector::applyProperty(int id, CSSValue *value)
1931 CSSPrimitiveValue* primitiveValue = 0;
1932 if (value->isPrimitiveValue())
1933 primitiveValue = static_cast<CSSPrimitiveValue*>(value);
1938 unsigned short valueType = value->cssValueType();
1940 bool isInherit = parentNode && valueType == CSSValue::CSS_INHERIT;
1941 bool isInitial = valueType == CSSValue::CSS_INITIAL || (!parentNode && valueType == CSSValue::CSS_INHERIT);
1943 // These properties are used to set the correct margins/padding on RTL lists.
1944 if (id == CSS_PROP__WEBKIT_MARGIN_START)
1945 id = style->direction() == LTR ? CSS_PROP_MARGIN_LEFT : CSS_PROP_MARGIN_RIGHT;
1946 else if (id == CSS_PROP__WEBKIT_PADDING_START)
1947 id = style->direction() == LTR ? CSS_PROP_PADDING_LEFT : CSS_PROP_PADDING_RIGHT;
1949 // What follows is a list that maps the CSS properties into their corresponding front-end
1950 // RenderStyle values. Shorthands (e.g. border, background) occur in this list as well and
1951 // are only hit when mapping "inherit" or "initial" into front-end values.
1952 switch (static_cast<CSSPropertyID>(id)) {
1953 // ident only properties
1954 case CSS_PROP_BACKGROUND_ATTACHMENT:
1955 HANDLE_BACKGROUND_VALUE(backgroundAttachment, BackgroundAttachment, value)
1957 case CSS_PROP__WEBKIT_BACKGROUND_CLIP:
1958 HANDLE_BACKGROUND_VALUE(backgroundClip, BackgroundClip, value)
1960 case CSS_PROP__WEBKIT_BACKGROUND_COMPOSITE:
1961 HANDLE_BACKGROUND_VALUE(backgroundComposite, BackgroundComposite, value)
1963 case CSS_PROP__WEBKIT_BACKGROUND_ORIGIN:
1964 HANDLE_BACKGROUND_VALUE(backgroundOrigin, BackgroundOrigin, value)
1966 case CSS_PROP_BACKGROUND_REPEAT:
1967 HANDLE_BACKGROUND_VALUE(backgroundRepeat, BackgroundRepeat, value)
1969 case CSS_PROP__WEBKIT_BACKGROUND_SIZE:
1970 HANDLE_BACKGROUND_VALUE(backgroundSize, BackgroundSize, value)
1972 case CSS_PROP_BORDER_COLLAPSE:
1973 HANDLE_INHERIT_AND_INITIAL(borderCollapse, BorderCollapse)
1974 if (!primitiveValue)
1976 switch (primitiveValue->getIdent()) {
1977 case CSS_VAL_COLLAPSE:
1978 style->setBorderCollapse(true);
1980 case CSS_VAL_SEPARATE:
1981 style->setBorderCollapse(false);
1988 case CSS_PROP_BORDER_TOP_STYLE:
1989 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderTopStyle, BorderTopStyle, BorderStyle)
1991 style->setBorderTopStyle(*primitiveValue);
1993 case CSS_PROP_BORDER_RIGHT_STYLE:
1994 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderRightStyle, BorderRightStyle, BorderStyle)
1996 style->setBorderRightStyle(*primitiveValue);
1998 case CSS_PROP_BORDER_BOTTOM_STYLE:
1999 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderBottomStyle, BorderBottomStyle, BorderStyle)
2001 style->setBorderBottomStyle(*primitiveValue);
2003 case CSS_PROP_BORDER_LEFT_STYLE:
2004 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderLeftStyle, BorderLeftStyle, BorderStyle)
2006 style->setBorderLeftStyle(*primitiveValue);
2008 case CSS_PROP_OUTLINE_STYLE:
2009 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(outlineStyle, OutlineStyle, BorderStyle)
2010 if (primitiveValue) {
2011 if (primitiveValue->getIdent() == CSS_VAL_AUTO)
2012 style->setOutlineStyle(DOTTED, true);
2014 style->setOutlineStyle(*primitiveValue);
2017 case CSS_PROP_CAPTION_SIDE:
2019 HANDLE_INHERIT_AND_INITIAL(captionSide, CaptionSide)
2021 style->setCaptionSide(*primitiveValue);
2024 case CSS_PROP_CLEAR:
2026 HANDLE_INHERIT_AND_INITIAL(clear, Clear)
2028 style->setClear(*primitiveValue);
2031 case CSS_PROP_DIRECTION:
2033 HANDLE_INHERIT_AND_INITIAL(direction, Direction)
2035 style->setDirection(*primitiveValue);
2038 case CSS_PROP_DISPLAY:
2040 HANDLE_INHERIT_AND_INITIAL(display, Display)
2042 style->setDisplay(*primitiveValue);
2046 case CSS_PROP_EMPTY_CELLS:
2048 HANDLE_INHERIT_AND_INITIAL(emptyCells, EmptyCells)
2050 style->setEmptyCells(*primitiveValue);
2053 case CSS_PROP_FLOAT:
2055 HANDLE_INHERIT_AND_INITIAL(floating, Floating)
2057 style->setFloating(*primitiveValue);
2061 case CSS_PROP_FONT_STYLE:
2063 FontDescription fontDescription = style->fontDescription();
2065 fontDescription.setItalic(parentStyle->fontDescription().italic());
2067 fontDescription.setItalic(false);
2069 if (!primitiveValue)
2071 switch (primitiveValue->getIdent()) {
2072 case CSS_VAL_OBLIQUE:
2073 // FIXME: oblique is the same as italic for the moment...
2074 case CSS_VAL_ITALIC:
2075 fontDescription.setItalic(true);
2077 case CSS_VAL_NORMAL:
2078 fontDescription.setItalic(false);
2084 if (style->setFontDescription(fontDescription))
2089 case CSS_PROP_FONT_VARIANT:
2091 FontDescription fontDescription = style->fontDescription();
2093 fontDescription.setSmallCaps(parentStyle->fontDescription().smallCaps());
2095 fontDescription.setSmallCaps(false);
2097 if (!primitiveValue)
2099 int id = primitiveValue->getIdent();
2100 if (id == CSS_VAL_NORMAL)
2101 fontDescription.setSmallCaps(false);
2102 else if (id == CSS_VAL_SMALL_CAPS)
2103 fontDescription.setSmallCaps(true);
2107 if (style->setFontDescription(fontDescription))
2112 case CSS_PROP_FONT_WEIGHT:
2114 FontDescription fontDescription = style->fontDescription();
2116 fontDescription.setWeight(parentStyle->fontDescription().weight());
2118 fontDescription.setWeight(cNormalWeight);
2120 if (!primitiveValue)
2122 if (primitiveValue->getIdent()) {
2123 switch (primitiveValue->getIdent()) {
2124 // FIXME: We aren't genuinely supporting specific weight values.
2126 case CSS_VAL_BOLDER:
2131 fontDescription.setWeight(cBoldWeight);
2133 case CSS_VAL_NORMAL:
2134 case CSS_VAL_LIGHTER:
2140 fontDescription.setWeight(cNormalWeight);
2148 // ### fix parsing of 100-900 values in parser, apply them here
2151 if (style->setFontDescription(fontDescription))
2156 case CSS_PROP_LIST_STYLE_POSITION:
2158 HANDLE_INHERIT_AND_INITIAL(listStylePosition, ListStylePosition)
2160 style->setListStylePosition(*primitiveValue);
2164 case CSS_PROP_LIST_STYLE_TYPE:
2166 HANDLE_INHERIT_AND_INITIAL(listStyleType, ListStyleType)
2168 style->setListStyleType(*primitiveValue);
2172 case CSS_PROP_OVERFLOW:
2175 style->setOverflowX(parentStyle->overflowX());
2176 style->setOverflowY(parentStyle->overflowY());
2181 style->setOverflowX(RenderStyle::initialOverflowX());
2182 style->setOverflowY(RenderStyle::initialOverflowY());
2186 EOverflow o = *primitiveValue;
2188 style->setOverflowX(o);
2189 style->setOverflowY(o);
2193 case CSS_PROP_OVERFLOW_X:
2195 HANDLE_INHERIT_AND_INITIAL(overflowX, OverflowX)
2196 style->setOverflowX(*primitiveValue);
2200 case CSS_PROP_OVERFLOW_Y:
2202 HANDLE_INHERIT_AND_INITIAL(overflowY, OverflowY)
2203 style->setOverflowY(*primitiveValue);
2207 case CSS_PROP_PAGE_BREAK_BEFORE:
2209 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(pageBreakBefore, PageBreakBefore, PageBreak)
2211 style->setPageBreakBefore(*primitiveValue);
2215 case CSS_PROP_PAGE_BREAK_AFTER:
2217 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(pageBreakAfter, PageBreakAfter, PageBreak)
2219 style->setPageBreakAfter(*primitiveValue);
2223 case CSS_PROP_PAGE_BREAK_INSIDE: {
2224 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(pageBreakInside, PageBreakInside, PageBreak)
2225 if (!primitiveValue)
2227 EPageBreak pageBreak = *primitiveValue;
2228 if (pageBreak != PBALWAYS)
2229 style->setPageBreakInside(pageBreak);
2233 case CSS_PROP_POSITION:
2235 HANDLE_INHERIT_AND_INITIAL(position, Position)
2237 style->setPosition(*primitiveValue);
2241 case CSS_PROP_TABLE_LAYOUT: {
2242 HANDLE_INHERIT_AND_INITIAL(tableLayout, TableLayout)
2244 ETableLayout l = *primitiveValue;
2246 l = RenderStyle::initialTableLayout();
2248 style->setTableLayout(l);
2252 case CSS_PROP_UNICODE_BIDI: {
2253 HANDLE_INHERIT_AND_INITIAL(unicodeBidi, UnicodeBidi)
2254 style->setUnicodeBidi(*primitiveValue);
2257 case CSS_PROP_TEXT_TRANSFORM: {
2258 HANDLE_INHERIT_AND_INITIAL(textTransform, TextTransform)
2259 style->setTextTransform(*primitiveValue);
2263 case CSS_PROP_VISIBILITY:
2265 HANDLE_INHERIT_AND_INITIAL(visibility, Visibility)
2266 style->setVisibility(*primitiveValue);
2269 case CSS_PROP_WHITE_SPACE:
2270 HANDLE_INHERIT_AND_INITIAL(whiteSpace, WhiteSpace)
2271 style->setWhiteSpace(*primitiveValue);
2274 case CSS_PROP_BACKGROUND_POSITION:
2275 HANDLE_BACKGROUND_INHERIT_AND_INITIAL(backgroundXPosition, BackgroundXPosition);
2276 HANDLE_BACKGROUND_INHERIT_AND_INITIAL(backgroundYPosition, BackgroundYPosition);
2278 case CSS_PROP_BACKGROUND_POSITION_X: {
2279 HANDLE_BACKGROUND_VALUE(backgroundXPosition, BackgroundXPosition, value)
2282 case CSS_PROP_BACKGROUND_POSITION_Y: {
2283 HANDLE_BACKGROUND_VALUE(backgroundYPosition, BackgroundYPosition, value)
2286 case CSS_PROP_BORDER_SPACING: {
2288 style->setHorizontalBorderSpacing(parentStyle->horizontalBorderSpacing());
2289 style->setVerticalBorderSpacing(parentStyle->verticalBorderSpacing());
2291 else if (isInitial) {
2292 style->setHorizontalBorderSpacing(0);
2293 style->setVerticalBorderSpacing(0);
2297 case CSS_PROP__WEBKIT_BORDER_HORIZONTAL_SPACING: {
2298 HANDLE_INHERIT_AND_INITIAL(horizontalBorderSpacing, HorizontalBorderSpacing)
2299 if (!primitiveValue)
2301 short spacing = primitiveValue->computeLengthShort(style);
2302 style->setHorizontalBorderSpacing(spacing);
2305 case CSS_PROP__WEBKIT_BORDER_VERTICAL_SPACING: {
2306 HANDLE_INHERIT_AND_INITIAL(verticalBorderSpacing, VerticalBorderSpacing)
2307 if (!primitiveValue)
2309 short spacing = primitiveValue->computeLengthShort(style);
2310 style->setVerticalBorderSpacing(spacing);
2313 case CSS_PROP_CURSOR:
2315 style->setCursor(parentStyle->cursor());
2316 style->setCursorList(parentStyle->cursors());
2319 style->clearCursorList();
2321 style->setCursor(RenderStyle::initialCursor());
2324 if (value->isValueList()) {
2325 CSSValueList* list = static_cast<CSSValueList*>(value);
2326 int len = list->length();
2327 style->setCursor(CURSOR_AUTO);
2328 for (int i = 0; i < len; i++) {
2329 CSSValue* item = list->item(i);
2330 if (!item->isPrimitiveValue())
2332 primitiveValue = static_cast<CSSPrimitiveValue*>(item);
2333 int type = primitiveValue->primitiveType();
2334 if (type == CSSPrimitiveValue::CSS_URI) {
2336 if (primitiveValue->getStringValue().find("#") == 0)
2337 style->addSVGCursor(primitiveValue->getStringValue().substring(1));
2341 CSSCursorImageValue* image = static_cast<CSSCursorImageValue*>(primitiveValue);
2342 style->addCursor(image->image(element->document()->docLoader()), image->hotspot());
2344 } else if (type == CSSPrimitiveValue::CSS_IDENT)
2345 style->setCursor(*primitiveValue);
2347 } else if (primitiveValue) {
2348 int type = primitiveValue->primitiveType();
2349 if (type == CSSPrimitiveValue::CSS_IDENT)
2350 style->setCursor(*primitiveValue);
2353 // colors || inherit
2354 case CSS_PROP_BACKGROUND_COLOR:
2355 case CSS_PROP_BORDER_TOP_COLOR:
2356 case CSS_PROP_BORDER_RIGHT_COLOR:
2357 case CSS_PROP_BORDER_BOTTOM_COLOR:
2358 case CSS_PROP_BORDER_LEFT_COLOR:
2359 case CSS_PROP_COLOR:
2360 case CSS_PROP_OUTLINE_COLOR:
2361 case CSS_PROP__WEBKIT_COLUMN_RULE_COLOR:
2362 case CSS_PROP__WEBKIT_TEXT_STROKE_COLOR:
2363 case CSS_PROP__WEBKIT_TEXT_FILL_COLOR: {
2366 HANDLE_INHERIT_COND(CSS_PROP_BACKGROUND_COLOR, backgroundColor, BackgroundColor)
2367 HANDLE_INHERIT_COND(CSS_PROP_BORDER_TOP_COLOR, borderTopColor, BorderTopColor)
2368 HANDLE_INHERIT_COND(CSS_PROP_BORDER_BOTTOM_COLOR, borderBottomColor, BorderBottomColor)
2369 HANDLE_INHERIT_COND(CSS_PROP_BORDER_RIGHT_COLOR, borderRightColor, BorderRightColor)
2370 HANDLE_INHERIT_COND(CSS_PROP_BORDER_LEFT_COLOR, borderLeftColor, BorderLeftColor)
2371 HANDLE_INHERIT_COND(CSS_PROP_COLOR, color, Color)
2372 HANDLE_INHERIT_COND(CSS_PROP_OUTLINE_COLOR, outlineColor, OutlineColor)
2373 HANDLE_INHERIT_COND(CSS_PROP__WEBKIT_COLUMN_RULE_COLOR, columnRuleColor, ColumnRuleColor)
2374 HANDLE_INHERIT_COND(CSS_PROP__WEBKIT_TEXT_STROKE_COLOR, textStrokeColor, TextStrokeColor)
2375 HANDLE_INHERIT_COND(CSS_PROP__WEBKIT_TEXT_FILL_COLOR, textFillColor, TextFillColor)
2379 // The border/outline colors will just map to the invalid color |col| above. This will have the
2380 // effect of forcing the use of the currentColor when it comes time to draw the borders (and of
2381 // not painting the background since the color won't be valid).
2382 if (id == CSS_PROP_COLOR)
2383 col = RenderStyle::initialColor();
2385 if (!primitiveValue)
2387 col = getColorFromPrimitiveValue(primitiveValue);
2391 case CSS_PROP_BACKGROUND_COLOR:
2392 style->setBackgroundColor(col); break;
2393 case CSS_PROP_BORDER_TOP_COLOR:
2394 style->setBorderTopColor(col); break;
2395 case CSS_PROP_BORDER_RIGHT_COLOR:
2396 style->setBorderRightColor(col); break;
2397 case CSS_PROP_BORDER_BOTTOM_COLOR:
2398 style->setBorderBottomColor(col); break;
2399 case CSS_PROP_BORDER_LEFT_COLOR:
2400 style->setBorderLeftColor(col); break;
2401 case CSS_PROP_COLOR:
2402 style->setColor(col); break;
2403 case CSS_PROP_OUTLINE_COLOR:
2404 style->setOutlineColor(col); break;
2405 case CSS_PROP__WEBKIT_COLUMN_RULE_COLOR:
2406 style->setColumnRuleColor(col);
2408 case CSS_PROP__WEBKIT_TEXT_STROKE_COLOR:
2409 style->setTextStrokeColor(col);
2411 case CSS_PROP__WEBKIT_TEXT_FILL_COLOR:
2412 style->setTextFillColor(col);
2420 case CSS_PROP_BACKGROUND_IMAGE:
2421 HANDLE_BACKGROUND_VALUE(backgroundImage, BackgroundImage, value)
2423 case CSS_PROP_LIST_STYLE_IMAGE:
2425 HANDLE_INHERIT_AND_INITIAL(listStyleImage, ListStyleImage)
2426 if (!primitiveValue)
2428 style->setListStyleImage(static_cast<CSSImageValue*>(primitiveValue)->image(element->document()->docLoader()));
2433 case CSS_PROP_BORDER_TOP_WIDTH:
2434 case CSS_PROP_BORDER_RIGHT_WIDTH:
2435 case CSS_PROP_BORDER_BOTTOM_WIDTH:
2436 case CSS_PROP_BORDER_LEFT_WIDTH:
2437 case CSS_PROP_OUTLINE_WIDTH:
2438 case CSS_PROP__WEBKIT_COLUMN_RULE_WIDTH:
2441 HANDLE_INHERIT_COND(CSS_PROP_BORDER_TOP_WIDTH, borderTopWidth, BorderTopWidth)
2442 HANDLE_INHERIT_COND(CSS_PROP_BORDER_RIGHT_WIDTH, borderRightWidth, BorderRightWidth)
2443 HANDLE_INHERIT_COND(CSS_PROP_BORDER_BOTTOM_WIDTH, borderBottomWidth, BorderBottomWidth)
2444 HANDLE_INHERIT_COND(CSS_PROP_BORDER_LEFT_WIDTH, borderLeftWidth, BorderLeftWidth)
2445 HANDLE_INHERIT_COND(CSS_PROP_OUTLINE_WIDTH, outlineWidth, OutlineWidth)
2446 HANDLE_INHERIT_COND(CSS_PROP__WEBKIT_COLUMN_RULE_WIDTH, columnRuleWidth, ColumnRuleWidth)
2449 else if (isInitial) {
2450 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_TOP_WIDTH, BorderTopWidth, BorderWidth)
2451 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_RIGHT_WIDTH, BorderRightWidth, BorderWidth)
2452 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_BOTTOM_WIDTH, BorderBottomWidth, BorderWidth)
2453 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_LEFT_WIDTH, BorderLeftWidth, BorderWidth)
2454 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_OUTLINE_WIDTH, OutlineWidth, BorderWidth)
2455 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP__WEBKIT_COLUMN_RULE_WIDTH, ColumnRuleWidth, BorderWidth)
2459 if (!primitiveValue)
2462 switch (primitiveValue->getIdent()) {
2466 case CSS_VAL_MEDIUM:
2472 case CSS_VAL_INVALID:
2473 width = primitiveValue->computeLengthShort(style);
2479 if (width < 0) return;
2481 case CSS_PROP_BORDER_TOP_WIDTH:
2482 style->setBorderTopWidth(width);
2484 case CSS_PROP_BORDER_RIGHT_WIDTH:
2485 style->setBorderRightWidth(width);
2487 case CSS_PROP_BORDER_BOTTOM_WIDTH:
2488 style->setBorderBottomWidth(width);
2490 case CSS_PROP_BORDER_LEFT_WIDTH:
2491 style->setBorderLeftWidth(width);
2493 case CSS_PROP_OUTLINE_WIDTH:
2494 style->setOutlineWidth(width);
2496 case CSS_PROP__WEBKIT_COLUMN_RULE_WIDTH:
2497 style->setColumnRuleWidth(width);
2505 case CSS_PROP_LETTER_SPACING:
2506 case CSS_PROP_WORD_SPACING:
2510 HANDLE_INHERIT_COND(CSS_PROP_LETTER_SPACING, letterSpacing, LetterSpacing)
2511 HANDLE_INHERIT_COND(CSS_PROP_WORD_SPACING, wordSpacing, WordSpacing)
2514 else if (isInitial) {
2515 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_LETTER_SPACING, LetterSpacing, LetterWordSpacing)
2516 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_WORD_SPACING, WordSpacing, LetterWordSpacing)
2521 if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_NORMAL){
2524 if (!primitiveValue)
2526 width = primitiveValue->computeLengthInt(style);
2529 case CSS_PROP_LETTER_SPACING:
2530 style->setLetterSpacing(width);
2532 case CSS_PROP_WORD_SPACING:
2533 style->setWordSpacing(width);
2535 // ### needs the definitions in renderstyle
2541 case CSS_PROP_WORD_BREAK: {
2542 HANDLE_INHERIT_AND_INITIAL(wordBreak, WordBreak)
2543 style->setWordBreak(*primitiveValue);
2547 case CSS_PROP_WORD_WRAP: {
2548 HANDLE_INHERIT_AND_INITIAL(wordWrap, WordWrap)
2549 style->setWordWrap(*primitiveValue);
2553 case CSS_PROP__WEBKIT_NBSP_MODE:
2555 HANDLE_INHERIT_AND_INITIAL(nbspMode, NBSPMode)
2556 style->setNBSPMode(*primitiveValue);
2560 case CSS_PROP__WEBKIT_LINE_BREAK:
2562 HANDLE_INHERIT_AND_INITIAL(khtmlLineBreak, KHTMLLineBreak)
2563 style->setKHTMLLineBreak(*primitiveValue);
2567 case CSS_PROP__WEBKIT_MATCH_NEAREST_MAIL_BLOCKQUOTE_COLOR:
2569 HANDLE_INHERIT_AND_INITIAL(matchNearestMailBlockquoteColor, MatchNearestMailBlockquoteColor)
2570 style->setMatchNearestMailBlockquoteColor(*primitiveValue);
2574 case CSS_PROP_RESIZE:
2576 HANDLE_INHERIT_AND_INITIAL(resize, Resize)
2578 if (!primitiveValue->getIdent())
2581 EResize r = RESIZE_NONE;
2582 if (primitiveValue->getIdent() == CSS_VAL_AUTO) {
2583 if (Settings* settings = m_document->settings())
2584 r = settings->textAreasAreResizable() ? RESIZE_BOTH : RESIZE_NONE;
2586 r = *primitiveValue;
2588 style->setResize(r);
2593 case CSS_PROP_MAX_WIDTH:
2595 if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_NONE)
2599 case CSS_PROP_RIGHT:
2600 case CSS_PROP_BOTTOM:
2601 case CSS_PROP_WIDTH:
2602 case CSS_PROP_MIN_WIDTH:
2603 case CSS_PROP_MARGIN_TOP:
2604 case CSS_PROP_MARGIN_RIGHT:
2605 case CSS_PROP_MARGIN_BOTTOM:
2606 case CSS_PROP_MARGIN_LEFT:
2608 if (id == CSS_PROP_WIDTH || id == CSS_PROP_MIN_WIDTH || id == CSS_PROP_MAX_WIDTH) {
2609 if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_INTRINSIC) {
2610 l = Length(Intrinsic);
2613 else if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_MIN_INTRINSIC) {
2614 l = Length(MinIntrinsic);
2618 if (id != CSS_PROP_MAX_WIDTH && primitiveValue && primitiveValue->getIdent() == CSS_VAL_AUTO)
2620 case CSS_PROP_PADDING_TOP:
2621 case CSS_PROP_PADDING_RIGHT:
2622 case CSS_PROP_PADDING_BOTTOM:
2623 case CSS_PROP_PADDING_LEFT:
2624 case CSS_PROP_TEXT_INDENT:
2628 HANDLE_INHERIT_COND(CSS_PROP_MAX_WIDTH, maxWidth, MaxWidth)
2629 HANDLE_INHERIT_COND(CSS_PROP_BOTTOM, bottom, Bottom)
2630 HANDLE_INHERIT_COND(CSS_PROP_TOP, top, Top)
2631 HANDLE_INHERIT_COND(CSS_PROP_LEFT, left, Left)
2632 HANDLE_INHERIT_COND(CSS_PROP_RIGHT, right, Right)
2633 HANDLE_INHERIT_COND(CSS_PROP_WIDTH, width, Width)
2634 HANDLE_INHERIT_COND(CSS_PROP_MIN_WIDTH, minWidth, MinWidth)
2635 HANDLE_INHERIT_COND(CSS_PROP_PADDING_TOP, paddingTop, PaddingTop)
2636 HANDLE_INHERIT_COND(CSS_PROP_PADDING_RIGHT, paddingRight, PaddingRight)
2637 HANDLE_INHERIT_COND(CSS_PROP_PADDING_BOTTOM, paddingBottom, PaddingBottom)
2638 HANDLE_INHERIT_COND(CSS_PROP_PADDING_LEFT, paddingLeft, PaddingLeft)
2639 HANDLE_INHERIT_COND(CSS_PROP_MARGIN_TOP, marginTop, MarginTop)
2640 HANDLE_INHERIT_COND(CSS_PROP_MARGIN_RIGHT, marginRight, MarginRight)
2641 HANDLE_INHERIT_COND(CSS_PROP_MARGIN_BOTTOM, marginBottom, MarginBottom)
2642 HANDLE_INHERIT_COND(CSS_PROP_MARGIN_LEFT, marginLeft, MarginLeft)
2643 HANDLE_INHERIT_COND(CSS_PROP_TEXT_INDENT, textIndent, TextIndent)
2646 else if (isInitial) {
2647 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MAX_WIDTH, MaxWidth, MaxSize)
2648 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BOTTOM, Bottom, Offset)
2649 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_TOP, Top, Offset)
2650 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_LEFT, Left, Offset)
2651 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_RIGHT, Right, Offset)
2652 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_WIDTH, Width, Size)
2653 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MIN_WIDTH, MinWidth, MinSize)
2654 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_PADDING_TOP, PaddingTop, Padding)
2655 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_PADDING_RIGHT, PaddingRight, Padding)
2656 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_PADDING_BOTTOM, PaddingBottom, Padding)
2657 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_PADDING_LEFT, PaddingLeft, Padding)
2658 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MARGIN_TOP, MarginTop, Margin)
2659 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MARGIN_RIGHT, MarginRight, Margin)
2660 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MARGIN_BOTTOM, MarginBottom, Margin)
2661 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MARGIN_LEFT, MarginLeft, Margin)
2662 HANDLE_INITIAL_COND(CSS_PROP_TEXT_INDENT, TextIndent)
2666 if (primitiveValue && !apply) {
2667 int type = primitiveValue->primitiveType();
2668 if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
2669 // Handle our quirky margin units if we have them.
2670 l = Length(primitiveValue->computeLengthIntForLength(style), Fixed,
2671 primitiveValue->isQuirkValue());
2672 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
2673 l = Length(primitiveValue->getDoubleValue(), Percent);
2676 if (id == CSS_PROP_PADDING_LEFT || id == CSS_PROP_PADDING_RIGHT ||
2677 id == CSS_PROP_PADDING_TOP || id == CSS_PROP_PADDING_BOTTOM)
2678 // Padding can't be negative
2679 apply = !((l.isFixed() || l.isPercent()) && l.calcValue(100) < 0);
2685 case CSS_PROP_MAX_WIDTH:
2686 style->setMaxWidth(l); break;
2687 case CSS_PROP_BOTTOM:
2688 style->setBottom(l); break;
2690 style->setTop(l); break;
2692 style->setLeft(l); break;
2693 case CSS_PROP_RIGHT:
2694 style->setRight(l); break;
2695 case CSS_PROP_WIDTH:
2696 style->setWidth(l); break;
2697 case CSS_PROP_MIN_WIDTH:
2698 style->setMinWidth(l); break;
2699 case CSS_PROP_PADDING_TOP:
2700 style->setPaddingTop(l); break;
2701 case CSS_PROP_PADDING_RIGHT:
2702 style->setPaddingRight(l); break;
2703 case CSS_PROP_PADDING_BOTTOM:
2704 style->setPaddingBottom(l); break;
2705 case CSS_PROP_PADDING_LEFT:
2706 style->setPaddingLeft(l); break;
2707 case CSS_PROP_MARGIN_TOP:
2708 style->setMarginTop(l); break;
2709 case CSS_PROP_MARGIN_RIGHT:
2710 style->setMarginRight(l); break;
2711 case CSS_PROP_MARGIN_BOTTOM:
2712 style->setMarginBottom(l); break;
2713 case CSS_PROP_MARGIN_LEFT:
2714 style->setMarginLeft(l); break;
2715 case CSS_PROP_TEXT_INDENT:
2716 style->setTextIndent(l); break;
2722 case CSS_PROP_MAX_HEIGHT:
2723 if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_NONE) {
2724 l = Length(undefinedLength, Fixed);
2727 case CSS_PROP_HEIGHT:
2728 case CSS_PROP_MIN_HEIGHT:
2729 if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_INTRINSIC) {
2730 l = Length(Intrinsic);
2732 } else if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_MIN_INTRINSIC) {
2733 l = Length(MinIntrinsic);
2735 } else if (id != CSS_PROP_MAX_HEIGHT && primitiveValue && primitiveValue->getIdent() == CSS_VAL_AUTO)
2738 HANDLE_INHERIT_COND(CSS_PROP_MAX_HEIGHT, maxHeight, MaxHeight)
2739 HANDLE_INHERIT_COND(CSS_PROP_HEIGHT, height, Height)
2740 HANDLE_INHERIT_COND(CSS_PROP_MIN_HEIGHT, minHeight, MinHeight)
2744 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MAX_HEIGHT, MaxHeight, MaxSize)
2745 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_HEIGHT, Height, Size)
2746 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MIN_HEIGHT, MinHeight, MinSize)
2750 if (primitiveValue && !apply) {
2751 unsigned short type = primitiveValue->primitiveType();
2752 if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
2753 l = Length(primitiveValue->computeLengthIntForLength(style), Fixed);
2754 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
2755 l = Length(primitiveValue->getDoubleValue(), Percent);
2762 case CSS_PROP_MAX_HEIGHT:
2763 style->setMaxHeight(l);
2765 case CSS_PROP_HEIGHT:
2766 style->setHeight(l);
2768 case CSS_PROP_MIN_HEIGHT:
2769 style->setMinHeight(l);
2774 case CSS_PROP_VERTICAL_ALIGN:
2775 HANDLE_INHERIT_AND_INITIAL(verticalAlign, VerticalAlign)
2776 if (!primitiveValue)
2778 if (primitiveValue->getIdent()) {
2779 EVerticalAlign align;
2781 switch (primitiveValue->getIdent()) {
2784 case CSS_VAL_BOTTOM:
2785 align = BOTTOM; break;
2786 case CSS_VAL_MIDDLE:
2787 align = MIDDLE; break;
2788 case CSS_VAL_BASELINE:
2789 align = BASELINE; break;
2790 case CSS_VAL_TEXT_BOTTOM:
2791 align = TEXT_BOTTOM; break;
2792 case CSS_VAL_TEXT_TOP:
2793 align = TEXT_TOP; break;
2797 align = SUPER; break;
2798 case CSS_VAL__WEBKIT_BASELINE_MIDDLE:
2799 align = BASELINE_MIDDLE; break;
2803 style->setVerticalAlign(align);
2806 int type = primitiveValue->primitiveType();
2808 if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
2809 l = Length(primitiveValue->computeLengthIntForLength(style), Fixed);
2810 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
2811 l = Length(primitiveValue->getDoubleValue(), Percent);
2813 style->setVerticalAlign(LENGTH);
2814 style->setVerticalAlignLength(l);
2818 case CSS_PROP_FONT_SIZE:
2820 FontDescription fontDescription = style->fontDescription();
2821 fontDescription.setKeywordSize(0);
2822 bool familyIsFixed = fontDescription.genericFamily() == FontDescription::MonospaceFamily;
2826 bool parentIsAbsoluteSize = false;
2828 oldSize = parentStyle->fontDescription().specifiedSize();
2829 parentIsAbsoluteSize = parentStyle->fontDescription().isAbsoluteSize();
2835 fontDescription.setKeywordSize(parentStyle->fontDescription().keywordSize());
2836 } else if (isInitial) {
2837 size = fontSizeForKeyword(CSS_VAL_MEDIUM, style->htmlHacks(), familyIsFixed);
2838 fontDescription.setKeywordSize(CSS_VAL_MEDIUM - CSS_VAL_XX_SMALL + 1);
2839 } else if (primitiveValue->getIdent()) {
2840 // Keywords are being used.
2841 switch (primitiveValue->getIdent()) {
2842 case CSS_VAL_XX_SMALL:
2843 case CSS_VAL_X_SMALL:
2845 case CSS_VAL_MEDIUM:
2847 case CSS_VAL_X_LARGE:
2848 case CSS_VAL_XX_LARGE:
2849 case CSS_VAL__WEBKIT_XXX_LARGE:
2850 size = fontSizeForKeyword(primitiveValue->getIdent(), style->htmlHacks(), familyIsFixed);
2851 fontDescription.setKeywordSize(primitiveValue->getIdent() - CSS_VAL_XX_SMALL + 1);
2853 case CSS_VAL_LARGER:
2854 size = largerFontSize(oldSize, style->htmlHacks());
2856 case CSS_VAL_SMALLER:
2857 size = smallerFontSize(oldSize, style->htmlHacks());
2863 fontDescription.setIsAbsoluteSize(parentIsAbsoluteSize &&
2864 (primitiveValue->getIdent() == CSS_VAL_LARGER ||
2865 primitiveValue->getIdent() == CSS_VAL_SMALLER));
2867 int type = primitiveValue->primitiveType();
2868 fontDescription.setIsAbsoluteSize(parentIsAbsoluteSize ||
2869 (type != CSSPrimitiveValue::CSS_PERCENTAGE &&
2870 type != CSSPrimitiveValue::CSS_EMS &&
2871 type != CSSPrimitiveValue::CSS_EXS));
2872 if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
2873 size = primitiveValue->computeLengthFloat(parentStyle, false);
2874 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
2875 size = (primitiveValue->getFloatValue() * oldSize) / 100.0f;
2883 setFontSize(fontDescription, size);
2884 if (style->setFontDescription(fontDescription))
2889 case CSS_PROP_Z_INDEX: {
2891 if (parentStyle->hasAutoZIndex())
2892 style->setHasAutoZIndex();
2894 style->setZIndex(parentStyle->zIndex());
2896 } else if (isInitial || primitiveValue->getIdent() == CSS_VAL_AUTO) {
2897 style->setHasAutoZIndex();
2901 // FIXME: Should clamp all sorts of other integer properties too.
2902 const double minIntAsDouble = INT_MIN;
2903 const double maxIntAsDouble = INT_MAX;
2904 style->setZIndex(static_cast<int>(max(minIntAsDouble, min(primitiveValue->getDoubleValue(), maxIntAsDouble))));
2907 case CSS_PROP_WIDOWS:
2909 HANDLE_INHERIT_AND_INITIAL(widows, Widows)
2910 if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER)
2912 style->setWidows(primitiveValue->getIntValue());
2916 case CSS_PROP_ORPHANS:
2918 HANDLE_INHERIT_AND_INITIAL(orphans, Orphans)
2919 if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER)
2921 style->setOrphans(primitiveValue->getIntValue());
2925 // length, percent, number
2926 case CSS_PROP_LINE_HEIGHT:
2928 HANDLE_INHERIT_AND_INITIAL(lineHeight, LineHeight)
2929 if (!primitiveValue)
2932 int type = primitiveValue->primitiveType();
2933 if (primitiveValue->getIdent() == CSS_VAL_NORMAL)
2934 lineHeight = Length(-100.0, Percent);
2935 else if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) {
2936 double multiplier = 1.0;
2937 // Scale for the font zoom factor only for types other than "em" and "ex", since those are
2938 // already based on the font size.
2939 if (type != CSSPrimitiveValue::CSS_EMS && type != CSSPrimitiveValue::CSS_EXS && style->textSizeAdjust() && m_document->frame()) {
2940 multiplier = m_document->frame()->zoomFactor() / 100.0;
2942 lineHeight = Length(primitiveValue->computeLengthIntForLength(style, multiplier), Fixed);
2943 } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
2944 lineHeight = Length((style->fontSize() * primitiveValue->getIntValue()) / 100, Fixed);
2945 else if (type == CSSPrimitiveValue::CSS_NUMBER)
2946 lineHeight = Length(primitiveValue->getDoubleValue() * 100.0, Percent);
2949 style->setLineHeight(lineHeight);
2954 case CSS_PROP_TEXT_ALIGN:
2956 HANDLE_INHERIT_AND_INITIAL(textAlign, TextAlign)
2957 if (!primitiveValue)
2959 int id = primitiveValue->getIdent();
2960 if (id == CSS_VAL_START)
2961 style->setTextAlign(style->direction() == LTR ? LEFT : RIGHT);
2962 else if (id == CSS_VAL_END)
2963 style->setTextAlign(style->direction() == LTR ? RIGHT : LEFT);
2965 style->setTextAlign(*primitiveValue);
2976 bool hasClip = true;
2978 if (parentStyle->hasClip()) {
2979 top = parentStyle->clipTop();
2980 right = parentStyle->clipRight();
2981 bottom = parentStyle->clipBottom();
2982 left = parentStyle->clipLeft();
2986 top = right = bottom = left = Length();
2988 } else if (isInitial) {
2990 top = right = bottom = left = Length();
2991 } else if (!primitiveValue) {
2993 } else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_RECT) {
2994 Rect* rect = primitiveValue->getRectValue();
2997 top = convertToLength(rect->top(), style);
2998 right = convertToLength(rect->right(), style);
2999 bottom = convertToLength(rect->bottom(), style);
3000 left = convertToLength(rect->left(), style);
3002 } else if (primitiveValue->getIdent() != CSS_VAL_AUTO) {
3005 style->setClip(top, right, bottom, left);
3006 style->setHasClip(hasClip);
3013 case CSS_PROP_CONTENT:
3014 // list of string, uri, counter, attr, i
3016 // FIXME: In CSS3, it will be possible to inherit content. In CSS2 it is not. This
3017 // note is a reminder that eventually "inherit" needs to be supported.
3020 style->clearContent();
3024 if (!value->isValueList())
3027 CSSValueList* list = static_cast<CSSValueList*>(value);
3028 int len = list->length();
3030 bool didSet = false;
3031 for (int i = 0; i < len; i++) {
3032 CSSValue* item = list->item(i);
3033 if (!item->isPrimitiveValue())
3036 CSSPrimitiveValue* val = static_cast<CSSPrimitiveValue*>(item);
3037 switch (val->primitiveType()) {
3038 case CSSPrimitiveValue::CSS_STRING:
3039 style->setContent(val->getStringValue().impl(), didSet);
3042 case CSSPrimitiveValue::CSS_ATTR: {
3043 // FIXME: Can a namespace be specified for an attr(foo)?
3044 if (style->styleType() == RenderStyle::NOPSEUDO)
3047 parentStyle->setUnique();
3048 QualifiedName attr(nullAtom, val->getStringValue().impl(), nullAtom);
3049 style->setContent(element->getAttribute(attr).impl(), didSet);
3051 // register the fact that the attribute value affects the style
3052 m_selectorAttrs.add(attr.localName().impl());
3055 case CSSPrimitiveValue::CSS_URI: {
3056 CSSImageValue *image = static_cast<CSSImageValue*>(val);
3057 style->setContent(image->image(element->document()->docLoader()), didSet);
3061 case CSSPrimitiveValue::CSS_COUNTER: {
3062 Counter* counterValue = val->getCounterValue();
3063 CounterContent* counter = new CounterContent(counterValue->identifier(),
3064 (EListStyleType)counterValue->listStyleNumber(), counterValue->separator());
3065 style->setContent(counter, didSet);
3071 style->clearContent();
3075 case CSS_PROP_COUNTER_INCREMENT:
3076 applyCounterList(style, value->isValueList() ? static_cast<CSSValueList*>(value) : 0, false);
3078 case CSS_PROP_COUNTER_RESET:
3079 applyCounterList(style, value->isValueList() ? static_cast<CSSValueList*>(value) : 0, true);
3082 case CSS_PROP_FONT_FAMILY: {
3083 // list of strings and ids
3085 FontDescription parentFontDescription = parentStyle->fontDescription();
3086 FontDescription fontDescription = style->fontDescription();
3087 fontDescription.setGenericFamily(parentFontDescription.genericFamily());
3088 fontDescription.setFamily(parentFontDescription.firstFamily());
3089 if (style->setFontDescription(fontDescription))
3093 else if (isInitial) {
3094 FontDescription initialDesc = FontDescription();
3095 FontDescription fontDescription = style->fontDescription();
3096 // We need to adjust the size to account for the generic family change from monospace
3097 // to non-monospace.
3098 if (fontDescription.keywordSize() && fontDescription.genericFamily() == FontDescription::MonospaceFamily)
3099 setFontSize(fontDescription, fontSizeForKeyword(CSS_VAL_XX_SMALL + fontDescription.keywordSize() - 1, style->htmlHacks(), false));
3100 fontDescription.setGenericFamily(initialDesc.genericFamily());
3101 fontDescription.setFamily(initialDesc.firstFamily());
3102 if (style->setFontDescription(fontDescription))
3107 if (!value->isValueList()) return;
3108 FontDescription fontDescription = style->fontDescription();
3109 CSSValueList *list = static_cast<CSSValueList*>(value);
3110 int len = list->length();
3111 FontFamily& firstFamily = fontDescription.firstFamily();
3112 FontFamily *currFamily = 0;
3114 // Before mapping in a new font-family property, we should reset the generic family.
3115 bool oldFamilyIsMonospace = fontDescription.genericFamily() == FontDescription::MonospaceFamily;
3116 fontDescription.setGenericFamily(FontDescription::NoFamily);
3118 for (int i = 0; i < len; i++) {
3119 CSSValue *item = list->item(i);
3120 if (!item->isPrimitiveValue()) continue;
3121 CSSPrimitiveValue *val = static_cast<CSSPrimitiveValue*>(item);
3123 Settings* settings = m_document->settings();
3124 if (val->primitiveType() == CSSPrimitiveValue::CSS_STRING)
3125 face = static_cast<FontFamilyValue*>(val)->fontName();
3126 else if (val->primitiveType() == CSSPrimitiveValue::CSS_IDENT && settings) {
3127 switch (val->getIdent()) {
3128 case CSS_VAL__WEBKIT_BODY:
3129 face = settings->standardFontFamily();
3132 face = "-webkit-serif";
3133 fontDescription.setGenericFamily(FontDescription::SerifFamily);
3135 case CSS_VAL_SANS_SERIF:
3136 face = "-webkit-sans-serif";
3137 fontDescription.setGenericFamily(FontDescription::SansSerifFamily);
3139 case CSS_VAL_CURSIVE:
3140 face = "-webkit-cursive";
3141 fontDescription.setGenericFamily(FontDescription::CursiveFamily);
3143 case CSS_VAL_FANTASY:
3144 face = "-webkit-fantasy";
3145 fontDescription.setGenericFamily(FontDescription::FantasyFamily);
3147 case CSS_VAL_MONOSPACE:
3148 face = "-webkit-monospace";
3149 fontDescription.setGenericFamily(FontDescription::MonospaceFamily);
3154 if (!face.isEmpty()) {
3156 // Filling in the first family.
3157 firstFamily.setFamily(face);
3158 currFamily = &firstFamily;
3161 FontFamily *newFamily = new FontFamily;
3162 newFamily->setFamily(face);
3163 currFamily->appendFamily(newFamily);
3164 currFamily = newFamily;
3167 if (fontDescription.keywordSize() && (fontDescription.genericFamily() == FontDescription::MonospaceFamily) != oldFamilyIsMonospace)
3168 setFontSize(fontDescription, fontSizeForKeyword(CSS_VAL_XX_SMALL + fontDescription.keywordSize() - 1, style->htmlHacks(), !oldFamilyIsMonospace));
3170 if (style->setFontDescription(fontDescription))
3176 case CSS_PROP_TEXT_DECORATION: {
3178 HANDLE_INHERIT_AND_INITIAL(textDecoration, TextDecoration)
3179 int t = RenderStyle::initialTextDecoration();
3180 if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_NONE) {
3183 if (!value->isValueList()) return;
3184 CSSValueList *list = static_cast<CSSValueList*>(value);
3185 int len = list->length();
3186 for (int i = 0; i < len; i++)
3188 CSSValue *item = list->item(i);
3189 if (!item->isPrimitiveValue()) continue;
3190 primitiveValue = static_cast<CSSPrimitiveValue*>(item);
3191 switch (primitiveValue->getIdent()) {
3194 case CSS_VAL_UNDERLINE:
3195 t |= UNDERLINE; break;
3196 case CSS_VAL_OVERLINE:
3197 t |= OVERLINE; break;
3198 case CSS_VAL_LINE_THROUGH:
3199 t |= LINE_THROUGH; break;
3208 style->setTextDecoration(t);
3212 // shorthand properties
3213 case CSS_PROP_BACKGROUND:
3215 style->clearBackgroundLayers();
3216 style->setBackgroundColor(Color());
3219 else if (isInherit) {
3220 style->inheritBackgroundLayers(*parentStyle->backgroundLayers());
3221 style->setBackgroundColor(parentStyle->backgroundColor());
3224 case CSS_PROP_BORDER:
3225 case CSS_PROP_BORDER_STYLE:
3226 case CSS_PROP_BORDER_WIDTH:
3227 case CSS_PROP_BORDER_COLOR:
3228 if (id == CSS_PROP_BORDER || id == CSS_PROP_BORDER_COLOR)
3231 style->setBorderTopColor(parentStyle->borderTopColor());
3232 style->setBorderBottomColor(parentStyle->borderBottomColor());
3233 style->setBorderLeftColor(parentStyle->borderLeftColor());
3234 style->setBorderRightColor(parentStyle->borderRightColor());
3236 else if (isInitial) {
3237 style->setBorderTopColor(Color()); // Reset to invalid color so currentColor is used instead.
3238 style->setBorderBottomColor(Color());
3239 style->setBorderLeftColor(Color());
3240 style->setBorderRightColor(Color());
3243 if (id == CSS_PROP_BORDER || id == CSS_PROP_BORDER_STYLE)
3246 style->setBorderTopStyle(parentStyle->borderTopStyle());
3247 style->setBorderBottomStyle(parentStyle->borderBottomStyle());
3248 style->setBorderLeftStyle(parentStyle->borderLeftStyle());
3249 style->setBorderRightStyle(parentStyle->borderRightStyle());
3251 else if (isInitial) {
3252 style->setBorderTopStyle(RenderStyle::initialBorderStyle());
3253 style->setBorderBottomStyle(RenderStyle::initialBorderStyle());
3254 style->setBorderLeftStyle(RenderStyle::initialBorderStyle());
3255 style->setBorderRightStyle(RenderStyle::initialBorderStyle());
3258 if (id == CSS_PROP_BORDER || id == CSS_PROP_BORDER_WIDTH)
3261 style->setBorderTopWidth(parentStyle->borderTopWidth());
3262 style->setBorderBottomWidth(parentStyle->borderBottomWidth());
3263 style->setBorderLeftWidth(parentStyle->borderLeftWidth());
3264 style->setBorderRightWidth(parentStyle->borderRightWidth());
3266 else if (isInitial) {
3267 style->setBorderTopWidth(RenderStyle::initialBorderWidth());
3268 style->setBorderBottomWidth(RenderStyle::initialBorderWidth());
3269 style->setBorderLeftWidth(RenderStyle::initialBorderWidth());
3270 style->setBorderRightWidth(RenderStyle::initialBorderWidth());
3274 case CSS_PROP_BORDER_TOP:
3276 style->setBorderTopColor(parentStyle->borderTopColor());
3277 style->setBorderTopStyle(parentStyle->borderTopStyle());
3278 style->setBorderTopWidth(parentStyle->borderTopWidth());
3281 style->resetBorderTop();
3283 case CSS_PROP_BORDER_RIGHT:
3285 style->setBorderRightColor(parentStyle->borderRightColor());
3286 style->setBorderRightStyle(parentStyle->borderRightStyle());
3287 style->setBorderRightWidth(parentStyle->borderRightWidth());