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 static void addLocalNameToSet(HashSet<AtomicStringImpl*>* set, const QualifiedName& qName)
1414 set->add(qName.localName().impl());
1417 static HashSet<AtomicStringImpl*>* createHtmlCaseInsensitiveAttributesSet()
1419 // This is the list of attributes in HTML 4.01 with values marked as "[CI]" or case-insensitive
1420 // Mozilla treats all other values as case-sensitive, thus so do we.
1421 HashSet<AtomicStringImpl*>* attrSet = new HashSet<AtomicStringImpl*>;
1423 addLocalNameToSet(attrSet, accept_charsetAttr);
1424 addLocalNameToSet(attrSet, acceptAttr);
1425 addLocalNameToSet(attrSet, alignAttr);
1426 addLocalNameToSet(attrSet, alinkAttr);
1427 addLocalNameToSet(attrSet, axisAttr);
1428 addLocalNameToSet(attrSet, bgcolorAttr);
1429 addLocalNameToSet(attrSet, charsetAttr);
1430 addLocalNameToSet(attrSet, checkedAttr);
1431 addLocalNameToSet(attrSet, clearAttr);
1432 addLocalNameToSet(attrSet, codetypeAttr);
1433 addLocalNameToSet(attrSet, colorAttr);
1434 addLocalNameToSet(attrSet, compactAttr);
1435 addLocalNameToSet(attrSet, declareAttr);
1436 addLocalNameToSet(attrSet, deferAttr);
1437 addLocalNameToSet(attrSet, dirAttr);
1438 addLocalNameToSet(attrSet, disabledAttr);
1439 addLocalNameToSet(attrSet, enctypeAttr);
1440 addLocalNameToSet(attrSet, faceAttr);
1441 addLocalNameToSet(attrSet, frameAttr);
1442 addLocalNameToSet(attrSet, hreflangAttr);
1443 addLocalNameToSet(attrSet, http_equivAttr);
1444 addLocalNameToSet(attrSet, langAttr);
1445 addLocalNameToSet(attrSet, languageAttr);
1446 addLocalNameToSet(attrSet, linkAttr);
1447 addLocalNameToSet(attrSet, mediaAttr);
1448 addLocalNameToSet(attrSet, methodAttr);
1449 addLocalNameToSet(attrSet, multipleAttr);
1450 addLocalNameToSet(attrSet, nohrefAttr);
1451 addLocalNameToSet(attrSet, noresizeAttr);
1452 addLocalNameToSet(attrSet, noshadeAttr);
1453 addLocalNameToSet(attrSet, nowrapAttr);
1454 addLocalNameToSet(attrSet, readonlyAttr);
1455 addLocalNameToSet(attrSet, relAttr);
1456 addLocalNameToSet(attrSet, revAttr);
1457 addLocalNameToSet(attrSet, rulesAttr);
1458 addLocalNameToSet(attrSet, scopeAttr);
1459 addLocalNameToSet(attrSet, scrollingAttr);
1460 addLocalNameToSet(attrSet, selectedAttr);
1461 addLocalNameToSet(attrSet, shapeAttr);
1462 addLocalNameToSet(attrSet, targetAttr);
1463 addLocalNameToSet(attrSet, textAttr);
1464 addLocalNameToSet(attrSet, typeAttr);
1465 addLocalNameToSet(attrSet, valignAttr);
1466 addLocalNameToSet(attrSet, valuetypeAttr);
1467 addLocalNameToSet(attrSet, vlinkAttr);
1472 static bool htmlAttributeHasCaseInsensitiveValue(const QualifiedName& attr)
1474 static HashSet<AtomicStringImpl*>* htmlCaseInsensitiveAttributesSet = createHtmlCaseInsensitiveAttributesSet();
1475 bool isPossibleHTMLAttr = !attr.hasPrefix() && (attr.namespaceURI() == nullAtom);
1476 return isPossibleHTMLAttr && htmlCaseInsensitiveAttributesSet->contains(attr.localName().impl());
1479 bool CSSStyleSelector::checkOneSelector(CSSSelector* sel, Element* e, bool isAncestor, bool isSubSelector)
1484 if (sel->hasTag()) {
1485 const AtomicString& localName = e->localName();
1486 const AtomicString& ns = e->namespaceURI();
1487 const AtomicString& selLocalName = sel->m_tag.localName();
1488 const AtomicString& selNS = sel->m_tag.namespaceURI();
1490 if ((selLocalName != starAtom && localName != selLocalName) ||
1491 (selNS != starAtom && ns != selNS))
1495 if (sel->hasAttribute()) {
1496 if (sel->m_match == CSSSelector::Class) {
1499 const ClassNames& classNames = *e->getClassNames();
1500 for (size_t i = 0; i < classNames.size(); ++i) {
1501 if (classNames[i] == sel->m_value)
1505 } else if (sel->m_match == CSSSelector::Id)
1506 return e->hasID() && e->getIDAttribute() == sel->m_value;
1507 else if (style && (e != element || !styledElement || (!styledElement->isMappedAttribute(sel->m_attr) && sel->m_attr != typeAttr && sel->m_attr != readonlyAttr))) {
1508 style->setAffectedByAttributeSelectors(); // Special-case the "type" and "readonly" attributes so input form controls can share style.
1509 m_selectorAttrs.add(sel->m_attr.localName().impl());
1512 const AtomicString& value = e->getAttribute(sel->m_attr);
1514 return false; // attribute is not set
1516 bool caseSensitive = isXMLDoc || !htmlAttributeHasCaseInsensitiveValue(sel->m_attr);
1518 switch (sel->m_match) {
1519 case CSSSelector::Exact:
1520 if (caseSensitive ? sel->m_value != value : !equalIgnoringCase(sel->m_value, value))
1523 case CSSSelector::List:
1525 // The selector's value can't contain a space, or it's totally bogus.
1526 if (sel->m_value.contains(' '))
1529 int startSearchAt = 0;
1531 int foundPos = value.find(sel->m_value, startSearchAt, caseSensitive);
1534 if (foundPos == 0 || value[foundPos-1] == ' ') {
1535 unsigned endStr = foundPos + sel->m_value.length();
1536 if (endStr == value.length() || value[endStr] == ' ')
1537 break; // We found a match.
1540 // No match. Keep looking.
1541 startSearchAt = foundPos + 1;
1545 case CSSSelector::Contain:
1546 if (!value.contains(sel->m_value, caseSensitive))
1549 case CSSSelector::Begin:
1550 if (!value.startsWith(sel->m_value, caseSensitive))
1553 case CSSSelector::End:
1554 if (!value.endsWith(sel->m_value, caseSensitive))
1557 case CSSSelector::Hyphen:
1558 if (value.length() < sel->m_value.length())
1560 if (!value.startsWith(sel->m_value, caseSensitive))
1562 // It they start the same, check for exact match or following '-':
1563 if (value.length() != sel->m_value.length() && value[sel->m_value.length()] != '-')
1566 case CSSSelector::PseudoClass:
1567 case CSSSelector::PseudoElement:
1572 if (sel->m_match == CSSSelector::PseudoClass) {
1573 switch (sel->pseudoType()) {
1575 case CSSSelector::PseudoEmpty:
1576 if (!e->firstChild())
1579 case CSSSelector::PseudoFirstChild: {
1580 // first-child matches the first child that is an element!
1581 if (e->parentNode() && e->parentNode()->isElementNode()) {
1582 Node *n = e->previousSibling();
1583 while (n && !n->isElementNode())
1584 n = n->previousSibling();
1590 case CSSSelector::PseudoFirstOfType: {
1591 // first-of-type matches the first element of its type!
1592 if (e->parentNode() && e->parentNode()->isElementNode()) {
1593 const QualifiedName& type = e->tagQName();
1594 Node *n = e->previousSibling();
1596 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
1598 n = n->previousSibling();
1605 case CSSSelector::PseudoTarget:
1606 if (e == e->document()->getCSSTarget())
1609 case CSSSelector::PseudoAnyLink:
1610 if (pseudoState == PseudoUnknown)
1611 checkPseudoState(e, false);
1612 if (pseudoState == PseudoAnyLink || pseudoState == PseudoLink || pseudoState == PseudoVisited)
1615 case CSSSelector::PseudoAutofill:
1616 if (e && e->hasTagName(inputTag))
1617 return static_cast<HTMLInputElement*>(e)->autofilled();
1619 case CSSSelector::PseudoLink:
1620 if (pseudoState == PseudoUnknown || pseudoState == PseudoAnyLink)
1621 checkPseudoState(e);
1622 if (pseudoState == PseudoLink)
1625 case CSSSelector::PseudoVisited:
1626 if (pseudoState == PseudoUnknown || pseudoState == PseudoAnyLink)
1627 checkPseudoState(e);
1628 if (pseudoState == PseudoVisited)
1631 case CSSSelector::PseudoDrag: {
1632 if (element == e && style)
1633 style->setAffectedByDragRules(true);
1634 if (element != e && e->renderStyle())
1635 e->renderStyle()->setAffectedByDragRules(true);
1636 if (e->renderer() && e->renderer()->isDragging())
1640 case CSSSelector::PseudoFocus:
1641 if (e && e->focused() && e->document()->frame()->isActive())
1644 case CSSSelector::PseudoHover: {
1645 // If we're in quirks mode, then hover should never match anchors with no
1646 // href and *:hover should not match anything. This is important for sites like wsj.com.
1647 if (strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {
1648 if (element == e && style)
1649 style->setAffectedByHoverRules(true);
1650 if (element != e && e->renderStyle())
1651 e->renderStyle()->setAffectedByHoverRules(true);
1657 case CSSSelector::PseudoActive:
1658 // If we're in quirks mode, then :active should never match anchors with no
1659 // href and *:active should not match anything.
1660 if (strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {
1661 if (element == e && style)
1662 style->setAffectedByActiveRules(true);
1663 else if (e->renderStyle())
1664 e->renderStyle()->setAffectedByActiveRules(true);
1669 case CSSSelector::PseudoEnabled:
1670 if (e && e->isControl() && !e->isInputTypeHidden())
1671 // The UI spec states that you can't match :enabled unless you are an object that can
1672 // "receive focus and be activated." We will limit matching of this pseudo-class to elements
1673 // that are non-"hidden" controls.
1674 return e->isEnabled();
1676 case CSSSelector::PseudoDisabled:
1677 if (e && e->isControl() && !e->isInputTypeHidden())
1678 // The UI spec states that you can't match :enabled unless you are an object that can
1679 // "receive focus and be activated." We will limit matching of this pseudo-class to elements
1680 // that are non-"hidden" controls.
1681 return !e->isEnabled();
1683 case CSSSelector::PseudoChecked:
1684 // Even though WinIE allows checked and indeterminate to co-exist, the CSS selector spec says that
1685 // you can't be both checked and indeterminate. We will behave like WinIE behind the scenes and just
1686 // obey the CSS spec here in the test for matching the pseudo.
1687 if (e && e->isChecked() && !e->isIndeterminate())
1690 case CSSSelector::PseudoIndeterminate:
1691 if (e && e->isIndeterminate())
1694 case CSSSelector::PseudoRoot:
1695 if (e == e->document()->documentElement())
1698 case CSSSelector::PseudoLang: {
1699 const AtomicString& value = e->getAttribute(langAttr);
1700 if (value.isEmpty() || !value.startsWith(sel->m_argument, false))
1702 if (value.length() != sel->m_argument.length() && value[sel->m_argument.length()] != '-')
1706 case CSSSelector::PseudoNot: {
1707 // check the simple selector
1708 for (CSSSelector* subSel = sel->m_simpleSelector; subSel; subSel = subSel->m_tagHistory) {
1709 // :not cannot nest. I don't really know why this is a
1710 // restriction in CSS3, but it is, so let's honour it.
1711 if (subSel->m_simpleSelector)
1713 if (!checkOneSelector(subSel, e, isAncestor, true))
1718 case CSSSelector::PseudoUnknown:
1719 case CSSSelector::PseudoNotParsed:
1721 ASSERT_NOT_REACHED();
1726 if (sel->m_match == CSSSelector::PseudoElement) {
1727 if (e != element) return false;
1729 switch (sel->pseudoType()) {
1731 case CSSSelector::PseudoFirstLine:
1732 dynamicPseudo = RenderStyle::FIRST_LINE;
1734 case CSSSelector::PseudoFirstLetter:
1735 dynamicPseudo = RenderStyle::FIRST_LETTER;
1736 if (Document* doc = e->document())
1737 doc->setUsesFirstLetterRules(true);
1739 case CSSSelector::PseudoSelection:
1740 dynamicPseudo = RenderStyle::SELECTION;
1742 case CSSSelector::PseudoBefore:
1743 dynamicPseudo = RenderStyle::BEFORE;
1745 case CSSSelector::PseudoAfter:
1746 dynamicPseudo = RenderStyle::AFTER;
1748 case CSSSelector::PseudoFileUploadButton:
1749 dynamicPseudo = RenderStyle::FILE_UPLOAD_BUTTON;
1751 case CSSSelector::PseudoSliderThumb:
1752 dynamicPseudo = RenderStyle::SLIDER_THUMB;
1754 case CSSSelector::PseudoSearchCancelButton:
1755 dynamicPseudo = RenderStyle::SEARCH_CANCEL_BUTTON;
1757 case CSSSelector::PseudoSearchDecoration:
1758 dynamicPseudo = RenderStyle::SEARCH_DECORATION;
1760 case CSSSelector::PseudoSearchResultsDecoration:
1761 dynamicPseudo = RenderStyle::SEARCH_RESULTS_DECORATION;
1763 case CSSSelector::PseudoSearchResultsButton:
1764 dynamicPseudo = RenderStyle::SEARCH_RESULTS_BUTTON;
1766 case CSSSelector::PseudoMediaControlsPanel:
1767 dynamicPseudo = RenderStyle::MEDIA_CONTROLS_PANEL;
1769 case CSSSelector::PseudoMediaControlsMuteButton:
1770 dynamicPseudo = RenderStyle::MEDIA_CONTROLS_MUTE_BUTTON;
1772 case CSSSelector::PseudoMediaControlsPlayButton:
1773 dynamicPseudo = RenderStyle::MEDIA_CONTROLS_PLAY_BUTTON;
1775 case CSSSelector::PseudoMediaControlsTimeDisplay:
1776 dynamicPseudo = RenderStyle::MEDIA_CONTROLS_TIME_DISPLAY;
1778 case CSSSelector::PseudoMediaControlsTimeline:
1779 dynamicPseudo = RenderStyle::MEDIA_CONTROLS_TIMELINE;
1781 case CSSSelector::PseudoUnknown:
1782 case CSSSelector::PseudoNotParsed:
1784 ASSERT_NOT_REACHED();
1789 // ### add the rest of the checks...
1793 // -----------------------------------------------------------------
1795 CSSRuleSet::CSSRuleSet()
1797 m_universalRules = 0;
1801 CSSRuleSet::~CSSRuleSet()
1803 deleteAllValues(m_idRules);
1804 deleteAllValues(m_classRules);
1805 deleteAllValues(m_tagRules);
1807 delete m_universalRules;
1811 void CSSRuleSet::addToRuleSet(AtomicStringImpl* key, AtomRuleMap& map,
1812 CSSStyleRule* rule, CSSSelector* sel)
1815 CSSRuleDataList* rules = map.get(key);
1817 rules = new CSSRuleDataList(m_ruleCount++, rule, sel);
1818 map.set(key, rules);
1820 rules->append(m_ruleCount++, rule, sel);
1823 void CSSRuleSet::addRule(CSSStyleRule* rule, CSSSelector* sel)
1825 if (sel->m_match == CSSSelector::Id) {
1826 addToRuleSet(sel->m_value.impl(), m_idRules, rule, sel);
1829 if (sel->m_match == CSSSelector::Class) {
1830 addToRuleSet(sel->m_value.impl(), m_classRules, rule, sel);
1834 const AtomicString& localName = sel->m_tag.localName();
1835 if (localName != starAtom) {
1836 addToRuleSet(localName.impl(), m_tagRules, rule, sel);
1840 // Just put it in the universal rule set.
1841 if (!m_universalRules)
1842 m_universalRules = new CSSRuleDataList(m_ruleCount++, rule, sel);
1844 m_universalRules->append(m_ruleCount++, rule, sel);
1847 void CSSRuleSet::addRulesFromSheet(CSSStyleSheet* sheet, const MediaQueryEvaluator& medium, CSSStyleSelector* styleSelector)
1849 if (!sheet || !sheet->isCSSStyleSheet())
1852 // No media implies "all", but if a media list exists it must
1853 // contain our current medium
1854 if (sheet->media() && !medium.eval(sheet->media()))
1855 return; // the style sheet doesn't apply
1857 int len = sheet->length();
1859 for (int i = 0; i < len; i++) {
1860 StyleBase* item = sheet->item(i);
1861 if (item->isStyleRule()) {
1862 CSSStyleRule* rule = static_cast<CSSStyleRule*>(item);
1863 for (CSSSelector* s = rule->selector(); s; s = s->next())
1866 else if (item->isImportRule()) {
1867 CSSImportRule* import = static_cast<CSSImportRule*>(item);
1868 if (!import->media() || medium.eval(import->media()))
1869 addRulesFromSheet(import->styleSheet(), medium, styleSelector);
1871 else if (item->isMediaRule()) {
1872 CSSMediaRule* r = static_cast<CSSMediaRule*>(item);
1873 CSSRuleList* rules = r->cssRules();
1875 if ((!r->media() || medium.eval(r->media())) && rules) {
1876 // Traverse child elements of the @media rule.
1877 for (unsigned j = 0; j < rules->length(); j++) {
1878 CSSRule *childItem = rules->item(j);
1879 if (childItem->isStyleRule()) {
1880 // It is a StyleRule, so append it to our list
1881 CSSStyleRule* rule = static_cast<CSSStyleRule*>(childItem);
1882 for (CSSSelector* s = rule->selector(); s; s = s->next())
1884 } else if (item->isFontFaceRule() && styleSelector) {
1885 // Add this font face to our set.
1886 const CSSFontFaceRule* fontFaceRule = static_cast<CSSFontFaceRule*>(item);
1887 styleSelector->fontSelector()->addFontFaceRule(fontFaceRule);
1891 } else if (item->isFontFaceRule() && styleSelector) {
1892 // Add this font face to our set.
1893 const CSSFontFaceRule* fontFaceRule = static_cast<CSSFontFaceRule*>(item);
1894 styleSelector->fontSelector()->addFontFaceRule(fontFaceRule);
1899 // -------------------------------------------------------------------------------------
1900 // this is mostly boring stuff on how to apply a certain rule to the renderstyle...
1902 static Length convertToLength(CSSPrimitiveValue *primitiveValue, RenderStyle *style, bool *ok = 0)
1905 if (!primitiveValue) {
1909 int type = primitiveValue->primitiveType();
1910 if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
1911 l = Length(primitiveValue->computeLengthIntForLength(style), Fixed);
1912 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
1913 l = Length(primitiveValue->getDoubleValue(), Percent);
1914 else if (type == CSSPrimitiveValue::CSS_NUMBER)
1915 l = Length(primitiveValue->getDoubleValue() * 100.0, Percent);
1922 void CSSStyleSelector::applyDeclarations(bool applyFirst, bool isImportant,
1923 int startIndex, int endIndex)
1925 if (startIndex == -1) return;
1926 for (int i = startIndex; i <= endIndex; i++) {
1927 CSSMutableStyleDeclaration* decl = m_matchedDecls[i];
1928 DeprecatedValueListConstIterator<CSSProperty> end;
1929 for (DeprecatedValueListConstIterator<CSSProperty> it = decl->valuesIterator(); it != end; ++it) {
1930 const CSSProperty& current = *it;
1931 // give special priority to font-xxx, color properties
1932 if (isImportant == current.isImportant()) {
1934 switch (current.id()) {
1935 case CSS_PROP_LINE_HEIGHT:
1936 m_lineHeightValue = current.value();
1937 first = !applyFirst; // we apply line-height later
1939 case CSS_PROP_COLOR:
1940 case CSS_PROP_DIRECTION:
1941 case CSS_PROP_DISPLAY:
1943 case CSS_PROP_FONT_SIZE:
1944 case CSS_PROP_FONT_STYLE:
1945 case CSS_PROP_FONT_FAMILY:
1946 case CSS_PROP_FONT_WEIGHT:
1947 case CSS_PROP__WEBKIT_TEXT_SIZE_ADJUST:
1948 case CSS_PROP_FONT_VARIANT:
1949 // these have to be applied first, because other properties use the computed
1950 // values of these porperties.
1957 if (first == applyFirst)
1958 applyProperty(current.id(), current.value());
1964 static void applyCounterList(RenderStyle* style, CSSValueList* list, bool isReset)
1966 CounterDirectiveMap& map = style->accessCounterDirectives();
1967 typedef CounterDirectiveMap::iterator Iterator;
1969 Iterator end = map.end();
1970 for (Iterator it = map.begin(); it != end; ++it)
1972 it->second.m_reset = false;
1974 it->second.m_increment = false;
1976 int length = list ? list->length() : 0;
1977 for (int i = 0; i < length; ++i) {
1978 Pair* pair = static_cast<CSSPrimitiveValue*>(list->item(i))->getPairValue();
1979 AtomicString identifier = static_cast<CSSPrimitiveValue*>(pair->first())->getStringValue();
1980 // FIXME: What about overflow?
1981 int value = static_cast<CSSPrimitiveValue*>(pair->second())->getIntValue();
1982 CounterDirectives& directives = map.add(identifier.impl(), CounterDirectives()).first->second;
1984 directives.m_reset = true;
1985 directives.m_resetValue = value;
1987 if (directives.m_increment)
1988 directives.m_incrementValue += value;
1990 directives.m_increment = true;
1991 directives.m_incrementValue = value;
1997 void CSSStyleSelector::applyProperty(int id, CSSValue *value)
1999 CSSPrimitiveValue* primitiveValue = 0;
2000 if (value->isPrimitiveValue())
2001 primitiveValue = static_cast<CSSPrimitiveValue*>(value);
2006 unsigned short valueType = value->cssValueType();
2008 bool isInherit = parentNode && valueType == CSSValue::CSS_INHERIT;
2009 bool isInitial = valueType == CSSValue::CSS_INITIAL || (!parentNode && valueType == CSSValue::CSS_INHERIT);
2011 // These properties are used to set the correct margins/padding on RTL lists.
2012 if (id == CSS_PROP__WEBKIT_MARGIN_START)
2013 id = style->direction() == LTR ? CSS_PROP_MARGIN_LEFT : CSS_PROP_MARGIN_RIGHT;
2014 else if (id == CSS_PROP__WEBKIT_PADDING_START)
2015 id = style->direction() == LTR ? CSS_PROP_PADDING_LEFT : CSS_PROP_PADDING_RIGHT;
2017 // What follows is a list that maps the CSS properties into their corresponding front-end
2018 // RenderStyle values. Shorthands (e.g. border, background) occur in this list as well and
2019 // are only hit when mapping "inherit" or "initial" into front-end values.
2020 switch (static_cast<CSSPropertyID>(id)) {
2021 // ident only properties
2022 case CSS_PROP_BACKGROUND_ATTACHMENT:
2023 HANDLE_BACKGROUND_VALUE(backgroundAttachment, BackgroundAttachment, value)
2025 case CSS_PROP__WEBKIT_BACKGROUND_CLIP:
2026 HANDLE_BACKGROUND_VALUE(backgroundClip, BackgroundClip, value)
2028 case CSS_PROP__WEBKIT_BACKGROUND_COMPOSITE:
2029 HANDLE_BACKGROUND_VALUE(backgroundComposite, BackgroundComposite, value)
2031 case CSS_PROP__WEBKIT_BACKGROUND_ORIGIN:
2032 HANDLE_BACKGROUND_VALUE(backgroundOrigin, BackgroundOrigin, value)
2034 case CSS_PROP_BACKGROUND_REPEAT:
2035 HANDLE_BACKGROUND_VALUE(backgroundRepeat, BackgroundRepeat, value)
2037 case CSS_PROP__WEBKIT_BACKGROUND_SIZE:
2038 HANDLE_BACKGROUND_VALUE(backgroundSize, BackgroundSize, value)
2040 case CSS_PROP_BORDER_COLLAPSE:
2041 HANDLE_INHERIT_AND_INITIAL(borderCollapse, BorderCollapse)
2042 if (!primitiveValue)
2044 switch (primitiveValue->getIdent()) {
2045 case CSS_VAL_COLLAPSE:
2046 style->setBorderCollapse(true);
2048 case CSS_VAL_SEPARATE:
2049 style->setBorderCollapse(false);
2056 case CSS_PROP_BORDER_TOP_STYLE:
2057 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderTopStyle, BorderTopStyle, BorderStyle)
2059 style->setBorderTopStyle(*primitiveValue);
2061 case CSS_PROP_BORDER_RIGHT_STYLE:
2062 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderRightStyle, BorderRightStyle, BorderStyle)
2064 style->setBorderRightStyle(*primitiveValue);
2066 case CSS_PROP_BORDER_BOTTOM_STYLE:
2067 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderBottomStyle, BorderBottomStyle, BorderStyle)
2069 style->setBorderBottomStyle(*primitiveValue);
2071 case CSS_PROP_BORDER_LEFT_STYLE:
2072 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderLeftStyle, BorderLeftStyle, BorderStyle)
2074 style->setBorderLeftStyle(*primitiveValue);
2076 case CSS_PROP_OUTLINE_STYLE:
2077 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(outlineStyle, OutlineStyle, BorderStyle)
2078 if (primitiveValue) {
2079 if (primitiveValue->getIdent() == CSS_VAL_AUTO)
2080 style->setOutlineStyle(DOTTED, true);
2082 style->setOutlineStyle(*primitiveValue);
2085 case CSS_PROP_CAPTION_SIDE:
2087 HANDLE_INHERIT_AND_INITIAL(captionSide, CaptionSide)
2089 style->setCaptionSide(*primitiveValue);
2092 case CSS_PROP_CLEAR:
2094 HANDLE_INHERIT_AND_INITIAL(clear, Clear)
2096 style->setClear(*primitiveValue);
2099 case CSS_PROP_DIRECTION:
2101 HANDLE_INHERIT_AND_INITIAL(direction, Direction)
2103 style->setDirection(*primitiveValue);
2106 case CSS_PROP_DISPLAY:
2108 HANDLE_INHERIT_AND_INITIAL(display, Display)
2110 style->setDisplay(*primitiveValue);
2114 case CSS_PROP_EMPTY_CELLS:
2116 HANDLE_INHERIT_AND_INITIAL(emptyCells, EmptyCells)
2118 style->setEmptyCells(*primitiveValue);
2121 case CSS_PROP_FLOAT:
2123 HANDLE_INHERIT_AND_INITIAL(floating, Floating)
2125 style->setFloating(*primitiveValue);
2129 case CSS_PROP_FONT_STYLE:
2131 FontDescription fontDescription = style->fontDescription();
2133 fontDescription.setItalic(parentStyle->fontDescription().italic());
2135 fontDescription.setItalic(false);
2137 if (!primitiveValue)
2139 switch (primitiveValue->getIdent()) {
2140 case CSS_VAL_OBLIQUE:
2141 // FIXME: oblique is the same as italic for the moment...
2142 case CSS_VAL_ITALIC:
2143 fontDescription.setItalic(true);
2145 case CSS_VAL_NORMAL:
2146 fontDescription.setItalic(false);
2152 if (style->setFontDescription(fontDescription))
2157 case CSS_PROP_FONT_VARIANT:
2159 FontDescription fontDescription = style->fontDescription();
2161 fontDescription.setSmallCaps(parentStyle->fontDescription().smallCaps());
2163 fontDescription.setSmallCaps(false);
2165 if (!primitiveValue)
2167 int id = primitiveValue->getIdent();
2168 if (id == CSS_VAL_NORMAL)
2169 fontDescription.setSmallCaps(false);
2170 else if (id == CSS_VAL_SMALL_CAPS)
2171 fontDescription.setSmallCaps(true);
2175 if (style->setFontDescription(fontDescription))
2180 case CSS_PROP_FONT_WEIGHT:
2182 FontDescription fontDescription = style->fontDescription();
2184 fontDescription.setWeight(parentStyle->fontDescription().weight());
2186 fontDescription.setWeight(cNormalWeight);
2188 if (!primitiveValue)
2190 if (primitiveValue->getIdent()) {
2191 switch (primitiveValue->getIdent()) {
2192 // FIXME: We aren't genuinely supporting specific weight values.
2194 case CSS_VAL_BOLDER:
2199 fontDescription.setWeight(cBoldWeight);
2201 case CSS_VAL_NORMAL:
2202 case CSS_VAL_LIGHTER:
2208 fontDescription.setWeight(cNormalWeight);
2216 // ### fix parsing of 100-900 values in parser, apply them here
2219 if (style->setFontDescription(fontDescription))
2224 case CSS_PROP_LIST_STYLE_POSITION:
2226 HANDLE_INHERIT_AND_INITIAL(listStylePosition, ListStylePosition)
2228 style->setListStylePosition(*primitiveValue);
2232 case CSS_PROP_LIST_STYLE_TYPE:
2234 HANDLE_INHERIT_AND_INITIAL(listStyleType, ListStyleType)
2236 style->setListStyleType(*primitiveValue);
2240 case CSS_PROP_OVERFLOW:
2243 style->setOverflowX(parentStyle->overflowX());
2244 style->setOverflowY(parentStyle->overflowY());
2249 style->setOverflowX(RenderStyle::initialOverflowX());
2250 style->setOverflowY(RenderStyle::initialOverflowY());
2254 EOverflow o = *primitiveValue;
2256 style->setOverflowX(o);
2257 style->setOverflowY(o);
2261 case CSS_PROP_OVERFLOW_X:
2263 HANDLE_INHERIT_AND_INITIAL(overflowX, OverflowX)
2264 style->setOverflowX(*primitiveValue);
2268 case CSS_PROP_OVERFLOW_Y:
2270 HANDLE_INHERIT_AND_INITIAL(overflowY, OverflowY)
2271 style->setOverflowY(*primitiveValue);
2275 case CSS_PROP_PAGE_BREAK_BEFORE:
2277 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(pageBreakBefore, PageBreakBefore, PageBreak)
2279 style->setPageBreakBefore(*primitiveValue);
2283 case CSS_PROP_PAGE_BREAK_AFTER:
2285 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(pageBreakAfter, PageBreakAfter, PageBreak)
2287 style->setPageBreakAfter(*primitiveValue);
2291 case CSS_PROP_PAGE_BREAK_INSIDE: {
2292 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(pageBreakInside, PageBreakInside, PageBreak)
2293 if (!primitiveValue)
2295 EPageBreak pageBreak = *primitiveValue;
2296 if (pageBreak != PBALWAYS)
2297 style->setPageBreakInside(pageBreak);
2301 case CSS_PROP_POSITION:
2303 HANDLE_INHERIT_AND_INITIAL(position, Position)
2305 style->setPosition(*primitiveValue);
2309 case CSS_PROP_TABLE_LAYOUT: {
2310 HANDLE_INHERIT_AND_INITIAL(tableLayout, TableLayout)
2312 ETableLayout l = *primitiveValue;
2314 l = RenderStyle::initialTableLayout();
2316 style->setTableLayout(l);
2320 case CSS_PROP_UNICODE_BIDI: {
2321 HANDLE_INHERIT_AND_INITIAL(unicodeBidi, UnicodeBidi)
2322 style->setUnicodeBidi(*primitiveValue);
2325 case CSS_PROP_TEXT_TRANSFORM: {
2326 HANDLE_INHERIT_AND_INITIAL(textTransform, TextTransform)
2327 style->setTextTransform(*primitiveValue);
2331 case CSS_PROP_VISIBILITY:
2333 HANDLE_INHERIT_AND_INITIAL(visibility, Visibility)
2334 style->setVisibility(*primitiveValue);
2337 case CSS_PROP_WHITE_SPACE:
2338 HANDLE_INHERIT_AND_INITIAL(whiteSpace, WhiteSpace)
2339 style->setWhiteSpace(*primitiveValue);
2342 case CSS_PROP_BACKGROUND_POSITION:
2343 HANDLE_BACKGROUND_INHERIT_AND_INITIAL(backgroundXPosition, BackgroundXPosition);
2344 HANDLE_BACKGROUND_INHERIT_AND_INITIAL(backgroundYPosition, BackgroundYPosition);
2346 case CSS_PROP_BACKGROUND_POSITION_X: {
2347 HANDLE_BACKGROUND_VALUE(backgroundXPosition, BackgroundXPosition, value)
2350 case CSS_PROP_BACKGROUND_POSITION_Y: {
2351 HANDLE_BACKGROUND_VALUE(backgroundYPosition, BackgroundYPosition, value)
2354 case CSS_PROP_BORDER_SPACING: {
2356 style->setHorizontalBorderSpacing(parentStyle->horizontalBorderSpacing());
2357 style->setVerticalBorderSpacing(parentStyle->verticalBorderSpacing());
2359 else if (isInitial) {
2360 style->setHorizontalBorderSpacing(0);
2361 style->setVerticalBorderSpacing(0);
2365 case CSS_PROP__WEBKIT_BORDER_HORIZONTAL_SPACING: {
2366 HANDLE_INHERIT_AND_INITIAL(horizontalBorderSpacing, HorizontalBorderSpacing)
2367 if (!primitiveValue)
2369 short spacing = primitiveValue->computeLengthShort(style);
2370 style->setHorizontalBorderSpacing(spacing);
2373 case CSS_PROP__WEBKIT_BORDER_VERTICAL_SPACING: {
2374 HANDLE_INHERIT_AND_INITIAL(verticalBorderSpacing, VerticalBorderSpacing)
2375 if (!primitiveValue)
2377 short spacing = primitiveValue->computeLengthShort(style);
2378 style->setVerticalBorderSpacing(spacing);
2381 case CSS_PROP_CURSOR:
2383 style->setCursor(parentStyle->cursor());
2384 style->setCursorList(parentStyle->cursors());
2387 style->clearCursorList();
2389 style->setCursor(RenderStyle::initialCursor());
2392 if (value->isValueList()) {
2393 CSSValueList* list = static_cast<CSSValueList*>(value);
2394 int len = list->length();
2395 style->setCursor(CURSOR_AUTO);
2396 for (int i = 0; i < len; i++) {
2397 CSSValue* item = list->item(i);
2398 if (!item->isPrimitiveValue())
2400 primitiveValue = static_cast<CSSPrimitiveValue*>(item);
2401 int type = primitiveValue->primitiveType();
2402 if (type == CSSPrimitiveValue::CSS_URI) {
2404 if (primitiveValue->getStringValue().find("#") == 0)
2405 style->addSVGCursor(primitiveValue->getStringValue().substring(1));
2409 CSSCursorImageValue* image = static_cast<CSSCursorImageValue*>(primitiveValue);
2410 style->addCursor(image->image(element->document()->docLoader()), image->hotspot());
2412 } else if (type == CSSPrimitiveValue::CSS_IDENT)
2413 style->setCursor(*primitiveValue);
2415 } else if (primitiveValue) {
2416 int type = primitiveValue->primitiveType();
2417 if (type == CSSPrimitiveValue::CSS_IDENT)
2418 style->setCursor(*primitiveValue);
2421 // colors || inherit
2422 case CSS_PROP_BACKGROUND_COLOR:
2423 case CSS_PROP_BORDER_TOP_COLOR:
2424 case CSS_PROP_BORDER_RIGHT_COLOR:
2425 case CSS_PROP_BORDER_BOTTOM_COLOR:
2426 case CSS_PROP_BORDER_LEFT_COLOR:
2427 case CSS_PROP_COLOR:
2428 case CSS_PROP_OUTLINE_COLOR:
2429 case CSS_PROP__WEBKIT_COLUMN_RULE_COLOR:
2430 case CSS_PROP__WEBKIT_TEXT_STROKE_COLOR:
2431 case CSS_PROP__WEBKIT_TEXT_FILL_COLOR: {
2434 HANDLE_INHERIT_COND(CSS_PROP_BACKGROUND_COLOR, backgroundColor, BackgroundColor)
2435 HANDLE_INHERIT_COND(CSS_PROP_BORDER_TOP_COLOR, borderTopColor, BorderTopColor)
2436 HANDLE_INHERIT_COND(CSS_PROP_BORDER_BOTTOM_COLOR, borderBottomColor, BorderBottomColor)
2437 HANDLE_INHERIT_COND(CSS_PROP_BORDER_RIGHT_COLOR, borderRightColor, BorderRightColor)
2438 HANDLE_INHERIT_COND(CSS_PROP_BORDER_LEFT_COLOR, borderLeftColor, BorderLeftColor)
2439 HANDLE_INHERIT_COND(CSS_PROP_COLOR, color, Color)
2440 HANDLE_INHERIT_COND(CSS_PROP_OUTLINE_COLOR, outlineColor, OutlineColor)
2441 HANDLE_INHERIT_COND(CSS_PROP__WEBKIT_COLUMN_RULE_COLOR, columnRuleColor, ColumnRuleColor)
2442 HANDLE_INHERIT_COND(CSS_PROP__WEBKIT_TEXT_STROKE_COLOR, textStrokeColor, TextStrokeColor)
2443 HANDLE_INHERIT_COND(CSS_PROP__WEBKIT_TEXT_FILL_COLOR, textFillColor, TextFillColor)
2447 // The border/outline colors will just map to the invalid color |col| above. This will have the
2448 // effect of forcing the use of the currentColor when it comes time to draw the borders (and of
2449 // not painting the background since the color won't be valid).
2450 if (id == CSS_PROP_COLOR)
2451 col = RenderStyle::initialColor();
2453 if (!primitiveValue)
2455 col = getColorFromPrimitiveValue(primitiveValue);
2459 case CSS_PROP_BACKGROUND_COLOR:
2460 style->setBackgroundColor(col); break;
2461 case CSS_PROP_BORDER_TOP_COLOR:
2462 style->setBorderTopColor(col); break;
2463 case CSS_PROP_BORDER_RIGHT_COLOR:
2464 style->setBorderRightColor(col); break;
2465 case CSS_PROP_BORDER_BOTTOM_COLOR:
2466 style->setBorderBottomColor(col); break;
2467 case CSS_PROP_BORDER_LEFT_COLOR:
2468 style->setBorderLeftColor(col); break;
2469 case CSS_PROP_COLOR:
2470 style->setColor(col); break;
2471 case CSS_PROP_OUTLINE_COLOR:
2472 style->setOutlineColor(col); break;
2473 case CSS_PROP__WEBKIT_COLUMN_RULE_COLOR:
2474 style->setColumnRuleColor(col);
2476 case CSS_PROP__WEBKIT_TEXT_STROKE_COLOR:
2477 style->setTextStrokeColor(col);
2479 case CSS_PROP__WEBKIT_TEXT_FILL_COLOR:
2480 style->setTextFillColor(col);
2488 case CSS_PROP_BACKGROUND_IMAGE:
2489 HANDLE_BACKGROUND_VALUE(backgroundImage, BackgroundImage, value)
2491 case CSS_PROP_LIST_STYLE_IMAGE:
2493 HANDLE_INHERIT_AND_INITIAL(listStyleImage, ListStyleImage)
2494 if (!primitiveValue)
2496 style->setListStyleImage(static_cast<CSSImageValue*>(primitiveValue)->image(element->document()->docLoader()));
2501 case CSS_PROP_BORDER_TOP_WIDTH:
2502 case CSS_PROP_BORDER_RIGHT_WIDTH:
2503 case CSS_PROP_BORDER_BOTTOM_WIDTH:
2504 case CSS_PROP_BORDER_LEFT_WIDTH:
2505 case CSS_PROP_OUTLINE_WIDTH:
2506 case CSS_PROP__WEBKIT_COLUMN_RULE_WIDTH:
2509 HANDLE_INHERIT_COND(CSS_PROP_BORDER_TOP_WIDTH, borderTopWidth, BorderTopWidth)
2510 HANDLE_INHERIT_COND(CSS_PROP_BORDER_RIGHT_WIDTH, borderRightWidth, BorderRightWidth)
2511 HANDLE_INHERIT_COND(CSS_PROP_BORDER_BOTTOM_WIDTH, borderBottomWidth, BorderBottomWidth)
2512 HANDLE_INHERIT_COND(CSS_PROP_BORDER_LEFT_WIDTH, borderLeftWidth, BorderLeftWidth)
2513 HANDLE_INHERIT_COND(CSS_PROP_OUTLINE_WIDTH, outlineWidth, OutlineWidth)
2514 HANDLE_INHERIT_COND(CSS_PROP__WEBKIT_COLUMN_RULE_WIDTH, columnRuleWidth, ColumnRuleWidth)
2517 else if (isInitial) {
2518 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_TOP_WIDTH, BorderTopWidth, BorderWidth)
2519 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_RIGHT_WIDTH, BorderRightWidth, BorderWidth)
2520 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_BOTTOM_WIDTH, BorderBottomWidth, BorderWidth)
2521 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BORDER_LEFT_WIDTH, BorderLeftWidth, BorderWidth)
2522 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_OUTLINE_WIDTH, OutlineWidth, BorderWidth)
2523 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP__WEBKIT_COLUMN_RULE_WIDTH, ColumnRuleWidth, BorderWidth)
2527 if (!primitiveValue)
2530 switch (primitiveValue->getIdent()) {
2534 case CSS_VAL_MEDIUM:
2540 case CSS_VAL_INVALID:
2541 width = primitiveValue->computeLengthShort(style);
2547 if (width < 0) return;
2549 case CSS_PROP_BORDER_TOP_WIDTH:
2550 style->setBorderTopWidth(width);
2552 case CSS_PROP_BORDER_RIGHT_WIDTH:
2553 style->setBorderRightWidth(width);
2555 case CSS_PROP_BORDER_BOTTOM_WIDTH:
2556 style->setBorderBottomWidth(width);
2558 case CSS_PROP_BORDER_LEFT_WIDTH:
2559 style->setBorderLeftWidth(width);
2561 case CSS_PROP_OUTLINE_WIDTH:
2562 style->setOutlineWidth(width);
2564 case CSS_PROP__WEBKIT_COLUMN_RULE_WIDTH:
2565 style->setColumnRuleWidth(width);
2573 case CSS_PROP_LETTER_SPACING:
2574 case CSS_PROP_WORD_SPACING:
2578 HANDLE_INHERIT_COND(CSS_PROP_LETTER_SPACING, letterSpacing, LetterSpacing)
2579 HANDLE_INHERIT_COND(CSS_PROP_WORD_SPACING, wordSpacing, WordSpacing)
2582 else if (isInitial) {
2583 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_LETTER_SPACING, LetterSpacing, LetterWordSpacing)
2584 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_WORD_SPACING, WordSpacing, LetterWordSpacing)
2589 if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_NORMAL){
2592 if (!primitiveValue)
2594 width = primitiveValue->computeLengthInt(style);
2597 case CSS_PROP_LETTER_SPACING:
2598 style->setLetterSpacing(width);
2600 case CSS_PROP_WORD_SPACING:
2601 style->setWordSpacing(width);
2603 // ### needs the definitions in renderstyle
2609 case CSS_PROP_WORD_BREAK: {
2610 HANDLE_INHERIT_AND_INITIAL(wordBreak, WordBreak)
2611 style->setWordBreak(*primitiveValue);
2615 case CSS_PROP_WORD_WRAP: {
2616 HANDLE_INHERIT_AND_INITIAL(wordWrap, WordWrap)
2617 style->setWordWrap(*primitiveValue);
2621 case CSS_PROP__WEBKIT_NBSP_MODE:
2623 HANDLE_INHERIT_AND_INITIAL(nbspMode, NBSPMode)
2624 style->setNBSPMode(*primitiveValue);
2628 case CSS_PROP__WEBKIT_LINE_BREAK:
2630 HANDLE_INHERIT_AND_INITIAL(khtmlLineBreak, KHTMLLineBreak)
2631 style->setKHTMLLineBreak(*primitiveValue);
2635 case CSS_PROP__WEBKIT_MATCH_NEAREST_MAIL_BLOCKQUOTE_COLOR:
2637 HANDLE_INHERIT_AND_INITIAL(matchNearestMailBlockquoteColor, MatchNearestMailBlockquoteColor)
2638 style->setMatchNearestMailBlockquoteColor(*primitiveValue);
2642 case CSS_PROP_RESIZE:
2644 HANDLE_INHERIT_AND_INITIAL(resize, Resize)
2646 if (!primitiveValue->getIdent())
2649 EResize r = RESIZE_NONE;
2650 if (primitiveValue->getIdent() == CSS_VAL_AUTO) {
2651 if (Settings* settings = m_document->settings())
2652 r = settings->textAreasAreResizable() ? RESIZE_BOTH : RESIZE_NONE;
2654 r = *primitiveValue;
2656 style->setResize(r);
2661 case CSS_PROP_MAX_WIDTH:
2663 if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_NONE)
2667 case CSS_PROP_RIGHT:
2668 case CSS_PROP_BOTTOM:
2669 case CSS_PROP_WIDTH:
2670 case CSS_PROP_MIN_WIDTH:
2671 case CSS_PROP_MARGIN_TOP:
2672 case CSS_PROP_MARGIN_RIGHT:
2673 case CSS_PROP_MARGIN_BOTTOM:
2674 case CSS_PROP_MARGIN_LEFT:
2676 if (id == CSS_PROP_WIDTH || id == CSS_PROP_MIN_WIDTH || id == CSS_PROP_MAX_WIDTH) {
2677 if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_INTRINSIC) {
2678 l = Length(Intrinsic);
2681 else if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_MIN_INTRINSIC) {
2682 l = Length(MinIntrinsic);
2686 if (id != CSS_PROP_MAX_WIDTH && primitiveValue && primitiveValue->getIdent() == CSS_VAL_AUTO)
2688 case CSS_PROP_PADDING_TOP:
2689 case CSS_PROP_PADDING_RIGHT:
2690 case CSS_PROP_PADDING_BOTTOM:
2691 case CSS_PROP_PADDING_LEFT:
2692 case CSS_PROP_TEXT_INDENT:
2696 HANDLE_INHERIT_COND(CSS_PROP_MAX_WIDTH, maxWidth, MaxWidth)
2697 HANDLE_INHERIT_COND(CSS_PROP_BOTTOM, bottom, Bottom)
2698 HANDLE_INHERIT_COND(CSS_PROP_TOP, top, Top)
2699 HANDLE_INHERIT_COND(CSS_PROP_LEFT, left, Left)
2700 HANDLE_INHERIT_COND(CSS_PROP_RIGHT, right, Right)
2701 HANDLE_INHERIT_COND(CSS_PROP_WIDTH, width, Width)
2702 HANDLE_INHERIT_COND(CSS_PROP_MIN_WIDTH, minWidth, MinWidth)
2703 HANDLE_INHERIT_COND(CSS_PROP_PADDING_TOP, paddingTop, PaddingTop)
2704 HANDLE_INHERIT_COND(CSS_PROP_PADDING_RIGHT, paddingRight, PaddingRight)
2705 HANDLE_INHERIT_COND(CSS_PROP_PADDING_BOTTOM, paddingBottom, PaddingBottom)
2706 HANDLE_INHERIT_COND(CSS_PROP_PADDING_LEFT, paddingLeft, PaddingLeft)
2707 HANDLE_INHERIT_COND(CSS_PROP_MARGIN_TOP, marginTop, MarginTop)
2708 HANDLE_INHERIT_COND(CSS_PROP_MARGIN_RIGHT, marginRight, MarginRight)
2709 HANDLE_INHERIT_COND(CSS_PROP_MARGIN_BOTTOM, marginBottom, MarginBottom)
2710 HANDLE_INHERIT_COND(CSS_PROP_MARGIN_LEFT, marginLeft, MarginLeft)
2711 HANDLE_INHERIT_COND(CSS_PROP_TEXT_INDENT, textIndent, TextIndent)
2714 else if (isInitial) {
2715 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MAX_WIDTH, MaxWidth, MaxSize)
2716 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_BOTTOM, Bottom, Offset)
2717 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_TOP, Top, Offset)
2718 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_LEFT, Left, Offset)
2719 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_RIGHT, Right, Offset)
2720 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_WIDTH, Width, Size)
2721 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MIN_WIDTH, MinWidth, MinSize)
2722 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_PADDING_TOP, PaddingTop, Padding)
2723 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_PADDING_RIGHT, PaddingRight, Padding)
2724 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_PADDING_BOTTOM, PaddingBottom, Padding)
2725 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_PADDING_LEFT, PaddingLeft, Padding)
2726 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MARGIN_TOP, MarginTop, Margin)
2727 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MARGIN_RIGHT, MarginRight, Margin)
2728 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MARGIN_BOTTOM, MarginBottom, Margin)
2729 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MARGIN_LEFT, MarginLeft, Margin)
2730 HANDLE_INITIAL_COND(CSS_PROP_TEXT_INDENT, TextIndent)
2734 if (primitiveValue && !apply) {
2735 int type = primitiveValue->primitiveType();
2736 if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
2737 // Handle our quirky margin units if we have them.
2738 l = Length(primitiveValue->computeLengthIntForLength(style), Fixed,
2739 primitiveValue->isQuirkValue());
2740 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
2741 l = Length(primitiveValue->getDoubleValue(), Percent);
2744 if (id == CSS_PROP_PADDING_LEFT || id == CSS_PROP_PADDING_RIGHT ||
2745 id == CSS_PROP_PADDING_TOP || id == CSS_PROP_PADDING_BOTTOM)
2746 // Padding can't be negative
2747 apply = !((l.isFixed() || l.isPercent()) && l.calcValue(100) < 0);
2753 case CSS_PROP_MAX_WIDTH:
2754 style->setMaxWidth(l); break;
2755 case CSS_PROP_BOTTOM:
2756 style->setBottom(l); break;
2758 style->setTop(l); break;
2760 style->setLeft(l); break;
2761 case CSS_PROP_RIGHT:
2762 style->setRight(l); break;
2763 case CSS_PROP_WIDTH:
2764 style->setWidth(l); break;
2765 case CSS_PROP_MIN_WIDTH:
2766 style->setMinWidth(l); break;
2767 case CSS_PROP_PADDING_TOP:
2768 style->setPaddingTop(l); break;
2769 case CSS_PROP_PADDING_RIGHT:
2770 style->setPaddingRight(l); break;
2771 case CSS_PROP_PADDING_BOTTOM:
2772 style->setPaddingBottom(l); break;
2773 case CSS_PROP_PADDING_LEFT:
2774 style->setPaddingLeft(l); break;
2775 case CSS_PROP_MARGIN_TOP:
2776 style->setMarginTop(l); break;
2777 case CSS_PROP_MARGIN_RIGHT:
2778 style->setMarginRight(l); break;
2779 case CSS_PROP_MARGIN_BOTTOM:
2780 style->setMarginBottom(l); break;
2781 case CSS_PROP_MARGIN_LEFT:
2782 style->setMarginLeft(l); break;
2783 case CSS_PROP_TEXT_INDENT:
2784 style->setTextIndent(l); break;
2790 case CSS_PROP_MAX_HEIGHT:
2791 if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_NONE) {
2792 l = Length(undefinedLength, Fixed);
2795 case CSS_PROP_HEIGHT:
2796 case CSS_PROP_MIN_HEIGHT:
2797 if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_INTRINSIC) {
2798 l = Length(Intrinsic);
2800 } else if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_MIN_INTRINSIC) {
2801 l = Length(MinIntrinsic);
2803 } else if (id != CSS_PROP_MAX_HEIGHT && primitiveValue && primitiveValue->getIdent() == CSS_VAL_AUTO)
2806 HANDLE_INHERIT_COND(CSS_PROP_MAX_HEIGHT, maxHeight, MaxHeight)
2807 HANDLE_INHERIT_COND(CSS_PROP_HEIGHT, height, Height)
2808 HANDLE_INHERIT_COND(CSS_PROP_MIN_HEIGHT, minHeight, MinHeight)
2812 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MAX_HEIGHT, MaxHeight, MaxSize)
2813 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_HEIGHT, Height, Size)
2814 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_MIN_HEIGHT, MinHeight, MinSize)
2818 if (primitiveValue && !apply) {
2819 unsigned short type = primitiveValue->primitiveType();
2820 if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
2821 l = Length(primitiveValue->computeLengthIntForLength(style), Fixed);
2822 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
2823 l = Length(primitiveValue->getDoubleValue(), Percent);
2830 case CSS_PROP_MAX_HEIGHT:
2831 style->setMaxHeight(l);
2833 case CSS_PROP_HEIGHT:
2834 style->setHeight(l);
2836 case CSS_PROP_MIN_HEIGHT:
2837 style->setMinHeight(l);
2842 case CSS_PROP_VERTICAL_ALIGN:
2843 HANDLE_INHERIT_AND_INITIAL(verticalAlign, VerticalAlign)
2844 if (!primitiveValue)
2846 if (primitiveValue->getIdent()) {
2847 EVerticalAlign align;
2849 switch (primitiveValue->getIdent()) {
2852 case CSS_VAL_BOTTOM:
2853 align = BOTTOM; break;
2854 case CSS_VAL_MIDDLE:
2855 align = MIDDLE; break;
2856 case CSS_VAL_BASELINE:
2857 align = BASELINE; break;
2858 case CSS_VAL_TEXT_BOTTOM:
2859 align = TEXT_BOTTOM; break;
2860 case CSS_VAL_TEXT_TOP:
2861 align = TEXT_TOP; break;
2865 align = SUPER; break;
2866 case CSS_VAL__WEBKIT_BASELINE_MIDDLE:
2867 align = BASELINE_MIDDLE; break;
2871 style->setVerticalAlign(align);
2874 int type = primitiveValue->primitiveType();
2876 if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
2877 l = Length(primitiveValue->computeLengthIntForLength(style), Fixed);
2878 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
2879 l = Length(primitiveValue->getDoubleValue(), Percent);
2881 style->setVerticalAlign(LENGTH);
2882 style->setVerticalAlignLength(l);
2886 case CSS_PROP_FONT_SIZE:
2888 FontDescription fontDescription = style->fontDescription();
2889 fontDescription.setKeywordSize(0);
2890 bool familyIsFixed = fontDescription.genericFamily() == FontDescription::MonospaceFamily;
2894 bool parentIsAbsoluteSize = false;
2896 oldSize = parentStyle->fontDescription().specifiedSize();
2897 parentIsAbsoluteSize = parentStyle->fontDescription().isAbsoluteSize();
2903 fontDescription.setKeywordSize(parentStyle->fontDescription().keywordSize());
2904 } else if (isInitial) {
2905 size = fontSizeForKeyword(CSS_VAL_MEDIUM, style->htmlHacks(), familyIsFixed);
2906 fontDescription.setKeywordSize(CSS_VAL_MEDIUM - CSS_VAL_XX_SMALL + 1);
2907 } else if (primitiveValue->getIdent()) {
2908 // Keywords are being used.
2909 switch (primitiveValue->getIdent()) {
2910 case CSS_VAL_XX_SMALL:
2911 case CSS_VAL_X_SMALL:
2913 case CSS_VAL_MEDIUM:
2915 case CSS_VAL_X_LARGE:
2916 case CSS_VAL_XX_LARGE:
2917 case CSS_VAL__WEBKIT_XXX_LARGE:
2918 size = fontSizeForKeyword(primitiveValue->getIdent(), style->htmlHacks(), familyIsFixed);
2919 fontDescription.setKeywordSize(primitiveValue->getIdent() - CSS_VAL_XX_SMALL + 1);
2921 case CSS_VAL_LARGER:
2922 size = largerFontSize(oldSize, style->htmlHacks());
2924 case CSS_VAL_SMALLER:
2925 size = smallerFontSize(oldSize, style->htmlHacks());
2931 fontDescription.setIsAbsoluteSize(parentIsAbsoluteSize &&
2932 (primitiveValue->getIdent() == CSS_VAL_LARGER ||
2933 primitiveValue->getIdent() == CSS_VAL_SMALLER));
2935 int type = primitiveValue->primitiveType();
2936 fontDescription.setIsAbsoluteSize(parentIsAbsoluteSize ||
2937 (type != CSSPrimitiveValue::CSS_PERCENTAGE &&
2938 type != CSSPrimitiveValue::CSS_EMS &&
2939 type != CSSPrimitiveValue::CSS_EXS));
2940 if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG)
2941 size = primitiveValue->computeLengthFloat(parentStyle, false);
2942 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
2943 size = (primitiveValue->getFloatValue() * oldSize) / 100.0f;
2951 setFontSize(fontDescription, size);
2952 if (style->setFontDescription(fontDescription))
2957 case CSS_PROP_Z_INDEX: {
2959 if (parentStyle->hasAutoZIndex())
2960 style->setHasAutoZIndex();
2962 style->setZIndex(parentStyle->zIndex());
2964 } else if (isInitial || primitiveValue->getIdent() == CSS_VAL_AUTO) {
2965 style->setHasAutoZIndex();
2969 // FIXME: Should clamp all sorts of other integer properties too.
2970 const double minIntAsDouble = INT_MIN;
2971 const double maxIntAsDouble = INT_MAX;
2972 style->setZIndex(static_cast<int>(max(minIntAsDouble, min(primitiveValue->getDoubleValue(), maxIntAsDouble))));
2975 case CSS_PROP_WIDOWS:
2977 HANDLE_INHERIT_AND_INITIAL(widows, Widows)
2978 if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER)
2980 style->setWidows(primitiveValue->getIntValue());
2984 case CSS_PROP_ORPHANS:
2986 HANDLE_INHERIT_AND_INITIAL(orphans, Orphans)
2987 if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER)
2989 style->setOrphans(primitiveValue->getIntValue());
2993 // length, percent, number
2994 case CSS_PROP_LINE_HEIGHT:
2996 HANDLE_INHERIT_AND_INITIAL(lineHeight, LineHeight)
2997 if (!primitiveValue)
3000 int type = primitiveValue->primitiveType();
3001 if (primitiveValue->getIdent() == CSS_VAL_NORMAL)
3002 lineHeight = Length(-100.0, Percent);
3003 else if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) {
3004 double multiplier = 1.0;
3005 // Scale for the font zoom factor only for types other than "em" and "ex", since those are
3006 // already based on the font size.
3007 if (type != CSSPrimitiveValue::CSS_EMS && type != CSSPrimitiveValue::CSS_EXS && style->textSizeAdjust() && m_document->frame()) {
3008 multiplier = m_document->frame()->zoomFactor() / 100.0;
3010 lineHeight = Length(primitiveValue->computeLengthIntForLength(style, multiplier), Fixed);
3011 } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
3012 lineHeight = Length((style->fontSize() * primitiveValue->getIntValue()) / 100, Fixed);
3013 else if (type == CSSPrimitiveValue::CSS_NUMBER)
3014 lineHeight = Length(primitiveValue->getDoubleValue() * 100.0, Percent);
3017 style->setLineHeight(lineHeight);
3022 case CSS_PROP_TEXT_ALIGN:
3024 HANDLE_INHERIT_AND_INITIAL(textAlign, TextAlign)
3025 if (!primitiveValue)
3027 int id = primitiveValue->getIdent();
3028 if (id == CSS_VAL_START)
3029 style->setTextAlign(style->direction() == LTR ? LEFT : RIGHT);
3030 else if (id == CSS_VAL_END)
3031 style->setTextAlign(style->direction() == LTR ? RIGHT : LEFT);
3033 style->setTextAlign(*primitiveValue);
3044 bool hasClip = true;
3046 if (parentStyle->hasClip()) {
3047 top = parentStyle->clipTop();
3048 right = parentStyle->clipRight();
3049 bottom = parentStyle->clipBottom();
3050 left = parentStyle->clipLeft();
3054 top = right = bottom = left = Length();
3056 } else if (isInitial) {
3058 top = right = bottom = left = Length();
3059 } else if (!primitiveValue) {
3061 } else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_RECT) {
3062 Rect* rect = primitiveValue->getRectValue();
3065 top = convertToLength(rect->top(), style);
3066 right = convertToLength(rect->right(), style);
3067 bottom = convertToLength(rect->bottom(), style);
3068 left = convertToLength(rect->left(), style);
3070 } else if (primitiveValue->getIdent() != CSS_VAL_AUTO) {
3073 style->setClip(top, right, bottom, left);
3074 style->setHasClip(hasClip);
3081 case CSS_PROP_CONTENT:
3082 // list of string, uri, counter, attr, i
3084 // FIXME: In CSS3, it will be possible to inherit content. In CSS2 it is not. This
3085 // note is a reminder that eventually "inherit" needs to be supported.
3088 style->clearContent();
3092 if (!value->isValueList())
3095 CSSValueList* list = static_cast<CSSValueList*>(value);
3096 int len = list->length();
3098 bool didSet = false;
3099 for (int i = 0; i < len; i++) {
3100 CSSValue* item = list->item(i);
3101 if (!item->isPrimitiveValue())
3104 CSSPrimitiveValue* val = static_cast<CSSPrimitiveValue*>(item);
3105 switch (val->primitiveType()) {
3106 case CSSPrimitiveValue::CSS_STRING:
3107 style->setContent(val->getStringValue().impl(), didSet);
3110 case CSSPrimitiveValue::CSS_ATTR: {
3111 // FIXME: Can a namespace be specified for an attr(foo)?
3112 if (style->styleType() == RenderStyle::NOPSEUDO)
3115 parentStyle->setUnique();
3116 QualifiedName attr(nullAtom, val->getStringValue().impl(), nullAtom);
3117 style->setContent(element->getAttribute(attr).impl(), didSet);
3119 // register the fact that the attribute value affects the style
3120 m_selectorAttrs.add(attr.localName().impl());
3123 case CSSPrimitiveValue::CSS_URI: {
3124 CSSImageValue *image = static_cast<CSSImageValue*>(val);
3125 style->setContent(image->image(element->document()->docLoader()), didSet);
3129 case CSSPrimitiveValue::CSS_COUNTER: {
3130 Counter* counterValue = val->getCounterValue();
3131 CounterContent* counter = new CounterContent(counterValue->identifier(),
3132 (EListStyleType)counterValue->listStyleNumber(), counterValue->separator());
3133 style->setContent(counter, didSet);
3139 style->clearContent();
3143 case CSS_PROP_COUNTER_INCREMENT:
3144 applyCounterList(style, value->isValueList() ? static_cast<CSSValueList*>(value) : 0, false);
3146 case CSS_PROP_COUNTER_RESET:
3147 applyCounterList(style, value->isValueList() ? static_cast<CSSValueList*>(value) : 0, true);
3150 case CSS_PROP_FONT_FAMILY: {
3151 // list of strings and ids
3153 FontDescription parentFontDescription = parentStyle->fontDescription();
3154 FontDescription fontDescription = style->fontDescription();
3155 fontDescription.setGenericFamily(parentFontDescription.genericFamily());
3156 fontDescription.setFamily(parentFontDescription.firstFamily());
3157 if (style->setFontDescription(fontDescription))
3161 else if (isInitial) {
3162 FontDescription initialDesc = FontDescription();
3163 FontDescription fontDescription = style->fontDescription();
3164 // We need to adjust the size to account for the generic family change from monospace
3165 // to non-monospace.
3166 if (fontDescription.keywordSize() && fontDescription.genericFamily() == FontDescription::MonospaceFamily)
3167 setFontSize(fontDescription, fontSizeForKeyword(CSS_VAL_XX_SMALL + fontDescription.keywordSize() - 1, style->htmlHacks(), false));
3168 fontDescription.setGenericFamily(initialDesc.genericFamily());
3169 fontDescription.setFamily(initialDesc.firstFamily());
3170 if (style->setFontDescription(fontDescription))
3175 if (!value->isValueList()) return;
3176 FontDescription fontDescription = style->fontDescription();
3177 CSSValueList *list = static_cast<CSSValueList*>(value);
3178 int len = list->length();
3179 FontFamily& firstFamily = fontDescription.firstFamily();
3180 FontFamily *currFamily = 0;
3182 // Before mapping in a new font-family property, we should reset the generic family.
3183 bool oldFamilyIsMonospace = fontDescription.genericFamily() == FontDescription::MonospaceFamily;
3184 fontDescription.setGenericFamily(FontDescription::NoFamily);
3186 for (int i = 0; i < len; i++) {
3187 CSSValue *item = list->item(i);
3188 if (!item->isPrimitiveValue()) continue;
3189 CSSPrimitiveValue *val = static_cast<CSSPrimitiveValue*>(item);
3191 Settings* settings = m_document->settings();
3192 if (val->primitiveType() == CSSPrimitiveValue::CSS_STRING)
3193 face = static_cast<FontFamilyValue*>(val)->fontName();
3194 else if (val->primitiveType() == CSSPrimitiveValue::CSS_IDENT && settings) {
3195 switch (val->getIdent()) {
3196 case CSS_VAL__WEBKIT_BODY:
3197 face = settings->standardFontFamily();
3200 face = "-webkit-serif";
3201 fontDescription.setGenericFamily(FontDescription::SerifFamily);
3203 case CSS_VAL_SANS_SERIF:
3204 face = "-webkit-sans-serif";
3205 fontDescription.setGenericFamily(FontDescription::SansSerifFamily);
3207 case CSS_VAL_CURSIVE:
3208 face = "-webkit-cursive";
3209 fontDescription.setGenericFamily(FontDescription::CursiveFamily);
3211 case CSS_VAL_FANTASY:
3212 face = "-webkit-fantasy";
3213 fontDescription.setGenericFamily(FontDescription::FantasyFamily);
3215 case CSS_VAL_MONOSPACE:
3216 face = "-webkit-monospace";
3217 fontDescription.setGenericFamily(FontDescription::MonospaceFamily);
3222 if (!face.isEmpty()) {
3224 // Filling in the first family.
3225 firstFamily.setFamily(face);
3226 currFamily = &firstFamily;
3229 FontFamily *newFamily = new FontFamily;
3230 newFamily->setFamily(face);
3231 currFamily->appendFamily(newFamily);
3232 currFamily = newFamily;
3235 if (fontDescription.keywordSize() && (fontDescription.genericFamily() == FontDescription::MonospaceFamily) != oldFamilyIsMonospace)
3236 setFontSize(fontDescription, fontSizeForKeyword(CSS_VAL_XX_SMALL + fontDescription.keywordSize() - 1, style->htmlHacks(), !oldFamilyIsMonospace));
3238 if (style->setFontDescription(fontDescription))
3244 case CSS_PROP_TEXT_DECORATION: {
3246 HANDLE_INHERIT_AND_INITIAL(textDecoration, TextDecoration)
3247 int t = RenderStyle::initialTextDecoration();
3248 if (primitiveValue && primitiveValue->getIdent() == CSS_VAL_NONE) {
3251 if (!value->isValueList()) return;
3252 CSSValueList *list = static_cast<CSSValueList*>(value);
3253 int len = list->length();
3254 for (int i = 0; i < len; i++)
3256 CSSValue *item = list->item(i);
3257 if (!item->isPrimitiveValue()) continue;
3258 primitiveValue = static_cast<CSSPrimitiveValue*>(item);
3259 switch (primitiveValue->getIdent()) {
3262 case CSS_VAL_UNDERLINE:
3263 t |= UNDERLINE; break;
3264 case CSS_VAL_OVERLINE:
3265 t |= OVERLINE; break;
3266 case CSS_VAL_LINE_THROUGH:
3267 t |= LINE_THROUGH; break;
3276 style->setTextDecoration(t);
3280 // shorthand properties
3281 case CSS_PROP_BACKGROUND:
3283 style->clearBackgroundLayers();
3284 style->setBackgroundColor(Color());
3287 else if (isInherit) {
3288 style->inheritBackgroundLayers(*parentStyle->backgroundLayers());
3289 style->setBackgroundColor(parentStyle->backgroundColor());
3292 case CSS_PROP_BORDER:
3293 case CSS_PROP_BORDER_STYLE:
3294 case CSS_PROP_BORDER_WIDTH:
3295 case CSS_PROP_BORDER_COLOR:
3296 if (id == CSS_PROP_BORDER || id == CSS_PROP_BORDER_COLOR)