1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public License
22 * along with this library; see the file COPYING.LIB. If not, write to
23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 * Boston, MA 02110-1301, USA.
25 */
26
27 #include "config.h"
28 #include "CSSStyleSelector.h"
29
30 #include "Attribute.h"
31 #include "ContentData.h"
32 #include "CounterContent.h"
33 #include "CursorList.h"
34 #include "CSSBorderImageValue.h"
35 #include "CSSCursorImageValue.h"
36 #include "CSSFontFaceRule.h"
37 #include "CSSImportRule.h"
38 #include "CSSLineBoxContainValue.h"
39 #include "CSSMediaRule.h"
40 #include "CSSPageRule.h"
41 #include "CSSParser.h"
42 #include "CSSPrimitiveValueMappings.h"
43 #include "CSSPropertyNames.h"
44 #include "CSSReflectValue.h"
45 #include "CSSRuleList.h"
46 #include "CSSSelector.h"
47 #include "CSSSelectorList.h"
48 #include "CSSStyleApplyProperty.h"
49 #include "CSSStyleRule.h"
50 #include "CSSStyleSheet.h"
51 #include "CSSTimingFunctionValue.h"
52 #include "CSSValueList.h"
53 #include "CachedImage.h"
54 #include "Counter.h"
55 #include "FocusController.h"
56 #include "FontFamilyValue.h"
57 #include "FontValue.h"
58 #include "Frame.h"
59 #include "FrameView.h"
60 #include "HTMLDocument.h"
61 #include "HTMLElement.h"
62 #include "HTMLInputElement.h"
63 #include "HTMLNames.h"
64 #include "HTMLTextAreaElement.h"
65 #include "KeyframeList.h"
66 #include "LinkHash.h"
67 #include "Matrix3DTransformOperation.h"
68 #include "MatrixTransformOperation.h"
69 #include "MediaList.h"
70 #include "MediaQueryEvaluator.h"
71 #include "NodeRenderStyle.h"
72 #include "Page.h"
73 #include "PageGroup.h"
74 #include "Pair.h"
75 #include "PerspectiveTransformOperation.h"
76 #include "QuotesData.h"
77 #include "Rect.h"
78 #include "RenderScrollbar.h"
79 #include "RenderScrollbarTheme.h"
80 #include "RenderStyleConstants.h"
81 #include "RenderTheme.h"
82 #include "RotateTransformOperation.h"
83 #include "ScaleTransformOperation.h"
84 #include "SelectionController.h"
85 #include "Settings.h"
86 #include "ShadowData.h"
87 #include "ShadowValue.h"
88 #include "SkewTransformOperation.h"
89 #include "StyleCachedImage.h"
90 #include "StylePendingImage.h"
91 #include "StyleGeneratedImage.h"
92 #include "StyleSheetList.h"
93 #include "Text.h"
94 #include "TransformationMatrix.h"
95 #include "TranslateTransformOperation.h"
96 #include "UserAgentStyleSheets.h"
97 #include "WebKitCSSKeyframeRule.h"
98 #include "WebKitCSSKeyframesRule.h"
99 #include "WebKitCSSTransformValue.h"
100 #include "XMLNames.h"
101 #include <wtf/StdLibExtras.h>
102 #include <wtf/Vector.h>
103
104 #if USE(PLATFORM_STRATEGIES)
105 #include "PlatformStrategies.h"
106 #include "VisitedLinkStrategy.h"
107 #endif
108
109 #if ENABLE(DASHBOARD_SUPPORT)
110 #include "DashboardRegion.h"
111 #endif
112
113 #if ENABLE(SVG)
114 #include "XLinkNames.h"
115 #include "SVGNames.h"
116 #endif
117
118 #if ENABLE(WML)
119 #include "WMLNames.h"
120 #endif
121
122 #if PLATFORM(QT)
123 #include <qwebhistoryinterface.h>
124 #endif
125
126 using namespace std;
127
128 namespace WebCore {
129
130 using namespace HTMLNames;
131
132 #define HANDLE_INHERIT(prop, Prop) \
133 if (isInherit) { \
134 m_style->set##Prop(m_parentStyle->prop()); \
135 return; \
136 }
137
138 #define HANDLE_INHERIT_AND_INITIAL(prop, Prop) \
139 HANDLE_INHERIT(prop, Prop) \
140 if (isInitial) { \
141 m_style->set##Prop(RenderStyle::initial##Prop()); \
142 return; \
143 }
144
145 #define HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(prop, Prop, Value) \
146 HANDLE_INHERIT(prop, Prop) \
147 if (isInitial) { \
148 m_style->set##Prop(RenderStyle::initial##Value());\
149 return;\
150 }
151
152 #define HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(prop, Prop) \
153 HANDLE_INHERIT_AND_INITIAL(prop, Prop) \
154 if (primitiveValue) \
155 m_style->set##Prop(*primitiveValue);
156
157 #define HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(prop, Prop, Value) \
158 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(prop, Prop, Value) \
159 if (primitiveValue) \
160 m_style->set##Prop(*primitiveValue);
161
162 #define HANDLE_ANIMATION_INHERIT_AND_INITIAL(prop, Prop) \
163 if (isInherit) { \
164 AnimationList* list = m_style->accessAnimations(); \
165 const AnimationList* parentList = m_parentStyle->animations(); \
166 size_t i = 0, parentSize = parentList ? parentList->size() : 0; \
167 for ( ; i < parentSize && parentList->animation(i)->is##Prop##Set(); ++i) { \
168 if (list->size() <= i) \
169 list->append(Animation::create()); \
170 list->animation(i)->set##Prop(parentList->animation(i)->prop()); \
171 } \
172 \
173 /* Reset any remaining animations to not have the property set. */ \
174 for ( ; i < list->size(); ++i) \
175 list->animation(i)->clear##Prop(); \
176 } else if (isInitial) { \
177 AnimationList* list = m_style->accessAnimations(); \
178 if (list->isEmpty()) \
179 list->append(Animation::create()); \
180 list->animation(0)->set##Prop(Animation::initialAnimation##Prop()); \
181 for (size_t i = 1; i < list->size(); ++i) \
182 list->animation(0)->clear##Prop(); \
183 }
184
185 #define HANDLE_ANIMATION_VALUE(prop, Prop, value) { \
186 HANDLE_ANIMATION_INHERIT_AND_INITIAL(prop, Prop) \
187 if (isInherit || isInitial) \
188 return; \
189 AnimationList* list = m_style->accessAnimations(); \
190 size_t childIndex = 0; \
191 if (value->isValueList()) { \
192 /* Walk each value and put it into an animation, creating new animations as needed. */ \
193 CSSValueList* valueList = static_cast<CSSValueList*>(value); \
194 for (unsigned int i = 0; i < valueList->length(); i++) { \
195 if (childIndex <= list->size()) \
196 list->append(Animation::create()); \
197 mapAnimation##Prop(list->animation(childIndex), valueList->itemWithoutBoundsCheck(i)); \
198 ++childIndex; \
199 } \
200 } else { \
201 if (list->isEmpty()) \
202 list->append(Animation::create()); \
203 mapAnimation##Prop(list->animation(childIndex), value); \
204 childIndex = 1; \
205 } \
206 for ( ; childIndex < list->size(); ++childIndex) { \
207 /* Reset all remaining animations to not have the property set. */ \
208 list->animation(childIndex)->clear##Prop(); \
209 } \
210 }
211
212 #define HANDLE_TRANSITION_INHERIT_AND_INITIAL(prop, Prop) \
213 if (isInherit) { \
214 AnimationList* list = m_style->accessTransitions(); \
215 const AnimationList* parentList = m_parentStyle->transitions(); \
216 size_t i = 0, parentSize = parentList ? parentList->size() : 0; \
217 for ( ; i < parentSize && parentList->animation(i)->is##Prop##Set(); ++i) { \
218 if (list->size() <= i) \
219 list->append(Animation::create()); \
220 list->animation(i)->set##Prop(parentList->animation(i)->prop()); \
221 } \
222 \
223 /* Reset any remaining transitions to not have the property set. */ \
224 for ( ; i < list->size(); ++i) \
225 list->animation(i)->clear##Prop(); \
226 } else if (isInitial) { \
227 AnimationList* list = m_style->accessTransitions(); \
228 if (list->isEmpty()) \
229 list->append(Animation::create()); \
230 list->animation(0)->set##Prop(Animation::initialAnimation##Prop()); \
231 for (size_t i = 1; i < list->size(); ++i) \
232 list->animation(0)->clear##Prop(); \
233 }
234
235 #define HANDLE_TRANSITION_VALUE(prop, Prop, value) { \
236 HANDLE_TRANSITION_INHERIT_AND_INITIAL(prop, Prop) \
237 if (isInherit || isInitial) \
238 return; \
239 AnimationList* list = m_style->accessTransitions(); \
240 size_t childIndex = 0; \
241 if (value->isValueList()) { \
242 /* Walk each value and put it into a transition, creating new animations as needed. */ \
243 CSSValueList* valueList = static_cast<CSSValueList*>(value); \
244 for (unsigned int i = 0; i < valueList->length(); i++) { \
245 if (childIndex <= list->size()) \
246 list->append(Animation::create()); \
247 mapAnimation##Prop(list->animation(childIndex), valueList->itemWithoutBoundsCheck(i)); \
248 ++childIndex; \
249 } \
250 } else { \
251 if (list->isEmpty()) \
252 list->append(Animation::create()); \
253 mapAnimation##Prop(list->animation(childIndex), value); \
254 childIndex = 1; \
255 } \
256 for ( ; childIndex < list->size(); ++childIndex) { \
257 /* Reset all remaining transitions to not have the property set. */ \
258 list->animation(childIndex)->clear##Prop(); \
259 } \
260 }
261
262 #define HANDLE_INHERIT_COND(propID, prop, Prop) \
263 if (id == propID) { \
264 m_style->set##Prop(m_parentStyle->prop()); \
265 return; \
266 }
267
268 #define HANDLE_INHERIT_COND_WITH_BACKUP(propID, prop, propAlt, Prop) \
269 if (id == propID) { \
270 if (m_parentStyle->prop().isValid()) \
271 m_style->set##Prop(m_parentStyle->prop()); \
272 else \
273 m_style->set##Prop(m_parentStyle->propAlt()); \
274 return; \
275 }
276
277 #define HANDLE_INITIAL_COND(propID, Prop) \
278 if (id == propID) { \
279 m_style->set##Prop(RenderStyle::initial##Prop()); \
280 return; \
281 }
282
283 #define HANDLE_INITIAL_COND_WITH_VALUE(propID, Prop, Value) \
284 if (id == propID) { \
285 m_style->set##Prop(RenderStyle::initial##Value()); \
286 return; \
287 }
288
289 class RuleData {
290 public:
291 RuleData(CSSStyleRule*, CSSSelector*, unsigned position);
292
position() const293 unsigned position() const { return m_position; }
rule() const294 CSSStyleRule* rule() const { return m_rule; }
selector() const295 CSSSelector* selector() const { return m_selector; }
296
hasFastCheckableSelector() const297 bool hasFastCheckableSelector() const { return m_hasFastCheckableSelector; }
hasMultipartSelector() const298 bool hasMultipartSelector() const { return m_hasMultipartSelector; }
hasTopSelectorMatchingHTMLBasedOnRuleHash() const299 bool hasTopSelectorMatchingHTMLBasedOnRuleHash() const { return m_hasTopSelectorMatchingHTMLBasedOnRuleHash; }
specificity() const300 unsigned specificity() const { return m_specificity; }
301
302 // Try to balance between memory usage (there can be lots of RuleData objects) and good filtering performance.
303 static const unsigned maximumIdentifierCount = 4;
descendantSelectorIdentifierHashes() const304 const unsigned* descendantSelectorIdentifierHashes() const { return m_descendantSelectorIdentifierHashes; }
305
306 private:
307 void collectDescendantSelectorIdentifierHashes();
308 void collectIdentifierHashes(const CSSSelector*, unsigned& identifierCount);
309
310 CSSStyleRule* m_rule;
311 CSSSelector* m_selector;
312 unsigned m_specificity;
313 unsigned m_position : 29;
314 bool m_hasFastCheckableSelector : 1;
315 bool m_hasMultipartSelector : 1;
316 bool m_hasTopSelectorMatchingHTMLBasedOnRuleHash : 1;
317 // Use plain array instead of a Vector to minimize memory overhead.
318 unsigned m_descendantSelectorIdentifierHashes[maximumIdentifierCount];
319 };
320
321 class RuleSet {
322 WTF_MAKE_NONCOPYABLE(RuleSet);
323 public:
324 RuleSet();
325 ~RuleSet();
326
327 typedef HashMap<AtomicStringImpl*, Vector<RuleData>*> AtomRuleMap;
328
329 void addRulesFromSheet(CSSStyleSheet*, const MediaQueryEvaluator&, CSSStyleSelector* = 0);
330
331 void addStyleRule(CSSStyleRule* item);
332 void addRule(CSSStyleRule* rule, CSSSelector* sel);
333 void addPageRule(CSSStyleRule* rule, CSSSelector* sel);
334 void addToRuleSet(AtomicStringImpl* key, AtomRuleMap& map,
335 CSSStyleRule* rule, CSSSelector* sel);
336 void shrinkToFit();
disableAutoShrinkToFit()337 void disableAutoShrinkToFit() { m_autoShrinkToFitEnabled = false; }
338
339 void collectFeatures(CSSStyleSelector::Features&) const;
340
getIDRules(AtomicStringImpl * key) const341 const Vector<RuleData>* getIDRules(AtomicStringImpl* key) const { return m_idRules.get(key); }
getClassRules(AtomicStringImpl * key) const342 const Vector<RuleData>* getClassRules(AtomicStringImpl* key) const { return m_classRules.get(key); }
getTagRules(AtomicStringImpl * key) const343 const Vector<RuleData>* getTagRules(AtomicStringImpl* key) const { return m_tagRules.get(key); }
getPseudoRules(AtomicStringImpl * key) const344 const Vector<RuleData>* getPseudoRules(AtomicStringImpl* key) const { return m_pseudoRules.get(key); }
getUniversalRules() const345 const Vector<RuleData>* getUniversalRules() const { return &m_universalRules; }
getPageRules() const346 const Vector<RuleData>* getPageRules() const { return &m_pageRules; }
347
348 public:
349 AtomRuleMap m_idRules;
350 AtomRuleMap m_classRules;
351 AtomRuleMap m_tagRules;
352 AtomRuleMap m_pseudoRules;
353 Vector<RuleData> m_universalRules;
354 Vector<RuleData> m_pageRules;
355 unsigned m_ruleCount;
356 bool m_autoShrinkToFitEnabled;
357 };
358
359 static RuleSet* defaultStyle;
360 static RuleSet* defaultQuirksStyle;
361 static RuleSet* defaultPrintStyle;
362 static RuleSet* defaultViewSourceStyle;
363 static CSSStyleSheet* simpleDefaultStyleSheet;
364
365 static RuleSet* siblingRulesInDefaultStyle;
366
367 RenderStyle* CSSStyleSelector::s_styleNotYetAvailable;
368
369 static void loadFullDefaultStyle();
370 static void loadSimpleDefaultStyle();
371 // FIXME: It would be nice to use some mechanism that guarantees this is in sync with the real UA stylesheet.
372 static const char* simpleUserAgentStyleSheet = "html,body,div{display:block}head{display:none}body{margin:8px}div:focus,span:focus{outline:auto 5px -webkit-focus-ring-color}a:-webkit-any-link{color:-webkit-link;text-decoration:underline}a:-webkit-any-link:active{color:-webkit-activelink}";
373
elementCanUseSimpleDefaultStyle(Element * e)374 static inline bool elementCanUseSimpleDefaultStyle(Element* e)
375 {
376 return e->hasTagName(htmlTag) || e->hasTagName(headTag) || e->hasTagName(bodyTag) || e->hasTagName(divTag) || e->hasTagName(spanTag) || e->hasTagName(brTag) || e->hasTagName(aTag);
377 }
378
collectSiblingRulesInDefaultStyle()379 static inline void collectSiblingRulesInDefaultStyle()
380 {
381 CSSStyleSelector::Features features;
382 defaultStyle->collectFeatures(features);
383 ASSERT(features.idsInRules.isEmpty());
384 delete siblingRulesInDefaultStyle;
385 siblingRulesInDefaultStyle = features.siblingRules.leakPtr();
386 }
387
assertNoSiblingRulesInDefaultStyle()388 static inline void assertNoSiblingRulesInDefaultStyle()
389 {
390 #ifndef NDEBUG
391 if (siblingRulesInDefaultStyle)
392 return;
393 collectSiblingRulesInDefaultStyle();
394 ASSERT(!siblingRulesInDefaultStyle);
395 #endif
396 }
397
screenEval()398 static const MediaQueryEvaluator& screenEval()
399 {
400 DEFINE_STATIC_LOCAL(const MediaQueryEvaluator, staticScreenEval, ("screen"));
401 return staticScreenEval;
402 }
403
printEval()404 static const MediaQueryEvaluator& printEval()
405 {
406 DEFINE_STATIC_LOCAL(const MediaQueryEvaluator, staticPrintEval, ("print"));
407 return staticPrintEval;
408 }
409
leftToRightDeclaration()410 static CSSMutableStyleDeclaration* leftToRightDeclaration()
411 {
412 DEFINE_STATIC_LOCAL(RefPtr<CSSMutableStyleDeclaration>, leftToRightDecl, (CSSMutableStyleDeclaration::create()));
413 if (!leftToRightDecl->length()) {
414 leftToRightDecl->setProperty(CSSPropertyDirection, "ltr", false, false);
415 leftToRightDecl->setStrictParsing(false);
416 }
417 return leftToRightDecl.get();
418 }
419
rightToLeftDeclaration()420 static CSSMutableStyleDeclaration* rightToLeftDeclaration()
421 {
422 DEFINE_STATIC_LOCAL(RefPtr<CSSMutableStyleDeclaration>, rightToLeftDecl, (CSSMutableStyleDeclaration::create()));
423 if (!rightToLeftDecl->length()) {
424 rightToLeftDecl->setProperty(CSSPropertyDirection, "rtl", false, false);
425 rightToLeftDecl->setStrictParsing(false);
426 }
427 return rightToLeftDecl.get();
428 }
429
CSSStyleSelector(Document * document,StyleSheetList * styleSheets,CSSStyleSheet * mappedElementSheet,CSSStyleSheet * pageUserSheet,const Vector<RefPtr<CSSStyleSheet>> * pageGroupUserSheets,bool strictParsing,bool matchAuthorAndUserStyles)430 CSSStyleSelector::CSSStyleSelector(Document* document, StyleSheetList* styleSheets, CSSStyleSheet* mappedElementSheet,
431 CSSStyleSheet* pageUserSheet, const Vector<RefPtr<CSSStyleSheet> >* pageGroupUserSheets,
432 bool strictParsing, bool matchAuthorAndUserStyles)
433 : m_backgroundData(BackgroundFillLayer)
434 , m_checker(document, strictParsing)
435 , m_element(0)
436 , m_styledElement(0)
437 , m_elementLinkState(NotInsideLink)
438 , m_fontSelector(CSSFontSelector::create(document))
439 , m_applyProperty(CSSStyleApplyProperty::sharedCSSStyleApplyProperty())
440 {
441 m_matchAuthorAndUserStyles = matchAuthorAndUserStyles;
442
443 Element* root = document->documentElement();
444
445 if (!defaultStyle) {
446 if (!root || elementCanUseSimpleDefaultStyle(root))
447 loadSimpleDefaultStyle();
448 else {
449 loadFullDefaultStyle();
450 }
451 }
452
453 // construct document root element default style. this is needed
454 // to evaluate media queries that contain relative constraints, like "screen and (max-width: 10em)"
455 // This is here instead of constructor, because when constructor is run,
456 // document doesn't have documentElement
457 // NOTE: this assumes that element that gets passed to styleForElement -call
458 // is always from the document that owns the style selector
459 FrameView* view = document->view();
460 if (view)
461 m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType()));
462 else
463 m_medium = adoptPtr(new MediaQueryEvaluator("all"));
464
465 if (root)
466 m_rootDefaultStyle = styleForElement(root, 0, false, true); // don't ref, because the RenderStyle is allocated from global heap
467
468 if (m_rootDefaultStyle && view)
469 m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType(), view->frame(), m_rootDefaultStyle.get()));
470
471 m_authorStyle = adoptPtr(new RuleSet);
472 // Adding rules from multiple sheets, shrink at the end.
473 m_authorStyle->disableAutoShrinkToFit();
474
475 // FIXME: This sucks! The user sheet is reparsed every time!
476 OwnPtr<RuleSet> tempUserStyle = adoptPtr(new RuleSet);
477 if (pageUserSheet)
478 tempUserStyle->addRulesFromSheet(pageUserSheet, *m_medium, this);
479 if (pageGroupUserSheets) {
480 unsigned length = pageGroupUserSheets->size();
481 for (unsigned i = 0; i < length; i++) {
482 if (pageGroupUserSheets->at(i)->isUserStyleSheet())
483 tempUserStyle->addRulesFromSheet(pageGroupUserSheets->at(i).get(), *m_medium, this);
484 else
485 m_authorStyle->addRulesFromSheet(pageGroupUserSheets->at(i).get(), *m_medium, this);
486 }
487 }
488
489 if (tempUserStyle->m_ruleCount > 0 || tempUserStyle->m_pageRules.size() > 0)
490 m_userStyle = tempUserStyle.release();
491
492 // Add rules from elements like SVG's <font-face>
493 if (mappedElementSheet)
494 m_authorStyle->addRulesFromSheet(mappedElementSheet, *m_medium, this);
495
496 // add stylesheets from document
497 unsigned length = styleSheets->length();
498 for (unsigned i = 0; i < length; i++) {
499 StyleSheet* sheet = styleSheets->item(i);
500 if (sheet->isCSSStyleSheet() && !sheet->disabled())
501 m_authorStyle->addRulesFromSheet(static_cast<CSSStyleSheet*>(sheet), *m_medium, this);
502 }
503 // Collect all ids and rules using sibling selectors (:first-child and similar)
504 // in the current set of stylesheets. Style sharing code uses this information to reject
505 // sharing candidates.
506 // Usually there are no sibling rules in the default style but the MathML sheet has some.
507 if (siblingRulesInDefaultStyle)
508 siblingRulesInDefaultStyle->collectFeatures(m_features);
509 m_authorStyle->collectFeatures(m_features);
510 if (m_userStyle)
511 m_userStyle->collectFeatures(m_features);
512
513 m_authorStyle->shrinkToFit();
514 if (m_features.siblingRules)
515 m_features.siblingRules->shrinkToFit();
516
517 if (document->renderer() && document->renderer()->style())
518 document->renderer()->style()->font().update(fontSelector());
519 }
520
521 // This is a simplified style setting function for keyframe styles
addKeyframeStyle(PassRefPtr<WebKitCSSKeyframesRule> rule)522 void CSSStyleSelector::addKeyframeStyle(PassRefPtr<WebKitCSSKeyframesRule> rule)
523 {
524 AtomicString s(rule->name());
525 m_keyframesRuleMap.add(s.impl(), rule);
526 }
527
~CSSStyleSelector()528 CSSStyleSelector::~CSSStyleSelector()
529 {
530 m_fontSelector->clearDocument();
531 deleteAllValues(m_viewportDependentMediaQueryResults);
532 }
533
Features()534 CSSStyleSelector::Features::Features()
535 : usesFirstLineRules(false)
536 , usesBeforeAfterRules(false)
537 , usesLinkRules(false)
538 {
539 }
540
~Features()541 CSSStyleSelector::Features::~Features()
542 {
543 }
544
parseUASheet(const String & str)545 static CSSStyleSheet* parseUASheet(const String& str)
546 {
547 CSSStyleSheet* sheet = CSSStyleSheet::create().releaseRef(); // leak the sheet on purpose
548 sheet->parseString(str);
549 return sheet;
550 }
551
parseUASheet(const char * characters,unsigned size)552 static CSSStyleSheet* parseUASheet(const char* characters, unsigned size)
553 {
554 return parseUASheet(String(characters, size));
555 }
556
loadFullDefaultStyle()557 static void loadFullDefaultStyle()
558 {
559 if (simpleDefaultStyleSheet) {
560 ASSERT(defaultStyle);
561 delete defaultStyle;
562 simpleDefaultStyleSheet->deref();
563 defaultStyle = new RuleSet;
564 simpleDefaultStyleSheet = 0;
565 } else {
566 ASSERT(!defaultStyle);
567 defaultStyle = new RuleSet;
568 defaultPrintStyle = new RuleSet;
569 defaultQuirksStyle = new RuleSet;
570 }
571
572 // Strict-mode rules.
573 String defaultRules = String(htmlUserAgentStyleSheet, sizeof(htmlUserAgentStyleSheet)) + RenderTheme::defaultTheme()->extraDefaultStyleSheet();
574 CSSStyleSheet* defaultSheet = parseUASheet(defaultRules);
575 defaultStyle->addRulesFromSheet(defaultSheet, screenEval());
576 defaultPrintStyle->addRulesFromSheet(defaultSheet, printEval());
577
578 // Quirks-mode rules.
579 String quirksRules = String(quirksUserAgentStyleSheet, sizeof(quirksUserAgentStyleSheet)) + RenderTheme::defaultTheme()->extraQuirksStyleSheet();
580 CSSStyleSheet* quirksSheet = parseUASheet(quirksRules);
581 defaultQuirksStyle->addRulesFromSheet(quirksSheet, screenEval());
582 }
583
loadSimpleDefaultStyle()584 static void loadSimpleDefaultStyle()
585 {
586 ASSERT(!defaultStyle);
587 ASSERT(!simpleDefaultStyleSheet);
588
589 defaultStyle = new RuleSet;
590 defaultPrintStyle = new RuleSet;
591 defaultQuirksStyle = new RuleSet;
592
593 simpleDefaultStyleSheet = parseUASheet(simpleUserAgentStyleSheet, strlen(simpleUserAgentStyleSheet));
594 defaultStyle->addRulesFromSheet(simpleDefaultStyleSheet, screenEval());
595
596 // No need to initialize quirks sheet yet as there are no quirk rules for elements allowed in simple default style.
597 }
598
loadViewSourceStyle()599 static void loadViewSourceStyle()
600 {
601 ASSERT(!defaultViewSourceStyle);
602 defaultViewSourceStyle = new RuleSet;
603 defaultViewSourceStyle->addRulesFromSheet(parseUASheet(sourceUserAgentStyleSheet, sizeof(sourceUserAgentStyleSheet)), screenEval());
604 }
605
collectElementIdentifierHashes(const Element * element,Vector<unsigned,4> & identifierHashes)606 static inline void collectElementIdentifierHashes(const Element* element, Vector<unsigned, 4>& identifierHashes)
607 {
608 identifierHashes.append(element->localName().impl()->existingHash());
609 if (element->hasID())
610 identifierHashes.append(element->idForStyleResolution().impl()->existingHash());
611 const StyledElement* styledElement = element->isStyledElement() ? static_cast<const StyledElement*>(element) : 0;
612 if (styledElement && styledElement->hasClass()) {
613 const SpaceSplitString& classNames = styledElement->classNames();
614 size_t count = classNames.size();
615 for (size_t i = 0; i < count; ++i)
616 identifierHashes.append(classNames[i].impl()->existingHash());
617 }
618 }
619
pushParentStackFrame(Element * parent)620 void CSSStyleSelector::pushParentStackFrame(Element* parent)
621 {
622 ASSERT(m_ancestorIdentifierFilter);
623 ASSERT(m_parentStack.isEmpty() || m_parentStack.last().element == parent->parentElement());
624 ASSERT(!m_parentStack.isEmpty() || !parent->parentElement());
625 m_parentStack.append(ParentStackFrame(parent));
626 ParentStackFrame& parentFrame = m_parentStack.last();
627 // Mix tags, class names and ids into some sort of weird bouillabaisse.
628 // The filter is used for fast rejection of child and descendant selectors.
629 collectElementIdentifierHashes(parent, parentFrame.identifierHashes);
630 size_t count = parentFrame.identifierHashes.size();
631 for (size_t i = 0; i < count; ++i)
632 m_ancestorIdentifierFilter->add(parentFrame.identifierHashes[i]);
633 }
634
popParentStackFrame()635 void CSSStyleSelector::popParentStackFrame()
636 {
637 ASSERT(!m_parentStack.isEmpty());
638 ASSERT(m_ancestorIdentifierFilter);
639 const ParentStackFrame& parentFrame = m_parentStack.last();
640 size_t count = parentFrame.identifierHashes.size();
641 for (size_t i = 0; i < count; ++i)
642 m_ancestorIdentifierFilter->remove(parentFrame.identifierHashes[i]);
643 m_parentStack.removeLast();
644 if (m_parentStack.isEmpty()) {
645 ASSERT(m_ancestorIdentifierFilter->likelyEmpty());
646 m_ancestorIdentifierFilter.clear();
647 }
648 }
649
pushParent(Element * parent)650 void CSSStyleSelector::pushParent(Element* parent)
651 {
652 if (m_parentStack.isEmpty()) {
653 ASSERT(!m_ancestorIdentifierFilter);
654 m_ancestorIdentifierFilter = adoptPtr(new BloomFilter<bloomFilterKeyBits>);
655 // If the element is not the root itself, build the stack starting from the root.
656 if (parent->parentElement()) {
657 Vector<Element*, 30> ancestors;
658 for (Element* ancestor = parent; ancestor; ancestor = ancestor->parentElement())
659 ancestors.append(ancestor);
660 int count = ancestors.size();
661 for (int n = count - 1; n >= 0; --n)
662 pushParentStackFrame(ancestors[n]);
663 return;
664 }
665 } else if (!parent->parentElement()) {
666 // We are not always invoked consistently. For example, script execution can cause us to enter
667 // style recalc in the middle of tree building. Reset the stack if we see a new root element.
668 ASSERT(m_ancestorIdentifierFilter);
669 m_ancestorIdentifierFilter->clear();
670 m_parentStack.resize(0);
671 } else {
672 ASSERT(m_ancestorIdentifierFilter);
673 // We may get invoked for some random elements in some wacky cases during style resolve.
674 // Pause maintaining the stack in this case.
675 if (m_parentStack.last().element != parent->parentElement())
676 return;
677 }
678 pushParentStackFrame(parent);
679 }
680
popParent(Element * parent)681 void CSSStyleSelector::popParent(Element* parent)
682 {
683 if (m_parentStack.isEmpty() || m_parentStack.last().element != parent)
684 return;
685 popParentStackFrame();
686 }
687
addMatchedDeclaration(CSSMutableStyleDeclaration * decl)688 void CSSStyleSelector::addMatchedDeclaration(CSSMutableStyleDeclaration* decl)
689 {
690 m_matchedDecls.append(decl);
691 }
692
matchRules(RuleSet * rules,int & firstRuleIndex,int & lastRuleIndex,bool includeEmptyRules)693 void CSSStyleSelector::matchRules(RuleSet* rules, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules)
694 {
695 m_matchedRules.clear();
696
697 if (!rules || !m_element)
698 return;
699
700 // We need to collect the rules for id, class, tag, and everything else into a buffer and
701 // then sort the buffer.
702 if (m_element->hasID())
703 matchRulesForList(rules->getIDRules(m_element->idForStyleResolution().impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules);
704 if (m_element->hasClass()) {
705 ASSERT(m_styledElement);
706 const SpaceSplitString& classNames = m_styledElement->classNames();
707 size_t size = classNames.size();
708 for (size_t i = 0; i < size; ++i)
709 matchRulesForList(rules->getClassRules(classNames[i].impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules);
710 }
711 if (!m_element->shadowPseudoId().isEmpty()) {
712 ASSERT(m_styledElement);
713 matchRulesForList(rules->getPseudoRules(m_element->shadowPseudoId().impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules);
714 }
715 matchRulesForList(rules->getTagRules(m_element->localName().impl()), firstRuleIndex, lastRuleIndex, includeEmptyRules);
716 matchRulesForList(rules->getUniversalRules(), firstRuleIndex, lastRuleIndex, includeEmptyRules);
717
718 // If we didn't match any rules, we're done.
719 if (m_matchedRules.isEmpty())
720 return;
721
722 // Sort the set of matched rules.
723 sortMatchedRules();
724
725 // Now transfer the set of matched rules over to our list of decls.
726 if (!m_checker.m_collectRulesOnly) {
727 for (unsigned i = 0; i < m_matchedRules.size(); i++)
728 addMatchedDeclaration(m_matchedRules[i]->rule()->declaration());
729 } else {
730 for (unsigned i = 0; i < m_matchedRules.size(); i++) {
731 if (!m_ruleList)
732 m_ruleList = CSSRuleList::create();
733 m_ruleList->append(m_matchedRules[i]->rule());
734 }
735 }
736 }
737
fastRejectSelector(const RuleData & ruleData) const738 inline bool CSSStyleSelector::fastRejectSelector(const RuleData& ruleData) const
739 {
740 ASSERT(m_ancestorIdentifierFilter);
741 const unsigned* descendantSelectorIdentifierHashes = ruleData.descendantSelectorIdentifierHashes();
742 for (unsigned n = 0; n < RuleData::maximumIdentifierCount && descendantSelectorIdentifierHashes[n]; ++n) {
743 if (!m_ancestorIdentifierFilter->mayContain(descendantSelectorIdentifierHashes[n]))
744 return true;
745 }
746 return false;
747 }
748
matchRulesForList(const Vector<RuleData> * rules,int & firstRuleIndex,int & lastRuleIndex,bool includeEmptyRules)749 void CSSStyleSelector::matchRulesForList(const Vector<RuleData>* rules, int& firstRuleIndex, int& lastRuleIndex, bool includeEmptyRules)
750 {
751 if (!rules)
752 return;
753 // In some cases we may end up looking up style for random elements in the middle of a recursive tree resolve.
754 // Ancestor identifier filter won't be up-to-date in that case and we can't use the fast path.
755 bool canUseFastReject = !m_parentStack.isEmpty() && m_parentStack.last().element == m_parentNode;
756
757 unsigned size = rules->size();
758 for (unsigned i = 0; i < size; ++i) {
759 const RuleData& ruleData = rules->at(i);
760 if (canUseFastReject && fastRejectSelector(ruleData))
761 continue;
762 if (checkSelector(ruleData)) {
763 // If the rule has no properties to apply, then ignore it in the non-debug mode.
764 CSSStyleRule* rule = ruleData.rule();
765 CSSMutableStyleDeclaration* decl = rule->declaration();
766 if (!decl || (!decl->length() && !includeEmptyRules))
767 continue;
768 if (m_checker.m_sameOriginOnly && !m_checker.m_document->securityOrigin()->canRequest(rule->baseURL()))
769 continue;
770 // If we're matching normal rules, set a pseudo bit if
771 // we really just matched a pseudo-element.
772 if (m_dynamicPseudo != NOPSEUDO && m_checker.m_pseudoStyle == NOPSEUDO) {
773 if (m_checker.m_collectRulesOnly)
774 continue;
775 if (m_dynamicPseudo < FIRST_INTERNAL_PSEUDOID)
776 m_style->setHasPseudoStyle(m_dynamicPseudo);
777 } else {
778 // Update our first/last rule indices in the matched rules array.
779 lastRuleIndex = m_matchedDecls.size() + m_matchedRules.size();
780 if (firstRuleIndex == -1)
781 firstRuleIndex = lastRuleIndex;
782
783 // Add this rule to our list of matched rules.
784 addMatchedRule(&ruleData);
785 }
786 }
787 }
788 }
789
compareRules(const RuleData * r1,const RuleData * r2)790 static inline bool compareRules(const RuleData* r1, const RuleData* r2)
791 {
792 unsigned specificity1 = r1->specificity();
793 unsigned specificity2 = r2->specificity();
794 return (specificity1 == specificity2) ? r1->position() < r2->position() : specificity1 < specificity2;
795 }
796
sortMatchedRules()797 void CSSStyleSelector::sortMatchedRules()
798 {
799 std::sort(m_matchedRules.begin(), m_matchedRules.end(), compareRules);
800 }
801
determineLinkState(Element * element) const802 inline EInsideLink CSSStyleSelector::SelectorChecker::determineLinkState(Element* element) const
803 {
804 if (!element || !element->isLink())
805 return NotInsideLink;
806 return determineLinkStateSlowCase(element);
807 }
808
initElement(Element * e)809 inline void CSSStyleSelector::initElement(Element* e)
810 {
811 if (m_element != e) {
812 m_element = e;
813 m_styledElement = m_element && m_element->isStyledElement() ? static_cast<StyledElement*>(m_element) : 0;
814 m_elementLinkState = m_checker.determineLinkState(m_element);
815 if (e && e == e->document()->documentElement()) {
816 e->document()->setDirectionSetOnDocumentElement(false);
817 e->document()->setWritingModeSetOnDocumentElement(false);
818 }
819 }
820 }
821
initForStyleResolve(Element * e,RenderStyle * parentStyle,PseudoId pseudoID)822 inline void CSSStyleSelector::initForStyleResolve(Element* e, RenderStyle* parentStyle, PseudoId pseudoID)
823 {
824 m_checker.m_pseudoStyle = pseudoID;
825
826 m_parentNode = e ? e->parentNodeForRenderingAndStyle() : 0;
827
828 if (parentStyle)
829 m_parentStyle = parentStyle;
830 else
831 m_parentStyle = m_parentNode ? m_parentNode->renderStyle() : 0;
832
833 Node* docElement = e ? e->document()->documentElement() : 0;
834 RenderStyle* docStyle = m_checker.m_document->renderStyle();
835 m_rootElementStyle = docElement && e != docElement ? docElement->renderStyle() : docStyle;
836
837 m_style = 0;
838
839 m_matchedDecls.clear();
840
841 m_pendingImageProperties.clear();
842
843 m_ruleList = 0;
844
845 m_fontDirty = false;
846 }
847
linkAttribute(Node * node)848 static inline const AtomicString* linkAttribute(Node* node)
849 {
850 if (!node->isLink())
851 return 0;
852
853 ASSERT(node->isElementNode());
854 Element* element = static_cast<Element*>(node);
855 if (element->isHTMLElement())
856 return &element->fastGetAttribute(hrefAttr);
857
858 #if ENABLE(WML)
859 if (element->isWMLElement()) {
860 // <anchor> elements don't have href attributes, but we still want to
861 // appear as link, so linkAttribute() has to return a non-null value!
862 if (element->hasTagName(WMLNames::anchorTag))
863 return &emptyAtom;
864
865 return &element->fastGetAttribute(hrefAttr);
866 }
867 #endif
868
869 #if ENABLE(SVG)
870 if (element->isSVGElement())
871 return &element->fastGetAttribute(XLinkNames::hrefAttr);
872 #endif
873
874 return 0;
875 }
876
SelectorChecker(Document * document,bool strictParsing)877 CSSStyleSelector::SelectorChecker::SelectorChecker(Document* document, bool strictParsing)
878 : m_document(document)
879 , m_strictParsing(strictParsing)
880 , m_collectRulesOnly(false)
881 , m_sameOriginOnly(false)
882 , m_pseudoStyle(NOPSEUDO)
883 , m_documentIsHTML(document->isHTMLDocument())
884 , m_matchVisitedPseudoClass(false)
885 {
886 }
887
determineLinkStateSlowCase(Element * element) const888 EInsideLink CSSStyleSelector::SelectorChecker::determineLinkStateSlowCase(Element* element) const
889 {
890 ASSERT(element->isLink());
891
892 const AtomicString* attr = linkAttribute(element);
893 if (!attr || attr->isNull())
894 return NotInsideLink;
895
896 #if PLATFORM(QT)
897 Vector<UChar, 512> url;
898 visitedURL(m_document->baseURL(), *attr, url);
899 if (url.isEmpty())
900 return InsideUnvisitedLink;
901
902 // If the Qt4.4 interface for the history is used, we will have to fallback
903 // to the old global history.
904 QWebHistoryInterface* iface = QWebHistoryInterface::defaultInterface();
905 if (iface)
906 return iface->historyContains(QString(reinterpret_cast<QChar*>(url.data()), url.size())) ? InsideVisitedLink : InsideUnvisitedLink;
907
908 LinkHash hash = visitedLinkHash(url.data(), url.size());
909 if (!hash)
910 return InsideUnvisitedLink;
911 #else
912 LinkHash hash = visitedLinkHash(m_document->baseURL(), *attr);
913 if (!hash)
914 return InsideUnvisitedLink;
915 #endif
916
917 Frame* frame = m_document->frame();
918 if (!frame)
919 return InsideUnvisitedLink;
920
921 Page* page = frame->page();
922 if (!page)
923 return InsideUnvisitedLink;
924
925 m_linksCheckedForVisitedState.add(hash);
926
927 #if USE(PLATFORM_STRATEGIES)
928 return platformStrategies()->visitedLinkStrategy()->isLinkVisited(page, hash) ? InsideVisitedLink : InsideUnvisitedLink;
929 #else
930 return page->group().isLinkVisited(hash) ? InsideVisitedLink : InsideUnvisitedLink;
931 #endif
932 }
933
checkSelector(CSSSelector * sel,Element * element) const934 bool CSSStyleSelector::SelectorChecker::checkSelector(CSSSelector* sel, Element* element) const
935 {
936 PseudoId dynamicPseudo = NOPSEUDO;
937 return checkSelector(sel, element, 0, dynamicPseudo, false, false) == SelectorMatches;
938 }
939
940 static const unsigned cStyleSearchThreshold = 10;
941 static const unsigned cStyleSearchLevelThreshold = 10;
942
locateCousinList(Element * parent,unsigned & visitedNodeCount) const943 Node* CSSStyleSelector::locateCousinList(Element* parent, unsigned& visitedNodeCount) const
944 {
945 if (visitedNodeCount >= cStyleSearchThreshold * cStyleSearchLevelThreshold)
946 return 0;
947 if (!parent || !parent->isStyledElement())
948 return 0;
949 StyledElement* p = static_cast<StyledElement*>(parent);
950 if (p->inlineStyleDecl())
951 return 0;
952 if (p->hasID() && m_features.idsInRules.contains(p->idForStyleResolution().impl()))
953 return 0;
954
955 RenderStyle* parentStyle = p->renderStyle();
956 unsigned subcount = 0;
957 Node* thisCousin = p;
958 Node* currentNode = p->previousSibling();
959
960 // Reserve the tries for this level. This effectively makes sure that the algorithm
961 // will never go deeper than cStyleSearchLevelThreshold levels into recursion.
962 visitedNodeCount += cStyleSearchThreshold;
963 while (thisCousin) {
964 while (currentNode) {
965 ++subcount;
966 if (currentNode->renderStyle() == parentStyle && currentNode->lastChild()) {
967 // Adjust for unused reserved tries.
968 visitedNodeCount -= cStyleSearchThreshold - subcount;
969 return currentNode->lastChild();
970 }
971 if (subcount >= cStyleSearchThreshold)
972 return 0;
973 currentNode = currentNode->previousSibling();
974 }
975 currentNode = locateCousinList(thisCousin->parentElement(), visitedNodeCount);
976 thisCousin = currentNode;
977 }
978
979 return 0;
980 }
981
matchesSiblingRules()982 bool CSSStyleSelector::matchesSiblingRules()
983 {
984 int firstSiblingRule = -1, lastSiblingRule = -1;
985 matchRules(m_features.siblingRules.get(), firstSiblingRule, lastSiblingRule, false);
986 if (m_matchedDecls.isEmpty())
987 return false;
988 m_matchedDecls.clear();
989 return true;
990 }
991
canShareStyleWithElement(Node * node) const992 bool CSSStyleSelector::canShareStyleWithElement(Node* node) const
993 {
994 if (!node->isStyledElement())
995 return false;
996
997 StyledElement* element = static_cast<StyledElement*>(node);
998 RenderStyle* style = element->renderStyle();
999
1000 if (!style)
1001 return false;
1002 if (style->unique())
1003 return false;
1004 if (element->tagQName() != m_element->tagQName())
1005 return false;
1006 if (element->hasClass() != m_element->hasClass())
1007 return false;
1008 if (element->inlineStyleDecl())
1009 return false;
1010 if (element->hasMappedAttributes() != m_styledElement->hasMappedAttributes())
1011 return false;
1012 if (element->isLink() != m_element->isLink())
1013 return false;
1014 if (style->affectedByAttributeSelectors())
1015 return false;
1016 if (element->hovered() != m_element->hovered())
1017 return false;
1018 if (element->active() != m_element->active())
1019 return false;
1020 if (element->focused() != m_element->focused())
1021 return false;
1022 if (element->shadowPseudoId() != m_element->shadowPseudoId())
1023 return false;
1024 if (element == element->document()->cssTarget())
1025 return false;
1026 if (m_element == m_element->document()->cssTarget())
1027 return false;
1028 if (element->fastGetAttribute(typeAttr) != m_element->fastGetAttribute(typeAttr))
1029 return false;
1030 if (element->fastGetAttribute(XMLNames::langAttr) != m_element->fastGetAttribute(XMLNames::langAttr))
1031 return false;
1032 if (element->fastGetAttribute(langAttr) != m_element->fastGetAttribute(langAttr))
1033 return false;
1034 if (element->fastGetAttribute(readonlyAttr) != m_element->fastGetAttribute(readonlyAttr))
1035 return false;
1036 if (element->fastGetAttribute(cellpaddingAttr) != m_element->fastGetAttribute(cellpaddingAttr))
1037 return false;
1038
1039 if (element->hasID() && m_features.idsInRules.contains(element->idForStyleResolution().impl()))
1040 return false;
1041
1042 bool isControl = element->isFormControlElement();
1043
1044 if (isControl != m_element->isFormControlElement())
1045 return false;
1046
1047 if (isControl) {
1048 InputElement* thisInputElement = element->toInputElement();
1049 InputElement* otherInputElement = m_element->toInputElement();
1050
1051 if (!thisInputElement || !otherInputElement)
1052 return false;
1053
1054 if (thisInputElement->isAutofilled() != otherInputElement->isAutofilled())
1055 return false;
1056 if (thisInputElement->isChecked() != otherInputElement->isChecked())
1057 return false;
1058 if (thisInputElement->isIndeterminate() != otherInputElement->isIndeterminate())
1059 return false;
1060
1061 if (element->isEnabledFormControl() != m_element->isEnabledFormControl())
1062 return false;
1063
1064 if (element->isDefaultButtonForForm() != m_element->isDefaultButtonForForm())
1065 return false;
1066
1067 if (!m_element->document()->containsValidityStyleRules())
1068 return false;
1069
1070 bool willValidate = element->willValidate();
1071
1072 if (willValidate != m_element->willValidate())
1073 return false;
1074
1075 if (willValidate && (element->isValidFormControlElement() != m_element->isValidFormControlElement()))
1076 return false;
1077
1078 if (element->isInRange() != m_element->isInRange())
1079 return false;
1080
1081 if (element->isOutOfRange() != m_element->isOutOfRange())
1082 return false;
1083 }
1084
1085 if (style->transitions() || style->animations())
1086 return false;
1087
1088 #if USE(ACCELERATED_COMPOSITING)
1089 // Turn off style sharing for elements that can gain layers for reasons outside of the style system.
1090 // See comments in RenderObject::setStyle().
1091 if (element->hasTagName(iframeTag) || element->hasTagName(frameTag) || element->hasTagName(embedTag) || element->hasTagName(objectTag) || element->hasTagName(appletTag))
1092 return false;
1093 #endif
1094
1095 if (equalIgnoringCase(element->fastGetAttribute(dirAttr), "auto") || equalIgnoringCase(m_element->fastGetAttribute(dirAttr), "auto"))
1096 return false;
1097
1098 if (element->hasClass() && m_element->fastGetAttribute(classAttr) != element->fastGetAttribute(classAttr))
1099 return false;
1100
1101 if (element->hasMappedAttributes() && !element->attributeMap()->mappedMapsEquivalent(m_styledElement->attributeMap()))
1102 return false;
1103
1104 if (element->isLink() && m_elementLinkState != style->insideLink())
1105 return false;
1106
1107 return true;
1108 }
1109
findSiblingForStyleSharing(Node * node,unsigned & count) const1110 inline Node* CSSStyleSelector::findSiblingForStyleSharing(Node* node, unsigned& count) const
1111 {
1112 for (; node; node = node->previousSibling()) {
1113 if (!node->isElementNode())
1114 continue;
1115 if (canShareStyleWithElement(node))
1116 break;
1117 if (count++ == cStyleSearchThreshold)
1118 return 0;
1119 }
1120 return node;
1121 }
1122
parentStylePreventsSharing(const RenderStyle * parentStyle)1123 static inline bool parentStylePreventsSharing(const RenderStyle* parentStyle)
1124 {
1125 return parentStyle->childrenAffectedByPositionalRules()
1126 || parentStyle->childrenAffectedByFirstChildRules()
1127 || parentStyle->childrenAffectedByLastChildRules()
1128 || parentStyle->childrenAffectedByDirectAdjacentRules();
1129 }
1130
locateSharedStyle()1131 ALWAYS_INLINE RenderStyle* CSSStyleSelector::locateSharedStyle()
1132 {
1133 if (!m_styledElement || !m_parentStyle)
1134 return 0;
1135 // If the element has inline style it is probably unique.
1136 if (m_styledElement->inlineStyleDecl())
1137 return 0;
1138 // Ids stop style sharing if they show up in the stylesheets.
1139 if (m_styledElement->hasID() && m_features.idsInRules.contains(m_styledElement->idForStyleResolution().impl()))
1140 return 0;
1141 if (parentStylePreventsSharing(m_parentStyle))
1142 return 0;
1143
1144 // Check previous siblings and their cousins.
1145 unsigned count = 0;
1146 unsigned visitedNodeCount = 0;
1147 Node* shareNode = 0;
1148 Node* cousinList = m_styledElement->previousSibling();
1149 while (cousinList) {
1150 shareNode = findSiblingForStyleSharing(cousinList, count);
1151 if (shareNode)
1152 break;
1153 cousinList = locateCousinList(cousinList->parentElement(), visitedNodeCount);
1154 }
1155
1156 // If we have exhausted all our budget or our cousins.
1157 if (!shareNode)
1158 return 0;
1159
1160 // Can't share if sibling rules apply. This is checked at the end as it should rarely fail.
1161 if (matchesSiblingRules())
1162 return 0;
1163 // Tracking child index requires unique style for each node. This may get set by the sibling rule match above.
1164 if (parentStylePreventsSharing(m_parentStyle))
1165 return 0;
1166 return shareNode->renderStyle();
1167 }
1168
matchUARules(int & firstUARule,int & lastUARule)1169 void CSSStyleSelector::matchUARules(int& firstUARule, int& lastUARule)
1170 {
1171 // First we match rules from the user agent sheet.
1172 RuleSet* userAgentStyleSheet = m_medium->mediaTypeMatchSpecific("print")
1173 ? defaultPrintStyle : defaultStyle;
1174 matchRules(userAgentStyleSheet, firstUARule, lastUARule, false);
1175
1176 // In quirks mode, we match rules from the quirks user agent sheet.
1177 if (!m_checker.m_strictParsing)
1178 matchRules(defaultQuirksStyle, firstUARule, lastUARule, false);
1179
1180 // If document uses view source styles (in view source mode or in xml viewer mode), then we match rules from the view source style sheet.
1181 if (m_checker.m_document->usesViewSourceStyles()) {
1182 if (!defaultViewSourceStyle)
1183 loadViewSourceStyle();
1184 matchRules(defaultViewSourceStyle, firstUARule, lastUARule, false);
1185 }
1186 }
1187
styleForDocument(Document * document)1188 PassRefPtr<RenderStyle> CSSStyleSelector::styleForDocument(Document* document)
1189 {
1190 Frame* frame = document->frame();
1191
1192 RefPtr<RenderStyle> documentStyle = RenderStyle::create();
1193 documentStyle->setDisplay(BLOCK);
1194 documentStyle->setVisuallyOrdered(document->visuallyOrdered());
1195 documentStyle->setZoom(frame ? frame->pageZoomFactor() : 1);
1196 documentStyle->setPageScaleTransform(frame ? frame->pageScaleFactor() : 1);
1197 documentStyle->setUserModify(document->inDesignMode() ? READ_WRITE : READ_ONLY);
1198
1199 Element* docElement = document->documentElement();
1200 RenderObject* docElementRenderer = docElement ? docElement->renderer() : 0;
1201 if (docElementRenderer) {
1202 // Use the direction and writing-mode of the body to set the
1203 // viewport's direction and writing-mode unless the property is set on the document element.
1204 // If there is no body, then use the document element.
1205 RenderObject* bodyRenderer = document->body() ? document->body()->renderer() : 0;
1206 if (bodyRenderer && !document->writingModeSetOnDocumentElement())
1207 documentStyle->setWritingMode(bodyRenderer->style()->writingMode());
1208 else
1209 documentStyle->setWritingMode(docElementRenderer->style()->writingMode());
1210 if (bodyRenderer && !document->directionSetOnDocumentElement())
1211 documentStyle->setDirection(bodyRenderer->style()->direction());
1212 else
1213 documentStyle->setDirection(docElementRenderer->style()->direction());
1214 }
1215
1216 FontDescription fontDescription;
1217 fontDescription.setUsePrinterFont(document->printing());
1218 if (Settings* settings = document->settings()) {
1219 fontDescription.setRenderingMode(settings->fontRenderingMode());
1220 if (document->printing() && !settings->shouldPrintBackgrounds())
1221 documentStyle->setForceBackgroundsToWhite(true);
1222 const AtomicString& stdfont = settings->standardFontFamily();
1223 if (!stdfont.isEmpty()) {
1224 fontDescription.firstFamily().setFamily(stdfont);
1225 fontDescription.firstFamily().appendFamily(0);
1226 }
1227 fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1);
1228 int size = CSSStyleSelector::fontSizeForKeyword(document, CSSValueMedium, false);
1229 fontDescription.setSpecifiedSize(size);
1230 bool useSVGZoomRules = document->isSVGDocument();
1231 fontDescription.setComputedSize(CSSStyleSelector::getComputedSizeFromSpecifiedSize(document, documentStyle.get(), fontDescription.isAbsoluteSize(), size, useSVGZoomRules));
1232 }
1233
1234 documentStyle->setFontDescription(fontDescription);
1235 documentStyle->font().update(0);
1236
1237 return documentStyle.release();
1238 }
1239
1240 // If resolveForRootDefault is true, style based on user agent style sheet only. This is used in media queries, where
1241 // relative units are interpreted according to document root element style, styled only with UA stylesheet
1242
styleForElement(Element * e,RenderStyle * defaultParent,bool allowSharing,bool resolveForRootDefault,bool matchVisitedPseudoClass)1243 PassRefPtr<RenderStyle> CSSStyleSelector::styleForElement(Element* e, RenderStyle* defaultParent, bool allowSharing, bool resolveForRootDefault, bool matchVisitedPseudoClass)
1244 {
1245 // Once an element has a renderer, we don't try to destroy it, since otherwise the renderer
1246 // will vanish if a style recalc happens during loading.
1247 if (allowSharing && !e->document()->haveStylesheetsLoaded() && !e->renderer()) {
1248 if (!s_styleNotYetAvailable) {
1249 s_styleNotYetAvailable = RenderStyle::create().releaseRef();
1250 s_styleNotYetAvailable->ref();
1251 s_styleNotYetAvailable->setDisplay(NONE);
1252 s_styleNotYetAvailable->font().update(m_fontSelector);
1253 }
1254 s_styleNotYetAvailable->ref();
1255 e->document()->setHasNodesWithPlaceholderStyle();
1256 return s_styleNotYetAvailable;
1257 }
1258
1259 initElement(e);
1260 initForStyleResolve(e, defaultParent);
1261 if (allowSharing) {
1262 RenderStyle* sharedStyle = locateSharedStyle();
1263 if (sharedStyle)
1264 return sharedStyle;
1265 }
1266
1267 // Compute our style allowing :visited to match first.
1268 RefPtr<RenderStyle> visitedStyle;
1269 if (!matchVisitedPseudoClass && m_parentStyle && (m_parentStyle->insideLink() || e->isLink()) && e->document()->usesLinkRules()) {
1270 // Fetch our parent style.
1271 RenderStyle* parentStyle = m_parentStyle;
1272 if (!e->isLink()) {
1273 // Use the parent's visited style if one exists.
1274 RenderStyle* parentVisitedStyle = m_parentStyle->getCachedPseudoStyle(VISITED_LINK);
1275 if (parentVisitedStyle)
1276 parentStyle = parentVisitedStyle;
1277 }
1278 visitedStyle = styleForElement(e, parentStyle, false, false, true);
1279 initForStyleResolve(e, defaultParent);
1280 }
1281
1282 m_checker.m_matchVisitedPseudoClass = matchVisitedPseudoClass;
1283
1284 m_style = RenderStyle::create();
1285
1286 if (m_parentStyle)
1287 m_style->inheritFrom(m_parentStyle);
1288 else {
1289 m_parentStyle = style();
1290 // Make sure our fonts are initialized if we don't inherit them from our parent style.
1291 m_style->font().update(0);
1292 }
1293
1294 if (e->isLink()) {
1295 m_style->setIsLink(true);
1296 m_style->setInsideLink(m_elementLinkState);
1297 }
1298
1299 if (visitedStyle) {
1300 // Copy any pseudo bits that the visited style has to the primary style so that
1301 // pseudo element styles will continue to work for pseudo elements inside :visited
1302 // links.
1303 for (unsigned pseudo = FIRST_PUBLIC_PSEUDOID; pseudo < FIRST_INTERNAL_PSEUDOID; ++pseudo) {
1304 if (visitedStyle->hasPseudoStyle(static_cast<PseudoId>(pseudo)))
1305 m_style->setHasPseudoStyle(static_cast<PseudoId>(pseudo));
1306 }
1307 if (m_elementLinkState == InsideUnvisitedLink)
1308 visitedStyle = 0; // We made the style to avoid timing attacks. Just throw it away now that we did that, since we don't need it.
1309 else
1310 visitedStyle->setStyleType(VISITED_LINK);
1311 }
1312
1313 if (simpleDefaultStyleSheet && !elementCanUseSimpleDefaultStyle(e)) {
1314 loadFullDefaultStyle();
1315 assertNoSiblingRulesInDefaultStyle();
1316 }
1317
1318 #if ENABLE(SVG)
1319 static bool loadedSVGUserAgentSheet;
1320 if (e->isSVGElement() && !loadedSVGUserAgentSheet) {
1321 // SVG rules.
1322 loadedSVGUserAgentSheet = true;
1323 CSSStyleSheet* svgSheet = parseUASheet(svgUserAgentStyleSheet, sizeof(svgUserAgentStyleSheet));
1324 defaultStyle->addRulesFromSheet(svgSheet, screenEval());
1325 defaultPrintStyle->addRulesFromSheet(svgSheet, printEval());
1326 assertNoSiblingRulesInDefaultStyle();
1327 }
1328 #endif
1329
1330 #if ENABLE(MATHML)
1331 static bool loadedMathMLUserAgentSheet;
1332 if (e->isMathMLElement() && !loadedMathMLUserAgentSheet) {
1333 // MathML rules.
1334 loadedMathMLUserAgentSheet = true;
1335 CSSStyleSheet* mathMLSheet = parseUASheet(mathmlUserAgentStyleSheet, sizeof(mathmlUserAgentStyleSheet));
1336 defaultStyle->addRulesFromSheet(mathMLSheet, screenEval());
1337 defaultPrintStyle->addRulesFromSheet(mathMLSheet, printEval());
1338 // There are some sibling rules here.
1339 collectSiblingRulesInDefaultStyle();
1340 }
1341 #endif
1342
1343 #if ENABLE(WML)
1344 static bool loadedWMLUserAgentSheet;
1345 if (e->isWMLElement() && !loadedWMLUserAgentSheet) {
1346 // WML rules.
1347 loadedWMLUserAgentSheet = true;
1348 CSSStyleSheet* wmlSheet = parseUASheet(wmlUserAgentStyleSheet, sizeof(wmlUserAgentStyleSheet));
1349 defaultStyle->addRulesFromSheet(wmlSheet, screenEval());
1350 defaultPrintStyle->addRulesFromSheet(wmlSheet, printEval());
1351 assertNoSiblingRulesInDefaultStyle();
1352 }
1353 #endif
1354
1355 #if ENABLE(VIDEO)
1356 static bool loadedMediaStyleSheet;
1357 if (!loadedMediaStyleSheet && (e->hasTagName(videoTag) || e->hasTagName(audioTag))) {
1358 loadedMediaStyleSheet = true;
1359 String mediaRules = String(mediaControlsUserAgentStyleSheet, sizeof(mediaControlsUserAgentStyleSheet)) + RenderTheme::themeForPage(e->document()->page())->extraMediaControlsStyleSheet();
1360 CSSStyleSheet* mediaControlsSheet = parseUASheet(mediaRules);
1361 defaultStyle->addRulesFromSheet(mediaControlsSheet, screenEval());
1362 defaultPrintStyle->addRulesFromSheet(mediaControlsSheet, printEval());
1363 assertNoSiblingRulesInDefaultStyle();
1364 }
1365 #endif
1366
1367 #if ENABLE(FULLSCREEN_API)
1368 static bool loadedFullScreenStyleSheet;
1369 if (!loadedFullScreenStyleSheet && e->document()->webkitIsFullScreen()) {
1370 loadedFullScreenStyleSheet = true;
1371 String fullscreenRules = String(fullscreenUserAgentStyleSheet, sizeof(fullscreenUserAgentStyleSheet)) + RenderTheme::defaultTheme()->extraFullScreenStyleSheet();
1372 CSSStyleSheet* fullscreenSheet = parseUASheet(fullscreenRules);
1373 defaultStyle->addRulesFromSheet(fullscreenSheet, screenEval());
1374 defaultQuirksStyle->addRulesFromSheet(fullscreenSheet, screenEval());
1375 }
1376 #endif
1377
1378 int firstUARule = -1, lastUARule = -1;
1379 int firstUserRule = -1, lastUserRule = -1;
1380 int firstAuthorRule = -1, lastAuthorRule = -1;
1381 matchUARules(firstUARule, lastUARule);
1382
1383 if (!resolveForRootDefault) {
1384 // 4. Now we check user sheet rules.
1385 if (m_matchAuthorAndUserStyles)
1386 matchRules(m_userStyle.get(), firstUserRule, lastUserRule, false);
1387
1388 // 5. Now check author rules, beginning first with presentational attributes
1389 // mapped from HTML.
1390 if (m_styledElement) {
1391 // Ask if the HTML element has mapped attributes.
1392 if (m_styledElement->hasMappedAttributes()) {
1393 // Walk our attribute list and add in each decl.
1394 const NamedNodeMap* map = m_styledElement->attributeMap();
1395 for (unsigned i = 0; i < map->length(); i++) {
1396 Attribute* attr = map->attributeItem(i);
1397 if (attr->isMappedAttribute() && attr->decl()) {
1398 lastAuthorRule = m_matchedDecls.size();
1399 if (firstAuthorRule == -1)
1400 firstAuthorRule = lastAuthorRule;
1401 addMatchedDeclaration(attr->decl());
1402 }
1403 }
1404 }
1405
1406 // Now we check additional mapped declarations.
1407 // Tables and table cells share an additional mapped rule that must be applied
1408 // after all attributes, since their mapped style depends on the values of multiple attributes.
1409 if (m_styledElement->canHaveAdditionalAttributeStyleDecls()) {
1410 m_additionalAttributeStyleDecls.clear();
1411 m_styledElement->additionalAttributeStyleDecls(m_additionalAttributeStyleDecls);
1412 if (!m_additionalAttributeStyleDecls.isEmpty()) {
1413 unsigned additionalDeclsSize = m_additionalAttributeStyleDecls.size();
1414 if (firstAuthorRule == -1)
1415 firstAuthorRule = m_matchedDecls.size();
1416 lastAuthorRule = m_matchedDecls.size() + additionalDeclsSize - 1;
1417 for (unsigned i = 0; i < additionalDeclsSize; i++)
1418 addMatchedDeclaration(m_additionalAttributeStyleDecls[i]);
1419 }
1420 }
1421 if (m_styledElement->isHTMLElement()) {
1422 bool isAuto;
1423 TextDirection textDirection = toHTMLElement(m_styledElement)->directionalityIfhasDirAutoAttribute(isAuto);
1424 if (isAuto)
1425 addMatchedDeclaration(textDirection == LTR ? leftToRightDeclaration() : rightToLeftDeclaration());
1426 }
1427 }
1428
1429 // 6. Check the rules in author sheets next.
1430 if (m_matchAuthorAndUserStyles)
1431 matchRules(m_authorStyle.get(), firstAuthorRule, lastAuthorRule, false);
1432
1433 // 7. Now check our inline style attribute.
1434 if (m_matchAuthorAndUserStyles && m_styledElement) {
1435 CSSMutableStyleDeclaration* inlineDecl = m_styledElement->inlineStyleDecl();
1436 if (inlineDecl) {
1437 lastAuthorRule = m_matchedDecls.size();
1438 if (firstAuthorRule == -1)
1439 firstAuthorRule = lastAuthorRule;
1440 addMatchedDeclaration(inlineDecl);
1441 }
1442 }
1443 }
1444
1445 // Reset the value back before applying properties, so that -webkit-link knows what color to use.
1446 m_checker.m_matchVisitedPseudoClass = matchVisitedPseudoClass;
1447
1448 // Now we have all of the matched rules in the appropriate order. Walk the rules and apply
1449 // high-priority properties first, i.e., those properties that other properties depend on.
1450 // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important
1451 // and (4) normal important.
1452 m_lineHeightValue = 0;
1453 applyDeclarations<true>(false, 0, m_matchedDecls.size() - 1);
1454 if (!resolveForRootDefault) {
1455 applyDeclarations<true>(true, firstAuthorRule, lastAuthorRule);
1456 applyDeclarations<true>(true, firstUserRule, lastUserRule);
1457 }
1458 applyDeclarations<true>(true, firstUARule, lastUARule);
1459
1460 // If our font got dirtied, go ahead and update it now.
1461 if (m_fontDirty)
1462 updateFont();
1463
1464 // Line-height is set when we are sure we decided on the font-size
1465 if (m_lineHeightValue)
1466 applyProperty(CSSPropertyLineHeight, m_lineHeightValue);
1467
1468 // Now do the normal priority UA properties.
1469 applyDeclarations<false>(false, firstUARule, lastUARule);
1470
1471 // Cache our border and background so that we can examine them later.
1472 cacheBorderAndBackground();
1473
1474 // Now do the author and user normal priority properties and all the !important properties.
1475 if (!resolveForRootDefault) {
1476 applyDeclarations<false>(false, lastUARule + 1, m_matchedDecls.size() - 1);
1477 applyDeclarations<false>(true, firstAuthorRule, lastAuthorRule);
1478 applyDeclarations<false>(true, firstUserRule, lastUserRule);
1479 }
1480 applyDeclarations<false>(true, firstUARule, lastUARule);
1481
1482 ASSERT(!m_fontDirty);
1483 // If our font got dirtied by one of the non-essential font props,
1484 // go ahead and update it a second time.
1485 if (m_fontDirty)
1486 updateFont();
1487
1488 // Clean up our style object's display and text decorations (among other fixups).
1489 adjustRenderStyle(style(), m_parentStyle, e);
1490
1491 // Start loading images referenced by this style.
1492 loadPendingImages();
1493
1494 // If we have first-letter pseudo style, do not share this style
1495 if (m_style->hasPseudoStyle(FIRST_LETTER))
1496 m_style->setUnique();
1497
1498 if (visitedStyle) {
1499 // Add the visited style off the main style.
1500 m_style->addCachedPseudoStyle(visitedStyle.release());
1501 }
1502
1503 if (!matchVisitedPseudoClass)
1504 initElement(0); // Clear out for the next resolve.
1505
1506 // Now return the style.
1507 return m_style.release();
1508 }
1509
styleForKeyframe(const RenderStyle * elementStyle,const WebKitCSSKeyframeRule * keyframeRule,KeyframeValue & keyframe)1510 PassRefPtr<RenderStyle> CSSStyleSelector::styleForKeyframe(const RenderStyle* elementStyle, const WebKitCSSKeyframeRule* keyframeRule, KeyframeValue& keyframe)
1511 {
1512 if (keyframeRule->style())
1513 addMatchedDeclaration(keyframeRule->style());
1514
1515 ASSERT(!m_style);
1516
1517 // Create the style
1518 m_style = RenderStyle::clone(elementStyle);
1519
1520 m_lineHeightValue = 0;
1521
1522 // We don't need to bother with !important. Since there is only ever one
1523 // decl, there's nothing to override. So just add the first properties.
1524 if (keyframeRule->style())
1525 applyDeclarations<true>(false, 0, m_matchedDecls.size() - 1);
1526
1527 // If our font got dirtied, go ahead and update it now.
1528 if (m_fontDirty)
1529 updateFont();
1530
1531 // Line-height is set when we are sure we decided on the font-size
1532 if (m_lineHeightValue)
1533 applyProperty(CSSPropertyLineHeight, m_lineHeightValue);
1534
1535 // Now do rest of the properties.
1536 if (keyframeRule->style())
1537 applyDeclarations<false>(false, 0, m_matchedDecls.size() - 1);
1538
1539 // If our font got dirtied by one of the non-essential font props,
1540 // go ahead and update it a second time.
1541 if (m_fontDirty)
1542 updateFont();
1543
1544 // Start loading images referenced by this style.
1545 loadPendingImages();
1546
1547 // Add all the animating properties to the keyframe.
1548 if (keyframeRule->style()) {
1549 CSSMutableStyleDeclaration::const_iterator end = keyframeRule->style()->end();
1550 for (CSSMutableStyleDeclaration::const_iterator it = keyframeRule->style()->begin(); it != end; ++it) {
1551 int property = (*it).id();
1552 // Timing-function within keyframes is special, because it is not animated; it just
1553 // describes the timing function between this keyframe and the next.
1554 if (property != CSSPropertyWebkitAnimationTimingFunction)
1555 keyframe.addProperty(property);
1556 }
1557 }
1558
1559 return m_style.release();
1560 }
1561
keyframeStylesForAnimation(Element * e,const RenderStyle * elementStyle,KeyframeList & list)1562 void CSSStyleSelector::keyframeStylesForAnimation(Element* e, const RenderStyle* elementStyle, KeyframeList& list)
1563 {
1564 list.clear();
1565
1566 // Get the keyframesRule for this name
1567 if (!e || list.animationName().isEmpty())
1568 return;
1569
1570 m_keyframesRuleMap.checkConsistency();
1571
1572 if (!m_keyframesRuleMap.contains(list.animationName().impl()))
1573 return;
1574
1575 const WebKitCSSKeyframesRule* rule = m_keyframesRuleMap.find(list.animationName().impl()).get()->second.get();
1576
1577 // Construct and populate the style for each keyframe
1578 for (unsigned i = 0; i < rule->length(); ++i) {
1579 // Apply the declaration to the style. This is a simplified version of the logic in styleForElement
1580 initElement(e);
1581 initForStyleResolve(e);
1582
1583 const WebKitCSSKeyframeRule* keyframeRule = rule->item(i);
1584
1585 KeyframeValue keyframe(0, 0);
1586 keyframe.setStyle(styleForKeyframe(elementStyle, keyframeRule, keyframe));
1587
1588 // Add this keyframe style to all the indicated key times
1589 Vector<float> keys;
1590 keyframeRule->getKeys(keys);
1591 for (size_t keyIndex = 0; keyIndex < keys.size(); ++keyIndex) {
1592 keyframe.setKey(keys[keyIndex]);
1593 list.insert(keyframe);
1594 }
1595 }
1596
1597 // If the 0% keyframe is missing, create it (but only if there is at least one other keyframe)
1598 int initialListSize = list.size();
1599 if (initialListSize > 0 && list[0].key() != 0) {
1600 RefPtr<WebKitCSSKeyframeRule> keyframeRule = WebKitCSSKeyframeRule::create();
1601 keyframeRule->setKeyText("0%");
1602 KeyframeValue keyframe(0, 0);
1603 keyframe.setStyle(styleForKeyframe(elementStyle, keyframeRule.get(), keyframe));
1604 list.insert(keyframe);
1605 }
1606
1607 // If the 100% keyframe is missing, create it (but only if there is at least one other keyframe)
1608 if (initialListSize > 0 && (list[list.size() - 1].key() != 1)) {
1609 RefPtr<WebKitCSSKeyframeRule> keyframeRule = WebKitCSSKeyframeRule::create();
1610 keyframeRule->setKeyText("100%");
1611 KeyframeValue keyframe(1, 0);
1612 keyframe.setStyle(styleForKeyframe(elementStyle, keyframeRule.get(), keyframe));
1613 list.insert(keyframe);
1614 }
1615 }
1616
pseudoStyleForElement(PseudoId pseudo,Element * e,RenderStyle * parentStyle,bool matchVisitedPseudoClass)1617 PassRefPtr<RenderStyle> CSSStyleSelector::pseudoStyleForElement(PseudoId pseudo, Element* e, RenderStyle* parentStyle, bool matchVisitedPseudoClass)
1618 {
1619 if (!e)
1620 return 0;
1621
1622 initElement(e);
1623
1624 // Compute our :visited style first, so that we know whether or not we'll need to create a normal style just to hang it
1625 // off of.
1626 RefPtr<RenderStyle> visitedStyle;
1627 if (!matchVisitedPseudoClass && parentStyle && parentStyle->insideLink()) {
1628 // Fetch our parent style with :visited in effect.
1629 RenderStyle* parentVisitedStyle = parentStyle->getCachedPseudoStyle(VISITED_LINK);
1630 visitedStyle = pseudoStyleForElement(pseudo, e, parentVisitedStyle ? parentVisitedStyle : parentStyle, true);
1631 if (visitedStyle)
1632 visitedStyle->setStyleType(VISITED_LINK);
1633 }
1634
1635 initForStyleResolve(e, parentStyle, pseudo);
1636 m_style = RenderStyle::create();
1637 if (parentStyle)
1638 m_style->inheritFrom(parentStyle);
1639
1640 m_checker.m_matchVisitedPseudoClass = matchVisitedPseudoClass;
1641
1642 // Since we don't use pseudo-elements in any of our quirk/print user agent rules, don't waste time walking
1643 // those rules.
1644
1645 // Check UA, user and author rules.
1646 int firstUARule = -1, lastUARule = -1, firstUserRule = -1, lastUserRule = -1, firstAuthorRule = -1, lastAuthorRule = -1;
1647 matchUARules(firstUARule, lastUARule);
1648
1649 if (m_matchAuthorAndUserStyles) {
1650 matchRules(m_userStyle.get(), firstUserRule, lastUserRule, false);
1651 matchRules(m_authorStyle.get(), firstAuthorRule, lastAuthorRule, false);
1652 }
1653
1654 if (m_matchedDecls.isEmpty() && !visitedStyle)
1655 return 0;
1656
1657 m_style->setStyleType(pseudo);
1658
1659 m_lineHeightValue = 0;
1660
1661 // Reset the value back before applying properties, so that -webkit-link knows what color to use.
1662 m_checker.m_matchVisitedPseudoClass = matchVisitedPseudoClass;
1663
1664 // High-priority properties.
1665 applyDeclarations<true>(false, 0, m_matchedDecls.size() - 1);
1666 applyDeclarations<true>(true, firstAuthorRule, lastAuthorRule);
1667 applyDeclarations<true>(true, firstUserRule, lastUserRule);
1668 applyDeclarations<true>(true, firstUARule, lastUARule);
1669
1670 // If our font got dirtied, go ahead and update it now.
1671 if (m_fontDirty)
1672 updateFont();
1673
1674 // Line-height is set when we are sure we decided on the font-size
1675 if (m_lineHeightValue)
1676 applyProperty(CSSPropertyLineHeight, m_lineHeightValue);
1677
1678 // Now do the normal priority properties.
1679 applyDeclarations<false>(false, firstUARule, lastUARule);
1680
1681 // Cache our border and background so that we can examine them later.
1682 cacheBorderAndBackground();
1683
1684 applyDeclarations<false>(false, lastUARule + 1, m_matchedDecls.size() - 1);
1685 applyDeclarations<false>(true, firstAuthorRule, lastAuthorRule);
1686 applyDeclarations<false>(true, firstUserRule, lastUserRule);
1687 applyDeclarations<false>(true, firstUARule, lastUARule);
1688
1689 // If our font got dirtied by one of the non-essential font props,
1690 // go ahead and update it a second time.
1691 if (m_fontDirty)
1692 updateFont();
1693
1694 // Clean up our style object's display and text decorations (among other fixups).
1695 adjustRenderStyle(style(), parentStyle, 0);
1696
1697 // Start loading images referenced by this style.
1698 loadPendingImages();
1699
1700 // Hang our visited style off m_style.
1701 if (visitedStyle)
1702 m_style->addCachedPseudoStyle(visitedStyle.release());
1703
1704 // Now return the style.
1705 return m_style.release();
1706 }
1707
styleForPage(int pageIndex)1708 PassRefPtr<RenderStyle> CSSStyleSelector::styleForPage(int pageIndex)
1709 {
1710 initForStyleResolve(m_checker.m_document->documentElement()); // m_rootElementStyle will be set to the document style.
1711
1712 m_style = RenderStyle::create();
1713 m_style->inheritFrom(m_rootElementStyle);
1714
1715 const bool isLeft = isLeftPage(pageIndex);
1716 const bool isFirst = isFirstPage(pageIndex);
1717 const String page = pageName(pageIndex);
1718 matchPageRules(defaultPrintStyle, isLeft, isFirst, page);
1719 matchPageRules(m_userStyle.get(), isLeft, isFirst, page);
1720 matchPageRules(m_authorStyle.get(), isLeft, isFirst, page);
1721 m_lineHeightValue = 0;
1722 applyDeclarations<true>(false, 0, m_matchedDecls.size() - 1);
1723
1724 // If our font got dirtied, go ahead and update it now.
1725 if (m_fontDirty)
1726 updateFont();
1727
1728 // Line-height is set when we are sure we decided on the font-size
1729 if (m_lineHeightValue)
1730 applyProperty(CSSPropertyLineHeight, m_lineHeightValue);
1731
1732 applyDeclarations<false>(false, 0, m_matchedDecls.size() - 1);
1733
1734 // Start loading images referenced by this style.
1735 loadPendingImages();
1736
1737 // Now return the style.
1738 return m_style.release();
1739 }
1740
1741 #if ENABLE(DATAGRID)
1742
pseudoStyleForDataGridColumn(DataGridColumn *,RenderStyle *)1743 PassRefPtr<RenderStyle> CSSStyleSelector::pseudoStyleForDataGridColumn(DataGridColumn*, RenderStyle*)
1744 {
1745 // FIXME: Implement
1746 return 0;
1747 }
1748
pseudoStyleForDataGridColumnHeader(DataGridColumn *,RenderStyle *)1749 PassRefPtr<RenderStyle> CSSStyleSelector::pseudoStyleForDataGridColumnHeader(DataGridColumn*, RenderStyle*)
1750 {
1751 // FIXME: Implement
1752 return 0;
1753 }
1754
1755 #endif
1756
addIntrinsicMargins(RenderStyle * style)1757 static void addIntrinsicMargins(RenderStyle* style)
1758 {
1759 // Intrinsic margin value.
1760 const int intrinsicMargin = 2 * style->effectiveZoom();
1761
1762 // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed.
1763 // FIXME: Using "quirk" to decide the margin wasn't set is kind of lame.
1764 if (style->width().isIntrinsicOrAuto()) {
1765 if (style->marginLeft().quirk())
1766 style->setMarginLeft(Length(intrinsicMargin, Fixed));
1767 if (style->marginRight().quirk())
1768 style->setMarginRight(Length(intrinsicMargin, Fixed));
1769 }
1770
1771 if (style->height().isAuto()) {
1772 if (style->marginTop().quirk())
1773 style->setMarginTop(Length(intrinsicMargin, Fixed));
1774 if (style->marginBottom().quirk())
1775 style->setMarginBottom(Length(intrinsicMargin, Fixed));
1776 }
1777 }
1778
isAtShadowBoundary(Element * element)1779 static inline bool isAtShadowBoundary(Element* element)
1780 {
1781 if (!element)
1782 return false;
1783
1784 ContainerNode* parentNode = element->parentNode();
1785 return parentNode && parentNode->isShadowBoundary();
1786 }
1787
adjustRenderStyle(RenderStyle * style,RenderStyle * parentStyle,Element * e)1788 void CSSStyleSelector::adjustRenderStyle(RenderStyle* style, RenderStyle* parentStyle, Element *e)
1789 {
1790 // Cache our original display.
1791 style->setOriginalDisplay(style->display());
1792
1793 if (style->display() != NONE) {
1794 // If we have a <td> that specifies a float property, in quirks mode we just drop the float
1795 // property.
1796 // Sites also commonly use display:inline/block on <td>s and <table>s. In quirks mode we force
1797 // these tags to retain their display types.
1798 if (!m_checker.m_strictParsing && e) {
1799 if (e->hasTagName(tdTag)) {
1800 style->setDisplay(TABLE_CELL);
1801 style->setFloating(FNONE);
1802 }
1803 else if (e->hasTagName(tableTag))
1804 style->setDisplay(style->isDisplayInlineType() ? INLINE_TABLE : TABLE);
1805 }
1806
1807 if (e && (e->hasTagName(tdTag) || e->hasTagName(thTag))) {
1808 if (style->whiteSpace() == KHTML_NOWRAP) {
1809 // Figure out if we are really nowrapping or if we should just
1810 // use normal instead. If the width of the cell is fixed, then
1811 // we don't actually use NOWRAP.
1812 if (style->width().isFixed())
1813 style->setWhiteSpace(NORMAL);
1814 else
1815 style->setWhiteSpace(NOWRAP);
1816 }
1817 }
1818
1819 // Tables never support the -webkit-* values for text-align and will reset back to the default.
1820 if (e && e->hasTagName(tableTag) && (style->textAlign() == WEBKIT_LEFT || style->textAlign() == WEBKIT_CENTER || style->textAlign() == WEBKIT_RIGHT))
1821 style->setTextAlign(TAAUTO);
1822
1823 // Frames and framesets never honor position:relative or position:absolute. This is necessary to
1824 // fix a crash where a site tries to position these objects. They also never honor display.
1825 if (e && (e->hasTagName(frameTag) || e->hasTagName(framesetTag))) {
1826 style->setPosition(StaticPosition);
1827 style->setDisplay(BLOCK);
1828 }
1829
1830 // Table headers with a text-align of auto will change the text-align to center.
1831 if (e && e->hasTagName(thTag) && style->textAlign() == TAAUTO)
1832 style->setTextAlign(CENTER);
1833
1834 if (e && e->hasTagName(legendTag))
1835 style->setDisplay(BLOCK);
1836
1837 // Mutate the display to BLOCK or TABLE for certain cases, e.g., if someone attempts to
1838 // position or float an inline, compact, or run-in. Cache the original display, since it
1839 // may be needed for positioned elements that have to compute their static normal flow
1840 // positions. We also force inline-level roots to be block-level.
1841 if (style->display() != BLOCK && style->display() != TABLE && style->display() != BOX &&
1842 (style->position() == AbsolutePosition || style->position() == FixedPosition || style->floating() != FNONE ||
1843 (e && e->document()->documentElement() == e))) {
1844 if (style->display() == INLINE_TABLE)
1845 style->setDisplay(TABLE);
1846 else if (style->display() == INLINE_BOX)
1847 style->setDisplay(BOX);
1848 else if (style->display() == LIST_ITEM) {
1849 // It is a WinIE bug that floated list items lose their bullets, so we'll emulate the quirk,
1850 // but only in quirks mode.
1851 if (!m_checker.m_strictParsing && style->floating() != FNONE)
1852 style->setDisplay(BLOCK);
1853 }
1854 else
1855 style->setDisplay(BLOCK);
1856 }
1857
1858 // FIXME: Don't support this mutation for pseudo styles like first-letter or first-line, since it's not completely
1859 // clear how that should work.
1860 if (style->display() == INLINE && style->styleType() == NOPSEUDO && parentStyle && style->writingMode() != parentStyle->writingMode())
1861 style->setDisplay(INLINE_BLOCK);
1862
1863 // After performing the display mutation, check table rows. We do not honor position:relative on
1864 // table rows or cells. This has been established in CSS2.1 (and caused a crash in containingBlock()
1865 // on some sites).
1866 if ((style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_ROW_GROUP
1867 || style->display() == TABLE_FOOTER_GROUP || style->display() == TABLE_ROW) &&
1868 style->position() == RelativePosition)
1869 style->setPosition(StaticPosition);
1870
1871 // writing-mode does not apply to table row groups, table column groups, table rows, and table columns.
1872 // FIXME: Table cells should be allowed to be perpendicular or flipped with respect to the table, though.
1873 if (style->display() == TABLE_COLUMN || style->display() == TABLE_COLUMN_GROUP || style->display() == TABLE_FOOTER_GROUP
1874 || style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_ROW || style->display() == TABLE_ROW_GROUP
1875 || style->display() == TABLE_CELL)
1876 style->setWritingMode(parentStyle->writingMode());
1877
1878 // FIXME: Since we don't support block-flow on flexible boxes yet, disallow setting
1879 // of block-flow to anything other than TopToBottomWritingMode.
1880 // https://bugs.webkit.org/show_bug.cgi?id=46418 - Flexible box support.
1881 if (style->writingMode() != TopToBottomWritingMode && (style->display() == BOX || style->display() == INLINE_BOX))
1882 style->setWritingMode(TopToBottomWritingMode);
1883 }
1884
1885 // Make sure our z-index value is only applied if the object is positioned.
1886 if (style->position() == StaticPosition)
1887 style->setHasAutoZIndex();
1888
1889 // Auto z-index becomes 0 for the root element and transparent objects. This prevents
1890 // cases where objects that should be blended as a single unit end up with a non-transparent
1891 // object wedged in between them. Auto z-index also becomes 0 for objects that specify transforms/masks/reflections.
1892 if (style->hasAutoZIndex() && ((e && e->document()->documentElement() == e) || style->opacity() < 1.0f ||
1893 style->hasTransformRelatedProperty() || style->hasMask() || style->boxReflect()))
1894 style->setZIndex(0);
1895
1896 #if ENABLE(WML)
1897 if (e && (e->hasTagName(WMLNames::insertedLegendTag)
1898 || e->hasTagName(WMLNames::inputTag))
1899 && style->width().isAuto())
1900 style->setWidth(Length(Intrinsic));
1901 #endif
1902
1903 // Textarea considers overflow visible as auto.
1904 if (e && e->hasTagName(textareaTag)) {
1905 style->setOverflowX(style->overflowX() == OVISIBLE ? OAUTO : style->overflowX());
1906 style->setOverflowY(style->overflowY() == OVISIBLE ? OAUTO : style->overflowY());
1907 }
1908
1909 // Finally update our text decorations in effect, but don't allow text-decoration to percolate through
1910 // tables, inline blocks, inline tables, run-ins, or shadow DOM.
1911 if (style->display() == TABLE || style->display() == INLINE_TABLE || style->display() == RUN_IN
1912 || style->display() == INLINE_BLOCK || style->display() == INLINE_BOX || isAtShadowBoundary(e))
1913 style->setTextDecorationsInEffect(style->textDecoration());
1914 else
1915 style->addToTextDecorationsInEffect(style->textDecoration());
1916
1917 // If either overflow value is not visible, change to auto.
1918 if (style->overflowX() == OMARQUEE && style->overflowY() != OMARQUEE)
1919 style->setOverflowY(OMARQUEE);
1920 else if (style->overflowY() == OMARQUEE && style->overflowX() != OMARQUEE)
1921 style->setOverflowX(OMARQUEE);
1922 else if (style->overflowX() == OVISIBLE && style->overflowY() != OVISIBLE)
1923 style->setOverflowX(OAUTO);
1924 else if (style->overflowY() == OVISIBLE && style->overflowX() != OVISIBLE)
1925 style->setOverflowY(OAUTO);
1926
1927 // Table rows, sections and the table itself will support overflow:hidden and will ignore scroll/auto.
1928 // FIXME: Eventually table sections will support auto and scroll.
1929 if (style->display() == TABLE || style->display() == INLINE_TABLE ||
1930 style->display() == TABLE_ROW_GROUP || style->display() == TABLE_ROW) {
1931 if (style->overflowX() != OVISIBLE && style->overflowX() != OHIDDEN)
1932 style->setOverflowX(OVISIBLE);
1933 if (style->overflowY() != OVISIBLE && style->overflowY() != OHIDDEN)
1934 style->setOverflowY(OVISIBLE);
1935 }
1936
1937 // Menulists should have visible overflow
1938 if (style->appearance() == MenulistPart) {
1939 style->setOverflowX(OVISIBLE);
1940 style->setOverflowY(OVISIBLE);
1941 }
1942
1943 // Cull out any useless layers and also repeat patterns into additional layers.
1944 style->adjustBackgroundLayers();
1945 style->adjustMaskLayers();
1946
1947 // Do the same for animations and transitions.
1948 style->adjustAnimations();
1949 style->adjustTransitions();
1950
1951 // Important: Intrinsic margins get added to controls before the theme has adjusted the style, since the theme will
1952 // alter fonts and heights/widths.
1953 if (e && e->isFormControlElement() && style->fontSize() >= 11) {
1954 // Don't apply intrinsic margins to image buttons. The designer knows how big the images are,
1955 // so we have to treat all image buttons as though they were explicitly sized.
1956 if (!e->hasTagName(inputTag) || !static_cast<HTMLInputElement*>(e)->isImageButton())
1957 addIntrinsicMargins(style);
1958 }
1959
1960 // Let the theme also have a crack at adjusting the style.
1961 if (style->hasAppearance())
1962 RenderTheme::defaultTheme()->adjustStyle(this, style, e, m_hasUAAppearance, m_borderData, m_backgroundData, m_backgroundColor);
1963
1964 #if ENABLE(SVG)
1965 if (e && e->isSVGElement()) {
1966 // Spec: http://www.w3.org/TR/SVG/masking.html#OverflowProperty
1967 if (style->overflowY() == OSCROLL)
1968 style->setOverflowY(OHIDDEN);
1969 else if (style->overflowY() == OAUTO)
1970 style->setOverflowY(OVISIBLE);
1971
1972 if (style->overflowX() == OSCROLL)
1973 style->setOverflowX(OHIDDEN);
1974 else if (style->overflowX() == OAUTO)
1975 style->setOverflowX(OVISIBLE);
1976
1977 // Only the root <svg> element in an SVG document fragment tree honors css position
1978 if (!(e->hasTagName(SVGNames::svgTag) && e->parentNode() && !e->parentNode()->isSVGElement()))
1979 style->setPosition(RenderStyle::initialPosition());
1980 }
1981 #endif
1982 }
1983
updateFont()1984 void CSSStyleSelector::updateFont()
1985 {
1986 checkForTextSizeAdjust();
1987 checkForGenericFamilyChange(style(), m_parentStyle);
1988 checkForZoomChange(style(), m_parentStyle);
1989 m_style->font().update(m_fontSelector);
1990 m_fontDirty = false;
1991 }
1992
cacheBorderAndBackground()1993 void CSSStyleSelector::cacheBorderAndBackground()
1994 {
1995 m_hasUAAppearance = m_style->hasAppearance();
1996 if (m_hasUAAppearance) {
1997 m_borderData = m_style->border();
1998 m_backgroundData = *m_style->backgroundLayers();
1999 m_backgroundColor = m_style->backgroundColor();
2000 }
2001 }
2002
styleRulesForElement(Element * e,bool authorOnly,bool includeEmptyRules,CSSRuleFilter filter)2003 PassRefPtr<CSSRuleList> CSSStyleSelector::styleRulesForElement(Element* e, bool authorOnly, bool includeEmptyRules, CSSRuleFilter filter)
2004 {
2005 return pseudoStyleRulesForElement(e, NOPSEUDO, authorOnly, includeEmptyRules, filter);
2006 }
2007
pseudoStyleRulesForElement(Element * e,PseudoId pseudoId,bool authorOnly,bool includeEmptyRules,CSSRuleFilter filter)2008 PassRefPtr<CSSRuleList> CSSStyleSelector::pseudoStyleRulesForElement(Element* e, PseudoId pseudoId, bool authorOnly, bool includeEmptyRules, CSSRuleFilter filter)
2009 {
2010 if (!e || !e->document()->haveStylesheetsLoaded())
2011 return 0;
2012
2013 m_checker.m_collectRulesOnly = true;
2014
2015 initElement(e);
2016 initForStyleResolve(e, 0, pseudoId);
2017
2018 if (!authorOnly) {
2019 int firstUARule = -1, lastUARule = -1;
2020 // First we match rules from the user agent sheet.
2021 matchUARules(firstUARule, lastUARule);
2022
2023 // Now we check user sheet rules.
2024 if (m_matchAuthorAndUserStyles) {
2025 int firstUserRule = -1, lastUserRule = -1;
2026 matchRules(m_userStyle.get(), firstUserRule, lastUserRule, includeEmptyRules);
2027 }
2028 }
2029
2030 if (m_matchAuthorAndUserStyles) {
2031 m_checker.m_sameOriginOnly = (filter == SameOriginCSSRulesOnly);
2032
2033 // Check the rules in author sheets.
2034 int firstAuthorRule = -1, lastAuthorRule = -1;
2035 matchRules(m_authorStyle.get(), firstAuthorRule, lastAuthorRule, includeEmptyRules);
2036
2037 m_checker.m_sameOriginOnly = false;
2038 }
2039
2040 m_checker.m_collectRulesOnly = false;
2041
2042 return m_ruleList.release();
2043 }
2044
checkSelector(const RuleData & ruleData)2045 inline bool CSSStyleSelector::checkSelector(const RuleData& ruleData)
2046 {
2047 m_dynamicPseudo = NOPSEUDO;
2048
2049 // Let the slow path handle SVG as it has some additional rules regarding shadow trees.
2050 if (ruleData.hasFastCheckableSelector() && !m_element->isSVGElement()) {
2051 // We know this selector does not include any pseudo selectors.
2052 if (m_checker.m_pseudoStyle != NOPSEUDO)
2053 return false;
2054 // We know a sufficiently simple single part selector matches simply because we found it from the rule hash.
2055 // This is limited to HTML only so we don't need to check the namespace.
2056 if (ruleData.hasTopSelectorMatchingHTMLBasedOnRuleHash() && !ruleData.hasMultipartSelector() && m_element->isHTMLElement())
2057 return true;
2058 return SelectorChecker::fastCheckSelector(ruleData.selector(), m_element);
2059 }
2060
2061 // Slow path.
2062 SelectorMatch match = m_checker.checkSelector(ruleData.selector(), m_element, &m_selectorAttrs, m_dynamicPseudo, false, false, style(), m_parentNode ? m_parentNode->renderStyle() : 0);
2063 if (match != SelectorMatches)
2064 return false;
2065 if (m_checker.m_pseudoStyle != NOPSEUDO && m_checker.m_pseudoStyle != m_dynamicPseudo)
2066 return false;
2067 return true;
2068 }
2069
selectorTagMatches(const Element * element,const CSSSelector * selector)2070 static inline bool selectorTagMatches(const Element* element, const CSSSelector* selector)
2071 {
2072 if (!selector->hasTag())
2073 return true;
2074 const AtomicString& localName = selector->tag().localName();
2075 if (localName != starAtom && localName != element->localName())
2076 return false;
2077 const AtomicString& namespaceURI = selector->tag().namespaceURI();
2078 return namespaceURI == starAtom || namespaceURI == element->namespaceURI();
2079 }
2080
isFastCheckableSelector(const CSSSelector * selector)2081 static inline bool isFastCheckableSelector(const CSSSelector* selector)
2082 {
2083 for (; selector; selector = selector->tagHistory()) {
2084 if (selector->relation() != CSSSelector::Descendant && selector->relation() != CSSSelector::Child && selector->relation() != CSSSelector::SubSelector)
2085 return false;
2086 if (selector->m_match != CSSSelector::None && selector->m_match != CSSSelector::Id && selector->m_match != CSSSelector::Class)
2087 return false;
2088 }
2089 return true;
2090 }
2091
2092 template <class ValueChecker>
fastCheckSingleSelector(const CSSSelector * & selector,const Element * & element,const CSSSelector * & topChildOrSubselector,const Element * & topChildOrSubselectorMatchElement)2093 inline bool fastCheckSingleSelector(const CSSSelector*& selector, const Element*& element, const CSSSelector*& topChildOrSubselector, const Element*& topChildOrSubselectorMatchElement)
2094 {
2095 AtomicStringImpl* value = selector->value().impl();
2096 for (; element; element = element->parentElement()) {
2097 if (ValueChecker::checkValue(element, value) && selectorTagMatches(element, selector)) {
2098 if (selector->relation() == CSSSelector::Descendant)
2099 topChildOrSubselector = 0;
2100 else if (!topChildOrSubselector) {
2101 ASSERT(selector->relation() == CSSSelector::Child || selector->relation() == CSSSelector::SubSelector);
2102 topChildOrSubselector = selector;
2103 topChildOrSubselectorMatchElement = element;
2104 }
2105 if (selector->relation() != CSSSelector::SubSelector)
2106 element = element->parentElement();
2107 selector = selector->tagHistory();
2108 return true;
2109 }
2110 if (topChildOrSubselector) {
2111 // Child or subselector check failed.
2112 // If the match element is null, topChildOrSubselector was also the very topmost selector and had to match
2113 // the original element we were checking.
2114 if (!topChildOrSubselectorMatchElement)
2115 return false;
2116 // There may be other matches down the ancestor chain.
2117 // Rewind to the topmost child or subselector and the element it matched, continue checking ancestors.
2118 selector = topChildOrSubselector;
2119 element = topChildOrSubselectorMatchElement->parentElement();
2120 topChildOrSubselector = 0;
2121 return true;
2122 }
2123 }
2124 return false;
2125 }
2126
2127 struct ClassCheck {
checkValueWebCore::ClassCheck2128 static bool checkValue(const Element* element, AtomicStringImpl* value)
2129 {
2130 return element->hasClass() && static_cast<const StyledElement*>(element)->classNames().contains(value);
2131 }
2132 };
2133 struct IdCheck {
checkValueWebCore::IdCheck2134 static bool checkValue(const Element* element, AtomicStringImpl* value)
2135 {
2136 return element->hasID() && element->idForStyleResolution().impl() == value;
2137 }
2138 };
2139 struct TagCheck {
checkValueWebCore::TagCheck2140 static bool checkValue(const Element*, AtomicStringImpl*)
2141 {
2142 return true;
2143 }
2144 };
2145
fastCheckSelector(const CSSSelector * selector,const Element * element)2146 bool CSSStyleSelector::SelectorChecker::fastCheckSelector(const CSSSelector* selector, const Element* element)
2147 {
2148 ASSERT(isFastCheckableSelector(selector));
2149
2150 // The top selector requires tag check only as rule hashes have already handled id and class matches.
2151 if (!selectorTagMatches(element, selector))
2152 return false;
2153
2154 const CSSSelector* topChildOrSubselector = 0;
2155 const Element* topChildOrSubselectorMatchElement = 0;
2156 if (selector->relation() == CSSSelector::Child || selector->relation() == CSSSelector::SubSelector)
2157 topChildOrSubselector = selector;
2158
2159 if (selector->relation() != CSSSelector::SubSelector)
2160 element = element->parentElement();
2161
2162 selector = selector->tagHistory();
2163
2164 // We know this compound selector has descendant, child and subselector combinators only and all components are simple.
2165 while (selector) {
2166 switch (selector->m_match) {
2167 case CSSSelector::Class:
2168 if (!fastCheckSingleSelector<ClassCheck>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
2169 return false;
2170 break;
2171 case CSSSelector::Id:
2172 if (!fastCheckSingleSelector<IdCheck>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
2173 return false;
2174 break;
2175 case CSSSelector::None:
2176 if (!fastCheckSingleSelector<TagCheck>(selector, element, topChildOrSubselector, topChildOrSubselectorMatchElement))
2177 return false;
2178 break;
2179 default:
2180 ASSERT_NOT_REACHED();
2181 }
2182 }
2183 return true;
2184 }
2185
2186 // Recursive check of selectors and combinators
2187 // It can return 3 different values:
2188 // * SelectorMatches - the selector matches the element e
2189 // * SelectorFailsLocally - the selector fails for the element e
2190 // * SelectorFailsCompletely - the selector fails for e and any sibling or ancestor of e
checkSelector(CSSSelector * sel,Element * e,HashSet<AtomicStringImpl * > * selectorAttrs,PseudoId & dynamicPseudo,bool isSubSelector,bool encounteredLink,RenderStyle * elementStyle,RenderStyle * elementParentStyle) const2191 CSSStyleSelector::SelectorMatch CSSStyleSelector::SelectorChecker::checkSelector(CSSSelector* sel, Element* e, HashSet<AtomicStringImpl*>* selectorAttrs, PseudoId& dynamicPseudo, bool isSubSelector, bool encounteredLink, RenderStyle* elementStyle, RenderStyle* elementParentStyle) const
2192 {
2193 #if ENABLE(SVG)
2194 // Spec: CSS2 selectors cannot be applied to the (conceptually) cloned DOM tree
2195 // because its contents are not part of the formal document structure.
2196 if (e->isSVGElement() && e->isShadowRoot())
2197 return SelectorFailsCompletely;
2198 #endif
2199
2200 // first selector has to match
2201 if (!checkOneSelector(sel, e, selectorAttrs, dynamicPseudo, isSubSelector, encounteredLink, elementStyle, elementParentStyle))
2202 return SelectorFailsLocally;
2203
2204 // The rest of the selectors has to match
2205 CSSSelector::Relation relation = sel->relation();
2206
2207 // Prepare next sel
2208 sel = sel->tagHistory();
2209 if (!sel)
2210 return SelectorMatches;
2211
2212 if (relation != CSSSelector::SubSelector)
2213 // Bail-out if this selector is irrelevant for the pseudoStyle
2214 if (m_pseudoStyle != NOPSEUDO && m_pseudoStyle != dynamicPseudo)
2215 return SelectorFailsCompletely;
2216
2217 // Check for nested links.
2218 if (m_matchVisitedPseudoClass && !isSubSelector) {
2219 RenderStyle* currentStyle = elementStyle ? elementStyle : e->renderStyle();
2220 if (currentStyle && currentStyle->insideLink() && e->isLink()) {
2221 if (encounteredLink)
2222 m_matchVisitedPseudoClass = false; // This link is not relevant to the style being resolved, so disable matching.
2223 else
2224 encounteredLink = true;
2225 }
2226 }
2227
2228 switch (relation) {
2229 case CSSSelector::Descendant:
2230 while (true) {
2231 ContainerNode* n = e->parentNode();
2232 if (!n || !n->isElementNode())
2233 return SelectorFailsCompletely;
2234 e = static_cast<Element*>(n);
2235 SelectorMatch match = checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, encounteredLink);
2236 if (match != SelectorFailsLocally)
2237 return match;
2238 }
2239 break;
2240 case CSSSelector::Child:
2241 {
2242 ContainerNode* n = e->parentNode();
2243 if (!n || !n->isElementNode())
2244 return SelectorFailsCompletely;
2245 e = static_cast<Element*>(n);
2246 return checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, encounteredLink);
2247 }
2248 case CSSSelector::DirectAdjacent:
2249 {
2250 if (!m_collectRulesOnly && e->parentNode() && e->parentNode()->isElementNode()) {
2251 RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle();
2252 if (parentStyle)
2253 parentStyle->setChildrenAffectedByDirectAdjacentRules();
2254 }
2255 Node* n = e->previousSibling();
2256 while (n && !n->isElementNode())
2257 n = n->previousSibling();
2258 if (!n)
2259 return SelectorFailsLocally;
2260 e = static_cast<Element*>(n);
2261 m_matchVisitedPseudoClass = false;
2262 return checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, encounteredLink);
2263 }
2264 case CSSSelector::IndirectAdjacent:
2265 if (!m_collectRulesOnly && e->parentNode() && e->parentNode()->isElementNode()) {
2266 RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle();
2267 if (parentStyle)
2268 parentStyle->setChildrenAffectedByForwardPositionalRules();
2269 }
2270 while (true) {
2271 Node* n = e->previousSibling();
2272 while (n && !n->isElementNode())
2273 n = n->previousSibling();
2274 if (!n)
2275 return SelectorFailsLocally;
2276 e = static_cast<Element*>(n);
2277 m_matchVisitedPseudoClass = false;
2278 SelectorMatch match = checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, encounteredLink);
2279 if (match != SelectorFailsLocally)
2280 return match;
2281 };
2282 break;
2283 case CSSSelector::SubSelector:
2284 // a selector is invalid if something follows a pseudo-element
2285 // We make an exception for scrollbar pseudo elements and allow a set of pseudo classes (but nothing else)
2286 // to follow the pseudo elements.
2287 if ((elementStyle || m_collectRulesOnly) && dynamicPseudo != NOPSEUDO && dynamicPseudo != SELECTION &&
2288 !((RenderScrollbar::scrollbarForStyleResolve() || dynamicPseudo == SCROLLBAR_CORNER || dynamicPseudo == RESIZER) && sel->m_match == CSSSelector::PseudoClass))
2289 return SelectorFailsCompletely;
2290 return checkSelector(sel, e, selectorAttrs, dynamicPseudo, true, encounteredLink, elementStyle, elementParentStyle);
2291 case CSSSelector::ShadowDescendant:
2292 {
2293 Node* shadowHostNode = e->shadowAncestorNode();
2294 if (shadowHostNode == e || !shadowHostNode->isElementNode())
2295 return SelectorFailsCompletely;
2296 e = static_cast<Element*>(shadowHostNode);
2297 return checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, encounteredLink);
2298 }
2299 }
2300
2301 return SelectorFailsCompletely;
2302 }
2303
addLocalNameToSet(HashSet<AtomicStringImpl * > * set,const QualifiedName & qName)2304 static void addLocalNameToSet(HashSet<AtomicStringImpl*>* set, const QualifiedName& qName)
2305 {
2306 set->add(qName.localName().impl());
2307 }
2308
createHtmlCaseInsensitiveAttributesSet()2309 static HashSet<AtomicStringImpl*>* createHtmlCaseInsensitiveAttributesSet()
2310 {
2311 // This is the list of attributes in HTML 4.01 with values marked as "[CI]" or case-insensitive
2312 // Mozilla treats all other values as case-sensitive, thus so do we.
2313 HashSet<AtomicStringImpl*>* attrSet = new HashSet<AtomicStringImpl*>;
2314
2315 addLocalNameToSet(attrSet, accept_charsetAttr);
2316 addLocalNameToSet(attrSet, acceptAttr);
2317 addLocalNameToSet(attrSet, alignAttr);
2318 addLocalNameToSet(attrSet, alinkAttr);
2319 addLocalNameToSet(attrSet, axisAttr);
2320 addLocalNameToSet(attrSet, bgcolorAttr);
2321 addLocalNameToSet(attrSet, charsetAttr);
2322 addLocalNameToSet(attrSet, checkedAttr);
2323 addLocalNameToSet(attrSet, clearAttr);
2324 addLocalNameToSet(attrSet, codetypeAttr);
2325 addLocalNameToSet(attrSet, colorAttr);
2326 addLocalNameToSet(attrSet, compactAttr);
2327 addLocalNameToSet(attrSet, declareAttr);
2328 addLocalNameToSet(attrSet, deferAttr);
2329 addLocalNameToSet(attrSet, dirAttr);
2330 addLocalNameToSet(attrSet, disabledAttr);
2331 addLocalNameToSet(attrSet, enctypeAttr);
2332 addLocalNameToSet(attrSet, faceAttr);
2333 addLocalNameToSet(attrSet, frameAttr);
2334 addLocalNameToSet(attrSet, hreflangAttr);
2335 addLocalNameToSet(attrSet, http_equivAttr);
2336 addLocalNameToSet(attrSet, langAttr);
2337 addLocalNameToSet(attrSet, languageAttr);
2338 addLocalNameToSet(attrSet, linkAttr);
2339 addLocalNameToSet(attrSet, mediaAttr);
2340 addLocalNameToSet(attrSet, methodAttr);
2341 addLocalNameToSet(attrSet, multipleAttr);
2342 addLocalNameToSet(attrSet, nohrefAttr);
2343 addLocalNameToSet(attrSet, noresizeAttr);
2344 addLocalNameToSet(attrSet, noshadeAttr);
2345 addLocalNameToSet(attrSet, nowrapAttr);
2346 addLocalNameToSet(attrSet, readonlyAttr);
2347 addLocalNameToSet(attrSet, relAttr);
2348 addLocalNameToSet(attrSet, revAttr);
2349 addLocalNameToSet(attrSet, rulesAttr);
2350 addLocalNameToSet(attrSet, scopeAttr);
2351 addLocalNameToSet(attrSet, scrollingAttr);
2352 addLocalNameToSet(attrSet, selectedAttr);
2353 addLocalNameToSet(attrSet, shapeAttr);
2354 addLocalNameToSet(attrSet, targetAttr);
2355 addLocalNameToSet(attrSet, textAttr);
2356 addLocalNameToSet(attrSet, typeAttr);
2357 addLocalNameToSet(attrSet, valignAttr);
2358 addLocalNameToSet(attrSet, valuetypeAttr);
2359 addLocalNameToSet(attrSet, vlinkAttr);
2360
2361 return attrSet;
2362 }
2363
htmlAttributeHasCaseInsensitiveValue(const QualifiedName & attr)2364 static bool htmlAttributeHasCaseInsensitiveValue(const QualifiedName& attr)
2365 {
2366 static HashSet<AtomicStringImpl*>* htmlCaseInsensitiveAttributesSet = createHtmlCaseInsensitiveAttributesSet();
2367 bool isPossibleHTMLAttr = !attr.hasPrefix() && (attr.namespaceURI() == nullAtom);
2368 return isPossibleHTMLAttr && htmlCaseInsensitiveAttributesSet->contains(attr.localName().impl());
2369 }
2370
checkOneSelector(CSSSelector * sel,Element * e,HashSet<AtomicStringImpl * > * selectorAttrs,PseudoId & dynamicPseudo,bool isSubSelector,bool encounteredLink,RenderStyle * elementStyle,RenderStyle * elementParentStyle) const2371 bool CSSStyleSelector::SelectorChecker::checkOneSelector(CSSSelector* sel, Element* e, HashSet<AtomicStringImpl*>* selectorAttrs, PseudoId& dynamicPseudo, bool isSubSelector, bool encounteredLink, RenderStyle* elementStyle, RenderStyle* elementParentStyle) const
2372 {
2373 ASSERT(e);
2374 if (!e)
2375 return false;
2376
2377 if (!selectorTagMatches(e, sel))
2378 return false;
2379
2380 if (sel->hasAttribute()) {
2381 if (sel->m_match == CSSSelector::Class)
2382 return e->hasClass() && static_cast<StyledElement*>(e)->classNames().contains(sel->value());
2383
2384 if (sel->m_match == CSSSelector::Id)
2385 return e->hasID() && e->idForStyleResolution() == sel->value();
2386
2387 const QualifiedName& attr = sel->attribute();
2388
2389 // FIXME: Handle the case were elementStyle is 0.
2390 if (elementStyle && (!e->isStyledElement() || (!static_cast<StyledElement*>(e)->isMappedAttribute(attr) && attr != typeAttr && attr != readonlyAttr))) {
2391 elementStyle->setAffectedByAttributeSelectors(); // Special-case the "type" and "readonly" attributes so input form controls can share style.
2392 if (selectorAttrs)
2393 selectorAttrs->add(attr.localName().impl());
2394 }
2395
2396 const AtomicString& value = e->getAttribute(attr);
2397 if (value.isNull())
2398 return false; // attribute is not set
2399
2400 bool caseSensitive = !m_documentIsHTML || !htmlAttributeHasCaseInsensitiveValue(attr);
2401
2402 switch (sel->m_match) {
2403 case CSSSelector::Exact:
2404 if (caseSensitive ? sel->value() != value : !equalIgnoringCase(sel->value(), value))
2405 return false;
2406 break;
2407 case CSSSelector::List:
2408 {
2409 // Ignore empty selectors or selectors containing spaces
2410 if (sel->value().contains(' ') || sel->value().isEmpty())
2411 return false;
2412
2413 unsigned startSearchAt = 0;
2414 while (true) {
2415 size_t foundPos = value.find(sel->value(), startSearchAt, caseSensitive);
2416 if (foundPos == notFound)
2417 return false;
2418 if (foundPos == 0 || value[foundPos - 1] == ' ') {
2419 unsigned endStr = foundPos + sel->value().length();
2420 if (endStr == value.length() || value[endStr] == ' ')
2421 break; // We found a match.
2422 }
2423
2424 // No match. Keep looking.
2425 startSearchAt = foundPos + 1;
2426 }
2427 break;
2428 }
2429 case CSSSelector::Contain:
2430 if (!value.contains(sel->value(), caseSensitive) || sel->value().isEmpty())
2431 return false;
2432 break;
2433 case CSSSelector::Begin:
2434 if (!value.startsWith(sel->value(), caseSensitive) || sel->value().isEmpty())
2435 return false;
2436 break;
2437 case CSSSelector::End:
2438 if (!value.endsWith(sel->value(), caseSensitive) || sel->value().isEmpty())
2439 return false;
2440 break;
2441 case CSSSelector::Hyphen:
2442 if (value.length() < sel->value().length())
2443 return false;
2444 if (!value.startsWith(sel->value(), caseSensitive))
2445 return false;
2446 // It they start the same, check for exact match or following '-':
2447 if (value.length() != sel->value().length() && value[sel->value().length()] != '-')
2448 return false;
2449 break;
2450 case CSSSelector::PseudoClass:
2451 case CSSSelector::PseudoElement:
2452 default:
2453 break;
2454 }
2455 }
2456
2457 if (sel->m_match == CSSSelector::PseudoClass) {
2458 // Handle :not up front.
2459 if (sel->pseudoType() == CSSSelector::PseudoNot) {
2460 ASSERT(sel->selectorList());
2461 for (CSSSelector* subSel = sel->selectorList()->first(); subSel; subSel = subSel->tagHistory()) {
2462 // :not cannot nest. I don't really know why this is a
2463 // restriction in CSS3, but it is, so let's honor it.
2464 // the parser enforces that this never occurs
2465 ASSERT(subSel->pseudoType() != CSSSelector::PseudoNot);
2466
2467 if (!checkOneSelector(subSel, e, selectorAttrs, dynamicPseudo, true, encounteredLink, elementStyle, elementParentStyle))
2468 return true;
2469 }
2470 } else if (dynamicPseudo != NOPSEUDO && (RenderScrollbar::scrollbarForStyleResolve() || dynamicPseudo == SCROLLBAR_CORNER || dynamicPseudo == RESIZER)) {
2471 // CSS scrollbars match a specific subset of pseudo classes, and they have specialized rules for each
2472 // (since there are no elements involved).
2473 return checkScrollbarPseudoClass(sel, dynamicPseudo);
2474 } else if (dynamicPseudo == SELECTION) {
2475 if (sel->pseudoType() == CSSSelector::PseudoWindowInactive)
2476 return !m_document->page()->focusController()->isActive();
2477 }
2478
2479 // Normal element pseudo class checking.
2480 switch (sel->pseudoType()) {
2481 // Pseudo classes:
2482 case CSSSelector::PseudoNot:
2483 break; // Already handled up above.
2484 case CSSSelector::PseudoEmpty: {
2485 bool result = true;
2486 for (Node* n = e->firstChild(); n; n = n->nextSibling()) {
2487 if (n->isElementNode()) {
2488 result = false;
2489 break;
2490 } else if (n->isTextNode()) {
2491 Text* textNode = static_cast<Text*>(n);
2492 if (!textNode->data().isEmpty()) {
2493 result = false;
2494 break;
2495 }
2496 }
2497 }
2498 if (!m_collectRulesOnly) {
2499 if (elementStyle)
2500 elementStyle->setEmptyState(result);
2501 else if (e->renderStyle() && (e->document()->usesSiblingRules() || e->renderStyle()->unique()))
2502 e->renderStyle()->setEmptyState(result);
2503 }
2504 return result;
2505 }
2506 case CSSSelector::PseudoFirstChild: {
2507 // first-child matches the first child that is an element
2508 if (e->parentNode() && e->parentNode()->isElementNode()) {
2509 bool result = false;
2510 Node* n = e->previousSibling();
2511 while (n && !n->isElementNode())
2512 n = n->previousSibling();
2513 if (!n)
2514 result = true;
2515 if (!m_collectRulesOnly) {
2516 RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle();
2517 RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle();
2518 if (parentStyle)
2519 parentStyle->setChildrenAffectedByFirstChildRules();
2520 if (result && childStyle)
2521 childStyle->setFirstChildState();
2522 }
2523 return result;
2524 }
2525 break;
2526 }
2527 case CSSSelector::PseudoFirstOfType: {
2528 // first-of-type matches the first element of its type
2529 if (e->parentNode() && e->parentNode()->isElementNode()) {
2530 bool result = false;
2531 const QualifiedName& type = e->tagQName();
2532 Node* n = e->previousSibling();
2533 while (n) {
2534 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
2535 break;
2536 n = n->previousSibling();
2537 }
2538 if (!n)
2539 result = true;
2540 if (!m_collectRulesOnly) {
2541 RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle();
2542 if (parentStyle)
2543 parentStyle->setChildrenAffectedByForwardPositionalRules();
2544 }
2545 return result;
2546 }
2547 break;
2548 }
2549 case CSSSelector::PseudoLastChild: {
2550 // last-child matches the last child that is an element
2551 if (Element* parentElement = e->parentElement()) {
2552 bool result = false;
2553 if (parentElement->isFinishedParsingChildren()) {
2554 Node* n = e->nextSibling();
2555 while (n && !n->isElementNode())
2556 n = n->nextSibling();
2557 if (!n)
2558 result = true;
2559 }
2560 if (!m_collectRulesOnly) {
2561 RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle();
2562 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
2563 if (parentStyle)
2564 parentStyle->setChildrenAffectedByLastChildRules();
2565 if (result && childStyle)
2566 childStyle->setLastChildState();
2567 }
2568 return result;
2569 }
2570 break;
2571 }
2572 case CSSSelector::PseudoLastOfType: {
2573 // last-of-type matches the last element of its type
2574 if (Element* parentElement = e->parentElement()) {
2575 if (!m_collectRulesOnly) {
2576 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
2577 if (parentStyle)
2578 parentStyle->setChildrenAffectedByBackwardPositionalRules();
2579 }
2580 if (!parentElement->isFinishedParsingChildren())
2581 return false;
2582 bool result = false;
2583 const QualifiedName& type = e->tagQName();
2584 Node* n = e->nextSibling();
2585 while (n) {
2586 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
2587 break;
2588 n = n->nextSibling();
2589 }
2590 if (!n)
2591 result = true;
2592 return result;
2593 }
2594 break;
2595 }
2596 case CSSSelector::PseudoOnlyChild: {
2597 if (Element* parentElement = e->parentElement()) {
2598 bool firstChild = false;
2599 bool lastChild = false;
2600
2601 Node* n = e->previousSibling();
2602 while (n && !n->isElementNode())
2603 n = n->previousSibling();
2604 if (!n)
2605 firstChild = true;
2606 if (firstChild && parentElement->isFinishedParsingChildren()) {
2607 n = e->nextSibling();
2608 while (n && !n->isElementNode())
2609 n = n->nextSibling();
2610 if (!n)
2611 lastChild = true;
2612 }
2613 if (!m_collectRulesOnly) {
2614 RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle();
2615 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
2616 if (parentStyle) {
2617 parentStyle->setChildrenAffectedByFirstChildRules();
2618 parentStyle->setChildrenAffectedByLastChildRules();
2619 }
2620 if (firstChild && childStyle)
2621 childStyle->setFirstChildState();
2622 if (lastChild && childStyle)
2623 childStyle->setLastChildState();
2624 }
2625 return firstChild && lastChild;
2626 }
2627 break;
2628 }
2629 case CSSSelector::PseudoOnlyOfType: {
2630 // FIXME: This selector is very slow.
2631 if (Element* parentElement = e->parentElement()) {
2632 if (!m_collectRulesOnly) {
2633 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
2634 if (parentStyle) {
2635 parentStyle->setChildrenAffectedByForwardPositionalRules();
2636 parentStyle->setChildrenAffectedByBackwardPositionalRules();
2637 }
2638 }
2639 if (!parentElement->isFinishedParsingChildren())
2640 return false;
2641 bool firstChild = false;
2642 bool lastChild = false;
2643 const QualifiedName& type = e->tagQName();
2644 Node* n = e->previousSibling();
2645 while (n) {
2646 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
2647 break;
2648 n = n->previousSibling();
2649 }
2650 if (!n)
2651 firstChild = true;
2652 if (firstChild) {
2653 n = e->nextSibling();
2654 while (n) {
2655 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
2656 break;
2657 n = n->nextSibling();
2658 }
2659 if (!n)
2660 lastChild = true;
2661 }
2662 return firstChild && lastChild;
2663 }
2664 break;
2665 }
2666 case CSSSelector::PseudoNthChild: {
2667 if (!sel->parseNth())
2668 break;
2669 if (Element* parentElement = e->parentElement()) {
2670 int count = 1;
2671 Node* n = e->previousSibling();
2672 while (n) {
2673 if (n->isElementNode()) {
2674 RenderStyle* s = n->renderStyle();
2675 unsigned index = s ? s->childIndex() : 0;
2676 if (index) {
2677 count += index;
2678 break;
2679 }
2680 count++;
2681 }
2682 n = n->previousSibling();
2683 }
2684
2685 if (!m_collectRulesOnly) {
2686 RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle();
2687 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
2688 if (childStyle)
2689 childStyle->setChildIndex(count);
2690 if (parentStyle)
2691 parentStyle->setChildrenAffectedByForwardPositionalRules();
2692 }
2693
2694 if (sel->matchNth(count))
2695 return true;
2696 }
2697 break;
2698 }
2699 case CSSSelector::PseudoNthOfType: {
2700 if (!sel->parseNth())
2701 break;
2702 if (Element* parentElement = e->parentElement()) {
2703 int count = 1;
2704 const QualifiedName& type = e->tagQName();
2705 Node* n = e->previousSibling();
2706 while (n) {
2707 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
2708 count++;
2709 n = n->previousSibling();
2710 }
2711
2712 if (!m_collectRulesOnly) {
2713 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
2714 if (parentStyle)
2715 parentStyle->setChildrenAffectedByForwardPositionalRules();
2716 }
2717
2718 if (sel->matchNth(count))
2719 return true;
2720 }
2721 break;
2722 }
2723 case CSSSelector::PseudoNthLastChild: {
2724 if (!sel->parseNth())
2725 break;
2726 if (Element* parentElement = e->parentElement()) {
2727 if (!m_collectRulesOnly) {
2728 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
2729 if (parentStyle)
2730 parentStyle->setChildrenAffectedByBackwardPositionalRules();
2731 }
2732 if (!parentElement->isFinishedParsingChildren())
2733 return false;
2734 int count = 1;
2735 Node* n = e->nextSibling();
2736 while (n) {
2737 if (n->isElementNode())
2738 count++;
2739 n = n->nextSibling();
2740 }
2741 if (sel->matchNth(count))
2742 return true;
2743 }
2744 break;
2745 }
2746 case CSSSelector::PseudoNthLastOfType: {
2747 if (!sel->parseNth())
2748 break;
2749 if (Element* parentElement = e->parentElement()) {
2750 if (!m_collectRulesOnly) {
2751 RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentElement->renderStyle();
2752 if (parentStyle)
2753 parentStyle->setChildrenAffectedByBackwardPositionalRules();
2754 }
2755 if (!parentElement->isFinishedParsingChildren())
2756 return false;
2757 int count = 1;
2758 const QualifiedName& type = e->tagQName();
2759 Node* n = e->nextSibling();
2760 while (n) {
2761 if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type))
2762 count++;
2763 n = n->nextSibling();
2764 }
2765 if (sel->matchNth(count))
2766 return true;
2767 }
2768 break;
2769 }
2770 case CSSSelector::PseudoTarget:
2771 if (e == e->document()->cssTarget())
2772 return true;
2773 break;
2774 case CSSSelector::PseudoAny:
2775 for (CSSSelector* selector = sel->selectorList()->first(); selector; selector = CSSSelectorList::next(selector)) {
2776 if (checkSelector(selector, e, selectorAttrs, dynamicPseudo, true, encounteredLink, elementStyle, elementParentStyle) == SelectorMatches)
2777 return true;
2778 }
2779 break;
2780 case CSSSelector::PseudoAnyLink:
2781 if (e && e->isLink())
2782 return true;
2783 break;
2784 case CSSSelector::PseudoAutofill: {
2785 if (!e || !e->isFormControlElement())
2786 break;
2787 if (InputElement* inputElement = e->toInputElement())
2788 return inputElement->isAutofilled();
2789 break;
2790 }
2791 case CSSSelector::PseudoLink:
2792 if (e && e->isLink())
2793 return !m_matchVisitedPseudoClass;
2794 break;
2795 case CSSSelector::PseudoVisited:
2796 if (e && e->isLink())
2797 return m_matchVisitedPseudoClass;
2798 break;
2799 case CSSSelector::PseudoDrag: {
2800 if (elementStyle)
2801 elementStyle->setAffectedByDragRules(true);
2802 else if (e->renderStyle())
2803 e->renderStyle()->setAffectedByDragRules(true);
2804 if (e->renderer() && e->renderer()->isDragging())
2805 return true;
2806 break;
2807 }
2808 case CSSSelector::PseudoFocus:
2809 if (e && e->focused() && e->document()->frame() && e->document()->frame()->selection()->isFocusedAndActive())
2810 return true;
2811 break;
2812 case CSSSelector::PseudoHover: {
2813 // If we're in quirks mode, then hover should never match anchors with no
2814 // href and *:hover should not match anything. This is important for sites like wsj.com.
2815 if (m_strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {
2816 if (elementStyle)
2817 elementStyle->setAffectedByHoverRules(true);
2818 else if (e->renderStyle())
2819 e->renderStyle()->setAffectedByHoverRules(true);
2820 if (e->hovered())
2821 return true;
2822 }
2823 break;
2824 }
2825 case CSSSelector::PseudoActive:
2826 // If we're in quirks mode, then :active should never match anchors with no
2827 // href and *:active should not match anything.
2828 if (m_strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {
2829 if (elementStyle)
2830 elementStyle->setAffectedByActiveRules(true);
2831 else if (e->renderStyle())
2832 e->renderStyle()->setAffectedByActiveRules(true);
2833 if (e->active())
2834 return true;
2835 }
2836 break;
2837 case CSSSelector::PseudoEnabled:
2838 if (e && e->isFormControlElement())
2839 return e->isEnabledFormControl();
2840 break;
2841 case CSSSelector::PseudoFullPageMedia:
2842 return e && e->document() && e->document()->isMediaDocument();
2843 break;
2844 case CSSSelector::PseudoDefault:
2845 return e && e->isDefaultButtonForForm();
2846 case CSSSelector::PseudoDisabled:
2847 if (e && e->isFormControlElement())
2848 return !e->isEnabledFormControl();
2849 break;
2850 case CSSSelector::PseudoReadOnly: {
2851 if (!e || !e->isFormControlElement())
2852 return false;
2853 return e->isTextFormControl() && e->isReadOnlyFormControl();
2854 }
2855 case CSSSelector::PseudoReadWrite: {
2856 if (!e || !e->isFormControlElement())
2857 return false;
2858 return e->isTextFormControl() && !e->isReadOnlyFormControl();
2859 }
2860 case CSSSelector::PseudoOptional:
2861 return e && e->isOptionalFormControl();
2862 case CSSSelector::PseudoRequired:
2863 return e && e->isRequiredFormControl();
2864 case CSSSelector::PseudoValid: {
2865 if (!e)
2866 return false;
2867 e->document()->setContainsValidityStyleRules();
2868 return e->willValidate() && e->isValidFormControlElement();
2869 } case CSSSelector::PseudoInvalid: {
2870 if (!e)
2871 return false;
2872 e->document()->setContainsValidityStyleRules();
2873 return (e->willValidate() && !e->isValidFormControlElement()) || e->hasUnacceptableValue();
2874 } case CSSSelector::PseudoChecked: {
2875 if (!e || !e->isFormControlElement())
2876 break;
2877 // Even though WinIE allows checked and indeterminate to co-exist, the CSS selector spec says that
2878 // you can't be both checked and indeterminate. We will behave like WinIE behind the scenes and just
2879 // obey the CSS spec here in the test for matching the pseudo.
2880 InputElement* inputElement = e->toInputElement();
2881 if (inputElement && inputElement->isChecked() && !inputElement->isIndeterminate())
2882 return true;
2883 break;
2884 }
2885 case CSSSelector::PseudoIndeterminate: {
2886 if (!e || !e->isFormControlElement())
2887 break;
2888 InputElement* inputElement = e->toInputElement();
2889 if (inputElement && inputElement->isIndeterminate())
2890 return true;
2891 break;
2892 }
2893 case CSSSelector::PseudoRoot:
2894 if (e == e->document()->documentElement())
2895 return true;
2896 break;
2897 case CSSSelector::PseudoLang: {
2898 AtomicString value = e->computeInheritedLanguage();
2899 const AtomicString& argument = sel->argument();
2900 if (value.isEmpty() || !value.startsWith(argument, false))
2901 break;
2902 if (value.length() != argument.length() && value[argument.length()] != '-')
2903 break;
2904 return true;
2905 }
2906 #if ENABLE(FULLSCREEN_API)
2907 case CSSSelector::PseudoFullScreen:
2908 // While a Document is in the fullscreen state, and the document's current fullscreen
2909 // element is an element in the document, the 'full-screen' pseudoclass applies to
2910 // that element. Also, an <iframe>, <object> or <embed> element whose child browsing
2911 // context's Document is in the fullscreen state has the 'full-screen' pseudoclass applied.
2912 if (!e->document()->webkitIsFullScreen())
2913 return false;
2914 if (e != e->document()->webkitCurrentFullScreenElement())
2915 return false;
2916 return true;
2917 case CSSSelector::PseudoFullScreenDocument:
2918 // While a Document is in the fullscreen state, the 'full-screen-document' pseudoclass applies
2919 // to all elements of that Document.
2920 if (!e->document()->webkitIsFullScreen())
2921 return false;
2922 return true;
2923 #endif
2924 case CSSSelector::PseudoInRange:
2925 if (!e)
2926 return false;
2927 e->document()->setContainsValidityStyleRules();
2928 return e->isInRange();
2929 case CSSSelector::PseudoOutOfRange:
2930 if (!e)
2931 return false;
2932 e->document()->setContainsValidityStyleRules();
2933 return e->isOutOfRange();
2934 case CSSSelector::PseudoUnknown:
2935 case CSSSelector::PseudoNotParsed:
2936 default:
2937 ASSERT_NOT_REACHED();
2938 break;
2939 }
2940 return false;
2941 }
2942 if (sel->m_match == CSSSelector::PseudoElement) {
2943 if (!elementStyle && !m_collectRulesOnly)
2944 return false;
2945
2946 PseudoId pseudoId = CSSSelector::pseudoId(sel->pseudoType());
2947 if (pseudoId == FIRST_LETTER) {
2948 if (Document* document = e->document())
2949 document->setUsesFirstLetterRules(true);
2950 }
2951 if (pseudoId != NOPSEUDO)
2952 dynamicPseudo = pseudoId;
2953 }
2954 // ### add the rest of the checks...
2955 return true;
2956 }
2957
checkScrollbarPseudoClass(CSSSelector * sel,PseudoId &) const2958 bool CSSStyleSelector::SelectorChecker::checkScrollbarPseudoClass(CSSSelector* sel, PseudoId&) const
2959 {
2960 RenderScrollbar* scrollbar = RenderScrollbar::scrollbarForStyleResolve();
2961 ScrollbarPart part = RenderScrollbar::partForStyleResolve();
2962
2963 // FIXME: This is a temporary hack for resizers and scrollbar corners. Eventually :window-inactive should become a real
2964 // pseudo class and just apply to everything.
2965 if (sel->pseudoType() == CSSSelector::PseudoWindowInactive)
2966 return !m_document->page()->focusController()->isActive();
2967
2968 if (!scrollbar)
2969 return false;
2970
2971 ASSERT(sel->m_match == CSSSelector::PseudoClass);
2972 switch (sel->pseudoType()) {
2973 case CSSSelector::PseudoEnabled:
2974 return scrollbar->enabled();
2975 case CSSSelector::PseudoDisabled:
2976 return !scrollbar->enabled();
2977 case CSSSelector::PseudoHover: {
2978 ScrollbarPart hoveredPart = scrollbar->hoveredPart();
2979 if (part == ScrollbarBGPart)
2980 return hoveredPart != NoPart;
2981 if (part == TrackBGPart)
2982 return hoveredPart == BackTrackPart || hoveredPart == ForwardTrackPart || hoveredPart == ThumbPart;
2983 return part == hoveredPart;
2984 }
2985 case CSSSelector::PseudoActive: {
2986 ScrollbarPart pressedPart = scrollbar->pressedPart();
2987 if (part == ScrollbarBGPart)
2988 return pressedPart != NoPart;
2989 if (part == TrackBGPart)
2990 return pressedPart == BackTrackPart || pressedPart == ForwardTrackPart || pressedPart == ThumbPart;
2991 return part == pressedPart;
2992 }
2993 case CSSSelector::PseudoHorizontal:
2994 return scrollbar->orientation() == HorizontalScrollbar;
2995 case CSSSelector::PseudoVertical:
2996 return scrollbar->orientation() == VerticalScrollbar;
2997 case CSSSelector::PseudoDecrement:
2998 return part == BackButtonStartPart || part == BackButtonEndPart || part == BackTrackPart;
2999 case CSSSelector::PseudoIncrement:
3000 return part == ForwardButtonStartPart || part == ForwardButtonEndPart || part == ForwardTrackPart;
3001 case CSSSelector::PseudoStart:
3002 return part == BackButtonStartPart || part == ForwardButtonStartPart || part == BackTrackPart;
3003 case CSSSelector::PseudoEnd:
3004 return part == BackButtonEndPart || part == ForwardButtonEndPart || part == ForwardTrackPart;
3005 case CSSSelector::PseudoDoubleButton: {
3006 ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
3007 if (part == BackButtonStartPart || part == ForwardButtonStartPart || part == BackTrackPart)
3008 return buttonsPlacement == ScrollbarButtonsDoubleStart || buttonsPlacement == ScrollbarButtonsDoubleBoth;
3009 if (part == BackButtonEndPart || part == ForwardButtonEndPart || part == ForwardTrackPart)
3010 return buttonsPlacement == ScrollbarButtonsDoubleEnd || buttonsPlacement == ScrollbarButtonsDoubleBoth;
3011 return false;
3012 }
3013 case CSSSelector::PseudoSingleButton: {
3014 ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
3015 if (part == BackButtonStartPart || part == ForwardButtonEndPart || part == BackTrackPart || part == ForwardTrackPart)
3016 return buttonsPlacement == ScrollbarButtonsSingle;
3017 return false;
3018 }
3019 case CSSSelector::PseudoNoButton: {
3020 ScrollbarButtonsPlacement buttonsPlacement = scrollbar->theme()->buttonsPlacement();
3021 if (part == BackTrackPart)
3022 return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacement == ScrollbarButtonsDoubleEnd;
3023 if (part == ForwardTrackPart)
3024 return buttonsPlacement == ScrollbarButtonsNone || buttonsPlacement == ScrollbarButtonsDoubleStart;
3025 return false;
3026 }
3027 case CSSSelector::PseudoCornerPresent:
3028 return scrollbar->scrollableArea()->isScrollCornerVisible();
3029 default:
3030 return false;
3031 }
3032 }
3033
3034 // -----------------------------------------------------------------
3035
isSelectorMatchingHTMLBasedOnRuleHash(const CSSSelector * selector)3036 static inline bool isSelectorMatchingHTMLBasedOnRuleHash(const CSSSelector* selector)
3037 {
3038 const AtomicString& selectorNamespace = selector->tag().namespaceURI();
3039 if (selectorNamespace != starAtom && selectorNamespace != xhtmlNamespaceURI)
3040 return false;
3041 if (selector->m_match == CSSSelector::None)
3042 return true;
3043 if (selector->m_match != CSSSelector::Id && selector->m_match != CSSSelector::Class)
3044 return false;
3045 return selector->tag() == starAtom;
3046 }
3047
RuleData(CSSStyleRule * rule,CSSSelector * selector,unsigned position)3048 RuleData::RuleData(CSSStyleRule* rule, CSSSelector* selector, unsigned position)
3049 : m_rule(rule)
3050 , m_selector(selector)
3051 , m_specificity(selector->specificity())
3052 , m_position(position)
3053 , m_hasFastCheckableSelector(isFastCheckableSelector(selector))
3054 , m_hasMultipartSelector(selector->tagHistory())
3055 , m_hasTopSelectorMatchingHTMLBasedOnRuleHash(isSelectorMatchingHTMLBasedOnRuleHash(selector))
3056 {
3057 collectDescendantSelectorIdentifierHashes();
3058 }
3059
collectIdentifierHashes(const CSSSelector * selector,unsigned & identifierCount)3060 inline void RuleData::collectIdentifierHashes(const CSSSelector* selector, unsigned& identifierCount)
3061 {
3062 if ((selector->m_match == CSSSelector::Id || selector->m_match == CSSSelector::Class) && !selector->value().isEmpty())
3063 m_descendantSelectorIdentifierHashes[identifierCount++] = selector->value().impl()->existingHash();
3064 if (identifierCount == maximumIdentifierCount)
3065 return;
3066 const AtomicString& localName = selector->tag().localName();
3067 if (localName != starAtom)
3068 m_descendantSelectorIdentifierHashes[identifierCount++] = localName.impl()->existingHash();
3069 }
3070
collectDescendantSelectorIdentifierHashes()3071 inline void RuleData::collectDescendantSelectorIdentifierHashes()
3072 {
3073 unsigned identifierCount = 0;
3074 CSSSelector::Relation relation = m_selector->relation();
3075
3076 // Skip the topmost selector. It is handled quickly by the rule hashes.
3077 bool skipOverSubselectors = true;
3078 for (const CSSSelector* selector = m_selector->tagHistory(); selector; selector = selector->tagHistory()) {
3079 // Only collect identifiers that match ancestors.
3080 switch (relation) {
3081 case CSSSelector::SubSelector:
3082 if (!skipOverSubselectors)
3083 collectIdentifierHashes(selector, identifierCount);
3084 break;
3085 case CSSSelector::DirectAdjacent:
3086 case CSSSelector::IndirectAdjacent:
3087 case CSSSelector::ShadowDescendant:
3088 skipOverSubselectors = true;
3089 break;
3090 case CSSSelector::Descendant:
3091 case CSSSelector::Child:
3092 skipOverSubselectors = false;
3093 collectIdentifierHashes(selector, identifierCount);
3094 break;
3095 }
3096 if (identifierCount == maximumIdentifierCount)
3097 return;
3098 relation = selector->relation();
3099 }
3100 m_descendantSelectorIdentifierHashes[identifierCount] = 0;
3101 }
3102
RuleSet()3103 RuleSet::RuleSet()
3104 : m_ruleCount(0)
3105 , m_autoShrinkToFitEnabled(true)
3106 {
3107 }
3108
~RuleSet()3109 RuleSet::~RuleSet()
3110 {
3111 deleteAllValues(m_idRules);
3112 deleteAllValues(m_classRules);
3113 deleteAllValues(m_pseudoRules);
3114 deleteAllValues(m_tagRules);
3115 }
3116
3117
addToRuleSet(AtomicStringImpl * key,AtomRuleMap & map,CSSStyleRule * rule,CSSSelector * sel)3118 void RuleSet::addToRuleSet(AtomicStringImpl* key, AtomRuleMap& map,
3119 CSSStyleRule* rule, CSSSelector* sel)
3120 {
3121 if (!key) return;
3122 Vector<RuleData>* rules = map.get(key);
3123 if (!rules) {
3124 rules = new Vector<RuleData>;
3125 map.set(key, rules);
3126 }
3127 rules->append(RuleData(rule, sel, m_ruleCount++));
3128 }
3129
addRule(CSSStyleRule * rule,CSSSelector * sel)3130 void RuleSet::addRule(CSSStyleRule* rule, CSSSelector* sel)
3131 {
3132 if (sel->m_match == CSSSelector::Id) {
3133 addToRuleSet(sel->value().impl(), m_idRules, rule, sel);
3134 return;
3135 }
3136 if (sel->m_match == CSSSelector::Class) {
3137 addToRuleSet(sel->value().impl(), m_classRules, rule, sel);
3138 return;
3139 }
3140
3141 if (sel->isUnknownPseudoElement()) {
3142 addToRuleSet(sel->value().impl(), m_pseudoRules, rule, sel);
3143 return;
3144 }
3145
3146 const AtomicString& localName = sel->tag().localName();
3147 if (localName != starAtom) {
3148 addToRuleSet(localName.impl(), m_tagRules, rule, sel);
3149 return;
3150 }
3151
3152 m_universalRules.append(RuleData(rule, sel, m_ruleCount++));
3153 }
3154
addPageRule(CSSStyleRule * rule,CSSSelector * sel)3155 void RuleSet::addPageRule(CSSStyleRule* rule, CSSSelector* sel)
3156 {
3157 m_pageRules.append(RuleData(rule, sel, m_pageRules.size()));
3158 }
3159
addRulesFromSheet(CSSStyleSheet * sheet,const MediaQueryEvaluator & medium,CSSStyleSelector * styleSelector)3160 void RuleSet::addRulesFromSheet(CSSStyleSheet* sheet, const MediaQueryEvaluator& medium, CSSStyleSelector* styleSelector)
3161 {
3162 if (!sheet)
3163 return;
3164
3165 // No media implies "all", but if a media list exists it must
3166 // contain our current medium
3167 if (sheet->media() && !medium.eval(sheet->media(), styleSelector))
3168 return; // the style sheet doesn't apply
3169
3170 int len = sheet->length();
3171
3172 for (int i = 0; i < len; i++) {
3173 StyleBase* item = sheet->item(i);
3174 if (item->isStyleRule())
3175 addStyleRule(static_cast<CSSStyleRule*>(item));
3176 else if (item->isImportRule()) {
3177 CSSImportRule* import = static_cast<CSSImportRule*>(item);
3178 if (!import->media() || medium.eval(import->media(), styleSelector))
3179 addRulesFromSheet(import->styleSheet(), medium, styleSelector);
3180 }
3181 else if (item->isMediaRule()) {
3182 CSSMediaRule* r = static_cast<CSSMediaRule*>(item);
3183 CSSRuleList* rules = r->cssRules();
3184
3185 if ((!r->media() || medium.eval(r->media(), styleSelector)) && rules) {
3186 // Traverse child elements of the @media rule.
3187 for (unsigned j = 0; j < rules->length(); j++) {
3188 CSSRule *childItem = rules->item(j);
3189 if (childItem->isStyleRule()) {
3190 // It is a StyleRule, so append it to our list
3191 addStyleRule(static_cast<CSSStyleRule*>(childItem));
3192 } else if (childItem->isFontFaceRule() && styleSelector) {
3193 // Add this font face to our set.
3194 const CSSFontFaceRule* fontFaceRule = static_cast<CSSFontFaceRule*>(childItem);
3195 styleSelector->fontSelector()->addFontFaceRule(fontFaceRule);
3196 } else if (childItem->isKeyframesRule() && styleSelector) {
3197 // Add this keyframe rule to our set.
3198 styleSelector->addKeyframeStyle(static_cast<WebKitCSSKeyframesRule*>(childItem));
3199 }
3200 } // for rules
3201 } // if rules
3202 } else if (item->isFontFaceRule() && styleSelector) {
3203 // Add this font face to our set.
3204 const CSSFontFaceRule* fontFaceRule = static_cast<CSSFontFaceRule*>(item);
3205 styleSelector->fontSelector()->addFontFaceRule(fontFaceRule);
3206 } else if (item->isKeyframesRule())
3207 styleSelector->addKeyframeStyle(static_cast<WebKitCSSKeyframesRule*>(item));
3208 }
3209 if (m_autoShrinkToFitEnabled)
3210 shrinkToFit();
3211 }
3212
addStyleRule(CSSStyleRule * rule)3213 void RuleSet::addStyleRule(CSSStyleRule* rule)
3214 {
3215 if (rule->isPageRule()) {
3216 CSSPageRule* pageRule = static_cast<CSSPageRule*>(rule);
3217 addPageRule(pageRule, pageRule->selectorList().first());
3218 } else {
3219 for (CSSSelector* s = rule->selectorList().first(); s; s = CSSSelectorList::next(s))
3220 addRule(rule, s);
3221 }
3222 }
3223
collectFeaturesFromSelector(CSSStyleSelector::Features & features,const CSSSelector * selector)3224 static inline void collectFeaturesFromSelector(CSSStyleSelector::Features& features, const CSSSelector* selector)
3225 {
3226 if (selector->m_match == CSSSelector::Id && !selector->value().isEmpty())
3227 features.idsInRules.add(selector->value().impl());
3228 switch (selector->pseudoType()) {
3229 case CSSSelector::PseudoFirstLine:
3230 features.usesFirstLineRules = true;
3231 break;
3232 case CSSSelector::PseudoBefore:
3233 case CSSSelector::PseudoAfter:
3234 features.usesBeforeAfterRules = true;
3235 break;
3236 case CSSSelector::PseudoLink:
3237 case CSSSelector::PseudoVisited:
3238 features.usesLinkRules = true;
3239 break;
3240 default:
3241 break;
3242 }
3243 }
3244
collectFeaturesFromList(CSSStyleSelector::Features & features,const Vector<RuleData> & rules)3245 static void collectFeaturesFromList(CSSStyleSelector::Features& features, const Vector<RuleData>& rules)
3246 {
3247 unsigned size = rules.size();
3248 for (unsigned i = 0; i < size; ++i) {
3249 const RuleData& ruleData = rules[i];
3250 bool foundSiblingSelector = false;
3251 for (CSSSelector* selector = ruleData.selector(); selector; selector = selector->tagHistory()) {
3252 collectFeaturesFromSelector(features, selector);
3253
3254 if (CSSSelectorList* selectorList = selector->selectorList()) {
3255 for (CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) {
3256 if (selector->isSiblingSelector())
3257 foundSiblingSelector = true;
3258 collectFeaturesFromSelector(features, subSelector);
3259 }
3260 } else if (selector->isSiblingSelector())
3261 foundSiblingSelector = true;
3262 }
3263 if (foundSiblingSelector) {
3264 if (!features.siblingRules)
3265 features.siblingRules = adoptPtr(new RuleSet);
3266 features.siblingRules->addRule(ruleData.rule(), ruleData.selector());
3267 }
3268 }
3269 }
3270
collectFeatures(CSSStyleSelector::Features & features) const3271 void RuleSet::collectFeatures(CSSStyleSelector::Features& features) const
3272 {
3273 AtomRuleMap::const_iterator end = m_idRules.end();
3274 for (AtomRuleMap::const_iterator it = m_idRules.begin(); it != end; ++it)
3275 collectFeaturesFromList(features, *it->second);
3276 end = m_classRules.end();
3277 for (AtomRuleMap::const_iterator it = m_classRules.begin(); it != end; ++it)
3278 collectFeaturesFromList(features, *it->second);
3279 end = m_tagRules.end();
3280 for (AtomRuleMap::const_iterator it = m_tagRules.begin(); it != end; ++it)
3281 collectFeaturesFromList(features, *it->second);
3282 end = m_pseudoRules.end();
3283 for (AtomRuleMap::const_iterator it = m_pseudoRules.begin(); it != end; ++it)
3284 collectFeaturesFromList(features, *it->second);
3285 collectFeaturesFromList(features, m_universalRules);
3286 }
3287
shrinkMapVectorsToFit(RuleSet::AtomRuleMap & map)3288 static inline void shrinkMapVectorsToFit(RuleSet::AtomRuleMap& map)
3289 {
3290 RuleSet::AtomRuleMap::iterator end = map.end();
3291 for (RuleSet::AtomRuleMap::iterator it = map.begin(); it != end; ++it)
3292 it->second->shrinkToFit();
3293 }
3294
shrinkToFit()3295 void RuleSet::shrinkToFit()
3296 {
3297 shrinkMapVectorsToFit(m_idRules);
3298 shrinkMapVectorsToFit(m_classRules);
3299 shrinkMapVectorsToFit(m_tagRules);
3300 shrinkMapVectorsToFit(m_pseudoRules);
3301 m_universalRules.shrinkToFit();
3302 m_pageRules.shrinkToFit();
3303 }
3304
3305 // -------------------------------------------------------------------------------------
3306 // this is mostly boring stuff on how to apply a certain rule to the renderstyle...
3307
convertToLength(CSSPrimitiveValue * primitiveValue,RenderStyle * style,RenderStyle * rootStyle,bool toFloat,double multiplier=1,bool * ok=0)3308 static Length convertToLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, bool toFloat, double multiplier = 1, bool *ok = 0)
3309 {
3310 // This function is tolerant of a null style value. The only place style is used is in
3311 // length measurements, like 'ems' and 'px'. And in those cases style is only used
3312 // when the units are EMS or EXS. So we will just fail in those cases.
3313 Length l;
3314 if (!primitiveValue) {
3315 if (ok)
3316 *ok = false;
3317 } else {
3318 int type = primitiveValue->primitiveType();
3319
3320 if (!style && (type == CSSPrimitiveValue::CSS_EMS || type == CSSPrimitiveValue::CSS_EXS || type == CSSPrimitiveValue::CSS_REMS)) {
3321 if (ok)
3322 *ok = false;
3323 } else if (CSSPrimitiveValue::isUnitTypeLength(type)) {
3324 if (toFloat)
3325 l = Length(primitiveValue->computeLengthDouble(style, rootStyle, multiplier), Fixed);
3326 else
3327 l = Length(primitiveValue->computeLengthIntForLength(style, rootStyle, multiplier), Fixed);
3328 }
3329 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
3330 l = Length(primitiveValue->getDoubleValue(), Percent);
3331 else if (type == CSSPrimitiveValue::CSS_NUMBER)
3332 l = Length(primitiveValue->getDoubleValue() * 100.0, Percent);
3333 else if (ok)
3334 *ok = false;
3335 }
3336 return l;
3337 }
3338
convertToIntLength(CSSPrimitiveValue * primitiveValue,RenderStyle * style,RenderStyle * rootStyle,double multiplier=1,bool * ok=0)3339 static Length convertToIntLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, double multiplier = 1, bool *ok = 0)
3340 {
3341 return convertToLength(primitiveValue, style, rootStyle, false, multiplier, ok);
3342 }
3343
convertToFloatLength(CSSPrimitiveValue * primitiveValue,RenderStyle * style,RenderStyle * rootStyle,double multiplier=1,bool * ok=0)3344 static Length convertToFloatLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, double multiplier = 1, bool *ok = 0)
3345 {
3346 return convertToLength(primitiveValue, style, rootStyle, true, multiplier, ok);
3347 }
3348
3349 template <bool applyFirst>
applyDeclarations(bool isImportant,int startIndex,int endIndex)3350 void CSSStyleSelector::applyDeclarations(bool isImportant, int startIndex, int endIndex)
3351 {
3352 if (startIndex == -1)
3353 return;
3354
3355 for (int i = startIndex; i <= endIndex; i++) {
3356 CSSMutableStyleDeclaration* decl = m_matchedDecls[i];
3357 CSSMutableStyleDeclaration::const_iterator end = decl->end();
3358 for (CSSMutableStyleDeclaration::const_iterator it = decl->begin(); it != end; ++it) {
3359 const CSSProperty& current = *it;
3360 if (isImportant == current.isImportant()) {
3361 int property = current.id();
3362
3363 if (applyFirst) {
3364 COMPILE_ASSERT(firstCSSProperty == CSSPropertyColor, CSS_color_is_first_property);
3365 COMPILE_ASSERT(CSSPropertyZoom == CSSPropertyColor + 14, CSS_zoom_is_end_of_first_prop_range);
3366 COMPILE_ASSERT(CSSPropertyLineHeight == CSSPropertyZoom + 1, CSS_line_height_is_after_zoom);
3367
3368 // give special priority to font-xxx, color properties, etc
3369 if (property <= CSSPropertyLineHeight) {
3370 // we apply line-height later
3371 if (property == CSSPropertyLineHeight)
3372 m_lineHeightValue = current.value();
3373 else
3374 applyProperty(current.id(), current.value());
3375 }
3376 } else {
3377 if (property > CSSPropertyLineHeight)
3378 applyProperty(current.id(), current.value());
3379 }
3380 }
3381 }
3382 }
3383 }
3384
matchPageRules(RuleSet * rules,bool isLeftPage,bool isFirstPage,const String & pageName)3385 void CSSStyleSelector::matchPageRules(RuleSet* rules, bool isLeftPage, bool isFirstPage, const String& pageName)
3386 {
3387 m_matchedRules.clear();
3388
3389 if (!rules)
3390 return;
3391
3392 matchPageRulesForList(rules->getPageRules(), isLeftPage, isFirstPage, pageName);
3393
3394 // If we didn't match any rules, we're done.
3395 if (m_matchedRules.isEmpty())
3396 return;
3397
3398 // Sort the set of matched rules.
3399 sortMatchedRules();
3400
3401 // Now transfer the set of matched rules over to our list of decls.
3402 for (unsigned i = 0; i < m_matchedRules.size(); i++)
3403 addMatchedDeclaration(m_matchedRules[i]->rule()->declaration());
3404 }
3405
matchPageRulesForList(const Vector<RuleData> * rules,bool isLeftPage,bool isFirstPage,const String & pageName)3406 void CSSStyleSelector::matchPageRulesForList(const Vector<RuleData>* rules, bool isLeftPage, bool isFirstPage, const String& pageName)
3407 {
3408 if (!rules)
3409 return;
3410
3411 unsigned size = rules->size();
3412 for (unsigned i = 0; i < size; ++i) {
3413 const RuleData& ruleData = rules->at(i);
3414 CSSStyleRule* rule = ruleData.rule();
3415 const AtomicString& selectorLocalName = ruleData.selector()->tag().localName();
3416 if (selectorLocalName != starAtom && selectorLocalName != pageName)
3417 continue;
3418 CSSSelector::PseudoType pseudoType = ruleData.selector()->pseudoType();
3419 if ((pseudoType == CSSSelector::PseudoLeftPage && !isLeftPage)
3420 || (pseudoType == CSSSelector::PseudoRightPage && isLeftPage)
3421 || (pseudoType == CSSSelector::PseudoFirstPage && !isFirstPage))
3422 continue;
3423
3424 // If the rule has no properties to apply, then ignore it.
3425 CSSMutableStyleDeclaration* decl = rule->declaration();
3426 if (!decl || !decl->length())
3427 continue;
3428
3429 // Add this rule to our list of matched rules.
3430 addMatchedRule(&ruleData);
3431 }
3432 }
3433
isLeftPage(int pageIndex) const3434 bool CSSStyleSelector::isLeftPage(int pageIndex) const
3435 {
3436 bool isFirstPageLeft = false;
3437 if (!m_rootElementStyle->isLeftToRightDirection())
3438 isFirstPageLeft = true;
3439
3440 return (pageIndex + (isFirstPageLeft ? 1 : 0)) % 2;
3441 }
3442
isFirstPage(int pageIndex) const3443 bool CSSStyleSelector::isFirstPage(int pageIndex) const
3444 {
3445 // FIXME: In case of forced left/right page, page at index 1 (not 0) can be the first page.
3446 return (!pageIndex);
3447 }
3448
pageName(int) const3449 String CSSStyleSelector::pageName(int /* pageIndex */) const
3450 {
3451 // FIXME: Implement page index to page name mapping.
3452 return "";
3453 }
3454
applyCounterList(RenderStyle * style,CSSValueList * list,bool isReset)3455 static void applyCounterList(RenderStyle* style, CSSValueList* list, bool isReset)
3456 {
3457 CounterDirectiveMap& map = style->accessCounterDirectives();
3458 typedef CounterDirectiveMap::iterator Iterator;
3459
3460 Iterator end = map.end();
3461 for (Iterator it = map.begin(); it != end; ++it)
3462 if (isReset)
3463 it->second.m_reset = false;
3464 else
3465 it->second.m_increment = false;
3466
3467 int length = list ? list->length() : 0;
3468 for (int i = 0; i < length; ++i) {
3469 CSSValue* currValue = list->itemWithoutBoundsCheck(i);
3470 if (!currValue->isPrimitiveValue())
3471 continue;
3472
3473 Pair* pair = static_cast<CSSPrimitiveValue*>(currValue)->getPairValue();
3474 if (!pair || !pair->first() || !pair->second())
3475 continue;
3476
3477 AtomicString identifier = static_cast<CSSPrimitiveValue*>(pair->first())->getStringValue();
3478 // FIXME: What about overflow?
3479 int value = static_cast<CSSPrimitiveValue*>(pair->second())->getIntValue();
3480 CounterDirectives& directives = map.add(identifier.impl(), CounterDirectives()).first->second;
3481 if (isReset) {
3482 directives.m_reset = true;
3483 directives.m_resetValue = value;
3484 } else {
3485 if (directives.m_increment)
3486 directives.m_incrementValue += value;
3487 else {
3488 directives.m_increment = true;
3489 directives.m_incrementValue = value;
3490 }
3491 }
3492 }
3493 }
3494
applyPropertyToStyle(int id,CSSValue * value,RenderStyle * style)3495 void CSSStyleSelector::applyPropertyToStyle(int id, CSSValue *value, RenderStyle* style)
3496 {
3497 initElement(0);
3498 initForStyleResolve(0, style);
3499 m_style = style;
3500 if (value)
3501 applyProperty(id, value);
3502 }
3503
isValidVisitedLinkProperty(int id)3504 inline bool isValidVisitedLinkProperty(int id)
3505 {
3506 switch(static_cast<CSSPropertyID>(id)) {
3507 case CSSPropertyBackgroundColor:
3508 case CSSPropertyBorderLeftColor:
3509 case CSSPropertyBorderRightColor:
3510 case CSSPropertyBorderTopColor:
3511 case CSSPropertyBorderBottomColor:
3512 case CSSPropertyColor:
3513 case CSSPropertyOutlineColor:
3514 case CSSPropertyWebkitColumnRuleColor:
3515 case CSSPropertyWebkitTextEmphasisColor:
3516 case CSSPropertyWebkitTextFillColor:
3517 case CSSPropertyWebkitTextStrokeColor:
3518 // Also allow shorthands so that inherit/initial still work.
3519 case CSSPropertyBackground:
3520 case CSSPropertyBorderLeft:
3521 case CSSPropertyBorderRight:
3522 case CSSPropertyBorderTop:
3523 case CSSPropertyBorderBottom:
3524 case CSSPropertyOutline:
3525 case CSSPropertyWebkitColumnRule:
3526 #if ENABLE(SVG)
3527 case CSSPropertyFill:
3528 case CSSPropertyStroke:
3529 #endif
3530 return true;
3531 default:
3532 break;
3533 }
3534
3535 return false;
3536 }
3537
3538 // SVG handles zooming in a different way compared to CSS. The whole document is scaled instead
3539 // of each individual length value in the render style / tree. CSSPrimitiveValue::computeLength*()
3540 // multiplies each resolved length with the zoom multiplier - so for SVG we need to disable that.
3541 // Though all CSS values that can be applied to outermost <svg> elements (width/height/border/padding...)
3542 // need to respect the scaling. RenderBox (the parent class of RenderSVGRoot) grabs values like
3543 // width/height/border/padding/... from the RenderStyle -> for SVG these values would never scale,
3544 // if we'd pass a 1.0 zoom factor everyhwere. So we only pass a zoom factor of 1.0 for specific
3545 // properties that are NOT allowed to scale within a zoomed SVG document (letter/word-spacing/font-size).
useSVGZoomRules(const Element * e)3546 static inline bool useSVGZoomRules(const Element* e)
3547 {
3548 return e && e->isSVGElement();
3549 }
3550
applyProperty(int id,CSSValue * value)3551 void CSSStyleSelector::applyProperty(int id, CSSValue *value)
3552 {
3553 CSSPrimitiveValue* primitiveValue = 0;
3554 if (value->isPrimitiveValue())
3555 primitiveValue = static_cast<CSSPrimitiveValue*>(value);
3556
3557 float zoomFactor = m_style->effectiveZoom();
3558
3559 Length l;
3560 bool apply = false;
3561
3562 unsigned short valueType = value->cssValueType();
3563
3564 bool isInherit = m_parentNode && valueType == CSSValue::CSS_INHERIT;
3565 bool isInitial = valueType == CSSValue::CSS_INITIAL || (!m_parentNode && valueType == CSSValue::CSS_INHERIT);
3566
3567 id = CSSProperty::resolveDirectionAwareProperty(id, m_style->direction(), m_style->writingMode());
3568
3569 if (m_checker.m_matchVisitedPseudoClass && !isValidVisitedLinkProperty(id)) {
3570 // Limit the properties that can be applied to only the ones honored by :visited.
3571 return;
3572 }
3573
3574 CSSPropertyID property = static_cast<CSSPropertyID>(id);
3575
3576 // check lookup table for implementations and use when available
3577 if (m_applyProperty.implements(property)) {
3578 if (isInherit)
3579 m_applyProperty.applyInheritValue(property, this);
3580 else if (isInitial)
3581 m_applyProperty.applyInitialValue(property, this);
3582 else
3583 m_applyProperty.applyValue(property, this, value);
3584 return;
3585 }
3586
3587 // What follows is a list that maps the CSS properties into their corresponding front-end
3588 // RenderStyle values. Shorthands (e.g. border, background) occur in this list as well and
3589 // are only hit when mapping "inherit" or "initial" into front-end values.
3590 switch (property) {
3591 // ident only properties
3592 case CSSPropertyBorderCollapse:
3593 HANDLE_INHERIT_AND_INITIAL(borderCollapse, BorderCollapse)
3594 if (!primitiveValue)
3595 return;
3596 switch (primitiveValue->getIdent()) {
3597 case CSSValueCollapse:
3598 m_style->setBorderCollapse(true);
3599 break;
3600 case CSSValueSeparate:
3601 m_style->setBorderCollapse(false);
3602 break;
3603 default:
3604 return;
3605 }
3606 return;
3607 case CSSPropertyOutlineStyle:
3608 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(outlineStyle, OutlineStyle, BorderStyle)
3609 if (primitiveValue) {
3610 if (primitiveValue->getIdent() == CSSValueAuto)
3611 m_style->setOutlineStyle(DOTTED, true);
3612 else
3613 m_style->setOutlineStyle(*primitiveValue);
3614 }
3615 return;
3616 case CSSPropertyCaptionSide:
3617 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(captionSide, CaptionSide)
3618 return;
3619 case CSSPropertyClear:
3620 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(clear, Clear)
3621 return;
3622 case CSSPropertyDisplay:
3623 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(display, Display)
3624 #if ENABLE(WCSS)
3625 if (primitiveValue) {
3626 if (primitiveValue->getIdent() == CSSValueWapMarquee) {
3627 // Initialize WAP Marquee style
3628 m_style->setOverflowX(OMARQUEE);
3629 m_style->setOverflowY(OMARQUEE);
3630 m_style->setWhiteSpace(NOWRAP);
3631 m_style->setMarqueeDirection(MLEFT);
3632 m_style->setMarqueeSpeed(85); // Normal speed
3633 m_style->setMarqueeLoopCount(1);
3634 m_style->setMarqueeBehavior(MSCROLL);
3635
3636 if (m_parentStyle)
3637 m_style->setDisplay(m_parentStyle->display());
3638 else
3639 m_style->setDisplay(*primitiveValue);
3640 } else
3641 m_style->setDisplay(*primitiveValue);
3642 }
3643 #endif
3644 return;
3645 case CSSPropertyEmptyCells:
3646 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(emptyCells, EmptyCells)
3647 return;
3648 case CSSPropertyFloat:
3649 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(floating, Floating)
3650 return;
3651 case CSSPropertyFontStyle:
3652 {
3653 FontDescription fontDescription = m_style->fontDescription();
3654 if (isInherit)
3655 fontDescription.setItalic(m_parentStyle->fontDescription().italic());
3656 else if (isInitial)
3657 fontDescription.setItalic(false);
3658 else {
3659 if (!primitiveValue)
3660 return;
3661 switch (primitiveValue->getIdent()) {
3662 case CSSValueOblique:
3663 // FIXME: oblique is the same as italic for the moment...
3664 case CSSValueItalic:
3665 fontDescription.setItalic(true);
3666 break;
3667 case CSSValueNormal:
3668 fontDescription.setItalic(false);
3669 break;
3670 default:
3671 return;
3672 }
3673 }
3674 if (m_style->setFontDescription(fontDescription))
3675 m_fontDirty = true;
3676 return;
3677 }
3678
3679 case CSSPropertyFontVariant:
3680 {
3681 FontDescription fontDescription = m_style->fontDescription();
3682 if (isInherit)
3683 fontDescription.setSmallCaps(m_parentStyle->fontDescription().smallCaps());
3684 else if (isInitial)
3685 fontDescription.setSmallCaps(false);
3686 else {
3687 if (!primitiveValue)
3688 return;
3689 int id = primitiveValue->getIdent();
3690 if (id == CSSValueNormal)
3691 fontDescription.setSmallCaps(false);
3692 else if (id == CSSValueSmallCaps)
3693 fontDescription.setSmallCaps(true);
3694 else
3695 return;
3696 }
3697 if (m_style->setFontDescription(fontDescription))
3698 m_fontDirty = true;
3699 return;
3700 }
3701
3702 case CSSPropertyFontWeight:
3703 {
3704 FontDescription fontDescription = m_style->fontDescription();
3705 if (isInherit)
3706 fontDescription.setWeight(m_parentStyle->fontDescription().weight());
3707 else if (isInitial)
3708 fontDescription.setWeight(FontWeightNormal);
3709 else {
3710 if (!primitiveValue)
3711 return;
3712 if (primitiveValue->getIdent()) {
3713 switch (primitiveValue->getIdent()) {
3714 case CSSValueBolder:
3715 fontDescription.setWeight(fontDescription.bolderWeight());
3716 break;
3717 case CSSValueLighter:
3718 fontDescription.setWeight(fontDescription.lighterWeight());
3719 break;
3720 case CSSValueBold:
3721 case CSSValue700:
3722 fontDescription.setWeight(FontWeightBold);
3723 break;
3724 case CSSValueNormal:
3725 case CSSValue400:
3726 fontDescription.setWeight(FontWeightNormal);
3727 break;
3728 case CSSValue900:
3729 fontDescription.setWeight(FontWeight900);
3730 break;
3731 case CSSValue800:
3732 fontDescription.setWeight(FontWeight800);
3733 break;
3734 case CSSValue600:
3735 fontDescription.setWeight(FontWeight600);
3736 break;
3737 case CSSValue500:
3738 fontDescription.setWeight(FontWeight500);
3739 break;
3740 case CSSValue300:
3741 fontDescription.setWeight(FontWeight300);
3742 break;
3743 case CSSValue200:
3744 fontDescription.setWeight(FontWeight200);
3745 break;
3746 case CSSValue100:
3747 fontDescription.setWeight(FontWeight100);
3748 break;
3749 default:
3750 return;
3751 }
3752 } else
3753 ASSERT_NOT_REACHED();
3754 }
3755 if (m_style->setFontDescription(fontDescription))
3756 m_fontDirty = true;
3757 return;
3758 }
3759
3760 case CSSPropertyListStylePosition:
3761 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(listStylePosition, ListStylePosition)
3762 return;
3763 case CSSPropertyListStyleType:
3764 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(listStyleType, ListStyleType)
3765 return;
3766 case CSSPropertyPageBreakBefore:
3767 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(pageBreakBefore, PageBreakBefore, PageBreak)
3768 return;
3769 case CSSPropertyPageBreakAfter:
3770 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(pageBreakAfter, PageBreakAfter, PageBreak)
3771 return;
3772 case CSSPropertyPageBreakInside: {
3773 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(pageBreakInside, PageBreakInside, PageBreak)
3774 if (!primitiveValue)
3775 return;
3776 EPageBreak pageBreak = *primitiveValue;
3777 if (pageBreak != PBALWAYS)
3778 m_style->setPageBreakInside(pageBreak);
3779 return;
3780 }
3781
3782 case CSSPropertyPosition:
3783 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(position, Position)
3784 return;
3785 case CSSPropertyTableLayout: {
3786 HANDLE_INHERIT_AND_INITIAL(tableLayout, TableLayout)
3787
3788 ETableLayout l = *primitiveValue;
3789 if (l == TAUTO)
3790 l = RenderStyle::initialTableLayout();
3791
3792 m_style->setTableLayout(l);
3793 return;
3794 }
3795
3796 case CSSPropertyUnicodeBidi:
3797 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(unicodeBidi, UnicodeBidi)
3798 return;
3799 case CSSPropertyTextTransform:
3800 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(textTransform, TextTransform)
3801 return;
3802 case CSSPropertyVisibility:
3803 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(visibility, Visibility)
3804 return;
3805 case CSSPropertyWhiteSpace:
3806 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(whiteSpace, WhiteSpace)
3807 return;
3808 case CSSPropertyBorderSpacing: {
3809 if (isInherit) {
3810 m_style->setHorizontalBorderSpacing(m_parentStyle->horizontalBorderSpacing());
3811 m_style->setVerticalBorderSpacing(m_parentStyle->verticalBorderSpacing());
3812 }
3813 else if (isInitial) {
3814 m_style->setHorizontalBorderSpacing(0);
3815 m_style->setVerticalBorderSpacing(0);
3816 }
3817 return;
3818 }
3819 case CSSPropertyWebkitBorderHorizontalSpacing: {
3820 HANDLE_INHERIT_AND_INITIAL(horizontalBorderSpacing, HorizontalBorderSpacing)
3821 if (!primitiveValue)
3822 return;
3823 short spacing = primitiveValue->computeLengthShort(style(), m_rootElementStyle, zoomFactor);
3824 m_style->setHorizontalBorderSpacing(spacing);
3825 return;
3826 }
3827 case CSSPropertyWebkitBorderVerticalSpacing: {
3828 HANDLE_INHERIT_AND_INITIAL(verticalBorderSpacing, VerticalBorderSpacing)
3829 if (!primitiveValue)
3830 return;
3831 short spacing = primitiveValue->computeLengthShort(style(), m_rootElementStyle, zoomFactor);
3832 m_style->setVerticalBorderSpacing(spacing);
3833 return;
3834 }
3835 case CSSPropertyCursor:
3836 if (isInherit) {
3837 m_style->setCursor(m_parentStyle->cursor());
3838 m_style->setCursorList(m_parentStyle->cursors());
3839 return;
3840 }
3841 m_style->clearCursorList();
3842 if (isInitial) {
3843 m_style->setCursor(RenderStyle::initialCursor());
3844 return;
3845 }
3846 if (value->isValueList()) {
3847 CSSValueList* list = static_cast<CSSValueList*>(value);
3848 int len = list->length();
3849 m_style->setCursor(CURSOR_AUTO);
3850 for (int i = 0; i < len; i++) {
3851 CSSValue* item = list->itemWithoutBoundsCheck(i);
3852 if (!item->isPrimitiveValue())
3853 continue;
3854 primitiveValue = static_cast<CSSPrimitiveValue*>(item);
3855 int type = primitiveValue->primitiveType();
3856 if (type == CSSPrimitiveValue::CSS_URI) {
3857 if (primitiveValue->isCursorImageValue()) {
3858 CSSCursorImageValue* image = static_cast<CSSCursorImageValue*>(primitiveValue);
3859 if (image->updateIfSVGCursorIsUsed(m_element)) // Elements with SVG cursors are not allowed to share style.
3860 m_style->setUnique();
3861 m_style->addCursor(cachedOrPendingFromValue(CSSPropertyCursor, image), image->hotSpot());
3862 }
3863 } else if (type == CSSPrimitiveValue::CSS_IDENT)
3864 m_style->setCursor(*primitiveValue);
3865 }
3866 } else if (primitiveValue) {
3867 int type = primitiveValue->primitiveType();
3868 if (type == CSSPrimitiveValue::CSS_IDENT && m_style->cursor() != ECursor(*primitiveValue))
3869 m_style->setCursor(*primitiveValue);
3870 }
3871 return;
3872
3873 // uri || inherit
3874 case CSSPropertyListStyleImage:
3875 {
3876 HANDLE_INHERIT_AND_INITIAL(listStyleImage, ListStyleImage)
3877 m_style->setListStyleImage(styleImage(CSSPropertyListStyleImage, value));
3878 return;
3879 }
3880
3881 // length
3882 case CSSPropertyBorderTopWidth:
3883 case CSSPropertyBorderRightWidth:
3884 case CSSPropertyBorderBottomWidth:
3885 case CSSPropertyBorderLeftWidth:
3886 case CSSPropertyOutlineWidth:
3887 case CSSPropertyWebkitColumnRuleWidth:
3888 {
3889 if (isInherit) {
3890 HANDLE_INHERIT_COND(CSSPropertyBorderTopWidth, borderTopWidth, BorderTopWidth)
3891 HANDLE_INHERIT_COND(CSSPropertyBorderRightWidth, borderRightWidth, BorderRightWidth)
3892 HANDLE_INHERIT_COND(CSSPropertyBorderBottomWidth, borderBottomWidth, BorderBottomWidth)
3893 HANDLE_INHERIT_COND(CSSPropertyBorderLeftWidth, borderLeftWidth, BorderLeftWidth)
3894 HANDLE_INHERIT_COND(CSSPropertyOutlineWidth, outlineWidth, OutlineWidth)
3895 HANDLE_INHERIT_COND(CSSPropertyWebkitColumnRuleWidth, columnRuleWidth, ColumnRuleWidth)
3896 return;
3897 }
3898 else if (isInitial) {
3899 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderTopWidth, BorderTopWidth, BorderWidth)
3900 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderRightWidth, BorderRightWidth, BorderWidth)
3901 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderBottomWidth, BorderBottomWidth, BorderWidth)
3902 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderLeftWidth, BorderLeftWidth, BorderWidth)
3903 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyOutlineWidth, OutlineWidth, BorderWidth)
3904 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyWebkitColumnRuleWidth, ColumnRuleWidth, BorderWidth)
3905 return;
3906 }
3907
3908 if (!primitiveValue)
3909 return;
3910 short width = 3;
3911 switch (primitiveValue->getIdent()) {
3912 case CSSValueThin:
3913 width = 1;
3914 break;
3915 case CSSValueMedium:
3916 width = 3;
3917 break;
3918 case CSSValueThick:
3919 width = 5;
3920 break;
3921 case CSSValueInvalid:
3922 width = primitiveValue->computeLengthShort(style(), m_rootElementStyle, zoomFactor);
3923 break;
3924 default:
3925 return;
3926 }
3927
3928 if (width < 0) return;
3929 switch (id) {
3930 case CSSPropertyBorderTopWidth:
3931 m_style->setBorderTopWidth(width);
3932 break;
3933 case CSSPropertyBorderRightWidth:
3934 m_style->setBorderRightWidth(width);
3935 break;
3936 case CSSPropertyBorderBottomWidth:
3937 m_style->setBorderBottomWidth(width);
3938 break;
3939 case CSSPropertyBorderLeftWidth:
3940 m_style->setBorderLeftWidth(width);
3941 break;
3942 case CSSPropertyOutlineWidth:
3943 m_style->setOutlineWidth(width);
3944 break;
3945 case CSSPropertyWebkitColumnRuleWidth:
3946 m_style->setColumnRuleWidth(width);
3947 break;
3948 default:
3949 return;
3950 }
3951 return;
3952 }
3953
3954 case CSSPropertyWebkitFontSmoothing: {
3955 FontDescription fontDescription = m_style->fontDescription();
3956 if (isInherit)
3957 fontDescription.setFontSmoothing(m_parentStyle->fontDescription().fontSmoothing());
3958 else if (isInitial)
3959 fontDescription.setFontSmoothing(AutoSmoothing);
3960 else {
3961 if (!primitiveValue)
3962 return;
3963 int id = primitiveValue->getIdent();
3964 FontSmoothingMode smoothing;
3965 switch (id) {
3966 case CSSValueAuto:
3967 smoothing = AutoSmoothing;
3968 break;
3969 case CSSValueNone:
3970 smoothing = NoSmoothing;
3971 break;
3972 case CSSValueAntialiased:
3973 smoothing = Antialiased;
3974 break;
3975 case CSSValueSubpixelAntialiased:
3976 smoothing = SubpixelAntialiased;
3977 break;
3978 default:
3979 ASSERT_NOT_REACHED();
3980 smoothing = AutoSmoothing;
3981 }
3982 fontDescription.setFontSmoothing(smoothing);
3983 }
3984 if (m_style->setFontDescription(fontDescription))
3985 m_fontDirty = true;
3986 return;
3987 }
3988
3989 case CSSPropertyLetterSpacing:
3990 case CSSPropertyWordSpacing:
3991 {
3992 if (isInherit) {
3993 HANDLE_INHERIT_COND(CSSPropertyLetterSpacing, letterSpacing, LetterSpacing)
3994 HANDLE_INHERIT_COND(CSSPropertyWordSpacing, wordSpacing, WordSpacing)
3995 return;
3996 }
3997 else if (isInitial) {
3998 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyLetterSpacing, LetterSpacing, LetterWordSpacing)
3999 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyWordSpacing, WordSpacing, LetterWordSpacing)
4000 return;
4001 }
4002
4003 int width = 0;
4004 if (primitiveValue && primitiveValue->getIdent() == CSSValueNormal) {
4005 width = 0;
4006 } else {
4007 if (!primitiveValue)
4008 return;
4009 width = primitiveValue->computeLengthInt(style(), m_rootElementStyle, useSVGZoomRules(m_element) ? 1.0f : zoomFactor);
4010 }
4011 switch (id) {
4012 case CSSPropertyLetterSpacing:
4013 m_style->setLetterSpacing(width);
4014 break;
4015 case CSSPropertyWordSpacing:
4016 m_style->setWordSpacing(width);
4017 break;
4018 // ### needs the definitions in renderstyle
4019 default: break;
4020 }
4021 return;
4022 }
4023
4024 case CSSPropertyWordBreak:
4025 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(wordBreak, WordBreak)
4026 return;
4027 case CSSPropertyWordWrap:
4028 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(wordWrap, WordWrap)
4029 return;
4030 case CSSPropertyWebkitNbspMode:
4031 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(nbspMode, NBSPMode)
4032 return;
4033 case CSSPropertyWebkitLineBreak:
4034 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(khtmlLineBreak, KHTMLLineBreak)
4035 return;
4036 case CSSPropertyWebkitMatchNearestMailBlockquoteColor:
4037 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(matchNearestMailBlockquoteColor, MatchNearestMailBlockquoteColor)
4038 return;
4039
4040 case CSSPropertyResize:
4041 {
4042 HANDLE_INHERIT_AND_INITIAL(resize, Resize)
4043
4044 if (!primitiveValue->getIdent())
4045 return;
4046
4047 EResize r = RESIZE_NONE;
4048 if (primitiveValue->getIdent() == CSSValueAuto) {
4049 if (Settings* settings = m_checker.m_document->settings())
4050 r = settings->textAreasAreResizable() ? RESIZE_BOTH : RESIZE_NONE;
4051 } else
4052 r = *primitiveValue;
4053
4054 m_style->setResize(r);
4055 return;
4056 }
4057
4058 // length, percent
4059 case CSSPropertyMaxWidth:
4060 // +none +inherit
4061 if (primitiveValue && primitiveValue->getIdent() == CSSValueNone) {
4062 l = Length(undefinedLength, Fixed);
4063 apply = true;
4064 }
4065 case CSSPropertyTop:
4066 case CSSPropertyLeft:
4067 case CSSPropertyRight:
4068 case CSSPropertyBottom:
4069 case CSSPropertyWidth:
4070 case CSSPropertyMinWidth:
4071 case CSSPropertyMarginTop:
4072 case CSSPropertyMarginRight:
4073 case CSSPropertyMarginBottom:
4074 case CSSPropertyMarginLeft:
4075 // +inherit +auto
4076 if (id == CSSPropertyWidth || id == CSSPropertyMinWidth || id == CSSPropertyMaxWidth) {
4077 if (primitiveValue && primitiveValue->getIdent() == CSSValueIntrinsic) {
4078 l = Length(Intrinsic);
4079 apply = true;
4080 }
4081 else if (primitiveValue && primitiveValue->getIdent() == CSSValueMinIntrinsic) {
4082 l = Length(MinIntrinsic);
4083 apply = true;
4084 }
4085 }
4086 if (id != CSSPropertyMaxWidth && primitiveValue && primitiveValue->getIdent() == CSSValueAuto)
4087 apply = true;
4088 case CSSPropertyPaddingTop:
4089 case CSSPropertyPaddingRight:
4090 case CSSPropertyPaddingBottom:
4091 case CSSPropertyPaddingLeft:
4092 case CSSPropertyTextIndent:
4093 // +inherit
4094 {
4095 if (isInherit) {
4096 HANDLE_INHERIT_COND(CSSPropertyMaxWidth, maxWidth, MaxWidth)
4097 HANDLE_INHERIT_COND(CSSPropertyBottom, bottom, Bottom)
4098 HANDLE_INHERIT_COND(CSSPropertyTop, top, Top)
4099 HANDLE_INHERIT_COND(CSSPropertyLeft, left, Left)
4100 HANDLE_INHERIT_COND(CSSPropertyRight, right, Right)
4101 HANDLE_INHERIT_COND(CSSPropertyWidth, width, Width)
4102 HANDLE_INHERIT_COND(CSSPropertyMinWidth, minWidth, MinWidth)
4103 HANDLE_INHERIT_COND(CSSPropertyPaddingTop, paddingTop, PaddingTop)
4104 HANDLE_INHERIT_COND(CSSPropertyPaddingRight, paddingRight, PaddingRight)
4105 HANDLE_INHERIT_COND(CSSPropertyPaddingBottom, paddingBottom, PaddingBottom)
4106 HANDLE_INHERIT_COND(CSSPropertyPaddingLeft, paddingLeft, PaddingLeft)
4107 HANDLE_INHERIT_COND(CSSPropertyMarginTop, marginTop, MarginTop)
4108 HANDLE_INHERIT_COND(CSSPropertyMarginRight, marginRight, MarginRight)
4109 HANDLE_INHERIT_COND(CSSPropertyMarginBottom, marginBottom, MarginBottom)
4110 HANDLE_INHERIT_COND(CSSPropertyMarginLeft, marginLeft, MarginLeft)
4111 HANDLE_INHERIT_COND(CSSPropertyTextIndent, textIndent, TextIndent)
4112 return;
4113 }
4114 else if (isInitial) {
4115 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMaxWidth, MaxWidth, MaxSize)
4116 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBottom, Bottom, Offset)
4117 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyTop, Top, Offset)
4118 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyLeft, Left, Offset)
4119 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyRight, Right, Offset)
4120 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyWidth, Width, Size)
4121 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMinWidth, MinWidth, MinSize)
4122 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyPaddingTop, PaddingTop, Padding)
4123 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyPaddingRight, PaddingRight, Padding)
4124 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyPaddingBottom, PaddingBottom, Padding)
4125 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyPaddingLeft, PaddingLeft, Padding)
4126 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMarginTop, MarginTop, Margin)
4127 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMarginRight, MarginRight, Margin)
4128 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMarginBottom, MarginBottom, Margin)
4129 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMarginLeft, MarginLeft, Margin)
4130 HANDLE_INITIAL_COND(CSSPropertyTextIndent, TextIndent)
4131 return;
4132 }
4133
4134 if (primitiveValue && !apply) {
4135 int type = primitiveValue->primitiveType();
4136 if (CSSPrimitiveValue::isUnitTypeLength(type))
4137 // Handle our quirky margin units if we have them.
4138 l = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed,
4139 primitiveValue->isQuirkValue());
4140 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
4141 l = Length(primitiveValue->getDoubleValue(), Percent);
4142 else
4143 return;
4144 apply = true;
4145 }
4146 if (!apply) return;
4147 switch (id) {
4148 case CSSPropertyMaxWidth:
4149 m_style->setMaxWidth(l);
4150 break;
4151 case CSSPropertyBottom:
4152 m_style->setBottom(l);
4153 break;
4154 case CSSPropertyTop:
4155 m_style->setTop(l);
4156 break;
4157 case CSSPropertyLeft:
4158 m_style->setLeft(l);
4159 break;
4160 case CSSPropertyRight:
4161 m_style->setRight(l);
4162 break;
4163 case CSSPropertyWidth:
4164 m_style->setWidth(l);
4165 break;
4166 case CSSPropertyMinWidth:
4167 m_style->setMinWidth(l);
4168 break;
4169 case CSSPropertyPaddingTop:
4170 m_style->setPaddingTop(l);
4171 break;
4172 case CSSPropertyPaddingRight:
4173 m_style->setPaddingRight(l);
4174 break;
4175 case CSSPropertyPaddingBottom:
4176 m_style->setPaddingBottom(l);
4177 break;
4178 case CSSPropertyPaddingLeft:
4179 m_style->setPaddingLeft(l);
4180 break;
4181 case CSSPropertyMarginTop:
4182 m_style->setMarginTop(l);
4183 break;
4184 case CSSPropertyMarginRight:
4185 m_style->setMarginRight(l);
4186 break;
4187 case CSSPropertyMarginBottom:
4188 m_style->setMarginBottom(l);
4189 break;
4190 case CSSPropertyMarginLeft:
4191 m_style->setMarginLeft(l);
4192 break;
4193 case CSSPropertyTextIndent:
4194 m_style->setTextIndent(l);
4195 break;
4196 default:
4197 break;
4198 }
4199 return;
4200 }
4201
4202 case CSSPropertyMaxHeight:
4203 if (primitiveValue && primitiveValue->getIdent() == CSSValueNone) {
4204 l = Length(undefinedLength, Fixed);
4205 apply = true;
4206 }
4207 case CSSPropertyHeight:
4208 case CSSPropertyMinHeight:
4209 if (primitiveValue && primitiveValue->getIdent() == CSSValueIntrinsic) {
4210 l = Length(Intrinsic);
4211 apply = true;
4212 } else if (primitiveValue && primitiveValue->getIdent() == CSSValueMinIntrinsic) {
4213 l = Length(MinIntrinsic);
4214 apply = true;
4215 } else if (id != CSSPropertyMaxHeight && primitiveValue && primitiveValue->getIdent() == CSSValueAuto)
4216 apply = true;
4217 if (isInherit) {
4218 HANDLE_INHERIT_COND(CSSPropertyMaxHeight, maxHeight, MaxHeight)
4219 HANDLE_INHERIT_COND(CSSPropertyHeight, height, Height)
4220 HANDLE_INHERIT_COND(CSSPropertyMinHeight, minHeight, MinHeight)
4221 return;
4222 }
4223 if (isInitial) {
4224 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMaxHeight, MaxHeight, MaxSize)
4225 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyHeight, Height, Size)
4226 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMinHeight, MinHeight, MinSize)
4227 return;
4228 }
4229
4230 if (primitiveValue && !apply) {
4231 unsigned short type = primitiveValue->primitiveType();
4232 if (CSSPrimitiveValue::isUnitTypeLength(type))
4233 l = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed);
4234 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
4235 l = Length(primitiveValue->getDoubleValue(), Percent);
4236 else
4237 return;
4238 apply = true;
4239 }
4240 if (apply)
4241 switch (id) {
4242 case CSSPropertyMaxHeight:
4243 m_style->setMaxHeight(l);
4244 break;
4245 case CSSPropertyHeight:
4246 m_style->setHeight(l);
4247 break;
4248 case CSSPropertyMinHeight:
4249 m_style->setMinHeight(l);
4250 break;
4251 }
4252 return;
4253
4254 case CSSPropertyVerticalAlign:
4255 HANDLE_INHERIT_AND_INITIAL(verticalAlign, VerticalAlign)
4256 if (!primitiveValue)
4257 return;
4258 if (primitiveValue->getIdent()) {
4259 EVerticalAlign align;
4260
4261 switch (primitiveValue->getIdent()) {
4262 case CSSValueTop:
4263 align = TOP; break;
4264 case CSSValueBottom:
4265 align = BOTTOM; break;
4266 case CSSValueMiddle:
4267 align = MIDDLE; break;
4268 case CSSValueBaseline:
4269 align = BASELINE; break;
4270 case CSSValueTextBottom:
4271 align = TEXT_BOTTOM; break;
4272 case CSSValueTextTop:
4273 align = TEXT_TOP; break;
4274 case CSSValueSub:
4275 align = SUB; break;
4276 case CSSValueSuper:
4277 align = SUPER; break;
4278 case CSSValueWebkitBaselineMiddle:
4279 align = BASELINE_MIDDLE; break;
4280 default:
4281 return;
4282 }
4283 m_style->setVerticalAlign(align);
4284 return;
4285 } else {
4286 int type = primitiveValue->primitiveType();
4287 Length l;
4288 if (CSSPrimitiveValue::isUnitTypeLength(type))
4289 l = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed);
4290 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
4291 l = Length(primitiveValue->getDoubleValue(), Percent);
4292
4293 m_style->setVerticalAlign(LENGTH);
4294 m_style->setVerticalAlignLength(l);
4295 }
4296 return;
4297
4298 case CSSPropertyFontSize:
4299 {
4300 FontDescription fontDescription = m_style->fontDescription();
4301 fontDescription.setKeywordSize(0);
4302 float oldSize = 0;
4303 float size = 0;
4304
4305 bool parentIsAbsoluteSize = false;
4306 if (m_parentNode) {
4307 oldSize = m_parentStyle->fontDescription().specifiedSize();
4308 parentIsAbsoluteSize = m_parentStyle->fontDescription().isAbsoluteSize();
4309 }
4310
4311 if (isInherit) {
4312 size = oldSize;
4313 if (m_parentNode)
4314 fontDescription.setKeywordSize(m_parentStyle->fontDescription().keywordSize());
4315 } else if (isInitial) {
4316 size = fontSizeForKeyword(m_checker.m_document, CSSValueMedium, fontDescription.useFixedDefaultSize());
4317 fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1);
4318 } else if (primitiveValue->getIdent()) {
4319 // Keywords are being used.
4320 switch (primitiveValue->getIdent()) {
4321 case CSSValueXxSmall:
4322 case CSSValueXSmall:
4323 case CSSValueSmall:
4324 case CSSValueMedium:
4325 case CSSValueLarge:
4326 case CSSValueXLarge:
4327 case CSSValueXxLarge:
4328 case CSSValueWebkitXxxLarge:
4329 size = fontSizeForKeyword(m_checker.m_document, primitiveValue->getIdent(), fontDescription.useFixedDefaultSize());
4330 fontDescription.setKeywordSize(primitiveValue->getIdent() - CSSValueXxSmall + 1);
4331 break;
4332 case CSSValueLarger:
4333 size = largerFontSize(oldSize, m_checker.m_document->inQuirksMode());
4334 break;
4335 case CSSValueSmaller:
4336 size = smallerFontSize(oldSize, m_checker.m_document->inQuirksMode());
4337 break;
4338 default:
4339 return;
4340 }
4341
4342 fontDescription.setIsAbsoluteSize(parentIsAbsoluteSize &&
4343 (primitiveValue->getIdent() == CSSValueLarger ||
4344 primitiveValue->getIdent() == CSSValueSmaller));
4345 } else {
4346 int type = primitiveValue->primitiveType();
4347 fontDescription.setIsAbsoluteSize(parentIsAbsoluteSize ||
4348 (type != CSSPrimitiveValue::CSS_PERCENTAGE &&
4349 type != CSSPrimitiveValue::CSS_EMS &&
4350 type != CSSPrimitiveValue::CSS_EXS &&
4351 type != CSSPrimitiveValue::CSS_REMS));
4352 if (CSSPrimitiveValue::isUnitTypeLength(type))
4353 size = primitiveValue->computeLengthFloat(m_parentStyle, m_rootElementStyle, true);
4354 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
4355 size = (primitiveValue->getFloatValue() * oldSize) / 100.0f;
4356 else
4357 return;
4358 }
4359
4360 if (size < 0)
4361 return;
4362
4363 setFontSize(fontDescription, size);
4364 if (m_style->setFontDescription(fontDescription))
4365 m_fontDirty = true;
4366 return;
4367 }
4368
4369 case CSSPropertyZIndex: {
4370 if (isInherit) {
4371 if (m_parentStyle->hasAutoZIndex())
4372 m_style->setHasAutoZIndex();
4373 else
4374 m_style->setZIndex(m_parentStyle->zIndex());
4375 return;
4376 } else if (isInitial || primitiveValue->getIdent() == CSSValueAuto) {
4377 m_style->setHasAutoZIndex();
4378 return;
4379 }
4380
4381 // FIXME: Should clamp all sorts of other integer properties too.
4382 m_style->setZIndex(clampToInteger(primitiveValue->getDoubleValue()));
4383 return;
4384 }
4385 case CSSPropertyWidows:
4386 {
4387 HANDLE_INHERIT_AND_INITIAL(widows, Widows)
4388 if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER)
4389 return;
4390 m_style->setWidows(primitiveValue->getIntValue());
4391 return;
4392 }
4393
4394 case CSSPropertyOrphans:
4395 {
4396 HANDLE_INHERIT_AND_INITIAL(orphans, Orphans)
4397 if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER)
4398 return;
4399 m_style->setOrphans(primitiveValue->getIntValue());
4400 return;
4401 }
4402
4403 // length, percent, number
4404 case CSSPropertyLineHeight:
4405 {
4406 HANDLE_INHERIT_AND_INITIAL(lineHeight, LineHeight)
4407 if (!primitiveValue)
4408 return;
4409 Length lineHeight;
4410 int type = primitiveValue->primitiveType();
4411 if (primitiveValue->getIdent() == CSSValueNormal)
4412 lineHeight = Length(-100.0, Percent);
4413 else if (CSSPrimitiveValue::isUnitTypeLength(type)) {
4414 double multiplier = zoomFactor;
4415 if (m_style->textSizeAdjust()) {
4416 if (Frame* frame = m_checker.m_document->frame())
4417 multiplier *= frame->textZoomFactor();
4418 }
4419 lineHeight = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, multiplier), Fixed);
4420 } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
4421 lineHeight = Length((m_style->fontSize() * primitiveValue->getIntValue()) / 100, Fixed);
4422 else if (type == CSSPrimitiveValue::CSS_NUMBER)
4423 lineHeight = Length(primitiveValue->getDoubleValue() * 100.0, Percent);
4424 else
4425 return;
4426 m_style->setLineHeight(lineHeight);
4427 return;
4428 }
4429
4430 // string
4431 case CSSPropertyTextAlign:
4432 {
4433 HANDLE_INHERIT_AND_INITIAL(textAlign, TextAlign)
4434 if (!primitiveValue)
4435 return;
4436 if (primitiveValue->getIdent() == CSSValueWebkitMatchParent) {
4437 if (m_parentStyle->textAlign() == TASTART)
4438 m_style->setTextAlign(m_parentStyle->isLeftToRightDirection() ? LEFT : RIGHT);
4439 else if (m_parentStyle->textAlign() == TAEND)
4440 m_style->setTextAlign(m_parentStyle->isLeftToRightDirection() ? RIGHT : LEFT);
4441 else
4442 m_style->setTextAlign(m_parentStyle->textAlign());
4443 return;
4444 }
4445 m_style->setTextAlign(*primitiveValue);
4446 return;
4447 }
4448
4449 // rect
4450 case CSSPropertyClip:
4451 {
4452 Length top;
4453 Length right;
4454 Length bottom;
4455 Length left;
4456 bool hasClip = true;
4457 if (isInherit) {
4458 if (m_parentStyle->hasClip()) {
4459 top = m_parentStyle->clipTop();
4460 right = m_parentStyle->clipRight();
4461 bottom = m_parentStyle->clipBottom();
4462 left = m_parentStyle->clipLeft();
4463 } else {
4464 hasClip = false;
4465 top = right = bottom = left = Length();
4466 }
4467 } else if (isInitial) {
4468 hasClip = false;
4469 top = right = bottom = left = Length();
4470 } else if (!primitiveValue) {
4471 return;
4472 } else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_RECT) {
4473 Rect* rect = primitiveValue->getRectValue();
4474 if (!rect)
4475 return;
4476 top = convertToIntLength(rect->top(), style(), m_rootElementStyle, zoomFactor);
4477 right = convertToIntLength(rect->right(), style(), m_rootElementStyle, zoomFactor);
4478 bottom = convertToIntLength(rect->bottom(), style(), m_rootElementStyle, zoomFactor);
4479 left = convertToIntLength(rect->left(), style(), m_rootElementStyle, zoomFactor);
4480 } else if (primitiveValue->getIdent() != CSSValueAuto) {
4481 return;
4482 }
4483 m_style->setClip(top, right, bottom, left);
4484 m_style->setHasClip(hasClip);
4485
4486 // rect, ident
4487 return;
4488 }
4489
4490 // lists
4491 case CSSPropertyContent:
4492 // list of string, uri, counter, attr, i
4493 {
4494 // FIXME: In CSS3, it will be possible to inherit content. In CSS2 it is not. This
4495 // note is a reminder that eventually "inherit" needs to be supported.
4496
4497 if (isInitial) {
4498 m_style->clearContent();
4499 return;
4500 }
4501
4502 if (!value->isValueList())
4503 return;
4504
4505 CSSValueList* list = static_cast<CSSValueList*>(value);
4506 int len = list->length();
4507
4508 bool didSet = false;
4509 for (int i = 0; i < len; i++) {
4510 CSSValue* item = list->itemWithoutBoundsCheck(i);
4511 if (item->isImageGeneratorValue()) {
4512 m_style->setContent(static_cast<CSSImageGeneratorValue*>(item)->generatedImage(), didSet);
4513 didSet = true;
4514 }
4515
4516 if (!item->isPrimitiveValue())
4517 continue;
4518
4519 CSSPrimitiveValue* contentValue = static_cast<CSSPrimitiveValue*>(item);
4520 switch (contentValue->primitiveType()) {
4521 case CSSPrimitiveValue::CSS_STRING:
4522 m_style->setContent(contentValue->getStringValue().impl(), didSet);
4523 didSet = true;
4524 break;
4525 case CSSPrimitiveValue::CSS_ATTR: {
4526 // FIXME: Can a namespace be specified for an attr(foo)?
4527 if (m_style->styleType() == NOPSEUDO)
4528 m_style->setUnique();
4529 else
4530 m_parentStyle->setUnique();
4531 QualifiedName attr(nullAtom, contentValue->getStringValue().impl(), nullAtom);
4532 m_style->setContent(m_element->getAttribute(attr).impl(), didSet);
4533 didSet = true;
4534 // register the fact that the attribute value affects the style
4535 m_selectorAttrs.add(attr.localName().impl());
4536 break;
4537 }
4538 case CSSPrimitiveValue::CSS_URI: {
4539 if (!contentValue->isImageValue())
4540 break;
4541 m_style->setContent(cachedOrPendingFromValue(CSSPropertyContent, static_cast<CSSImageValue*>(contentValue)), didSet);
4542 didSet = true;
4543 break;
4544 }
4545 case CSSPrimitiveValue::CSS_COUNTER: {
4546 Counter* counterValue = contentValue->getCounterValue();
4547 OwnPtr<CounterContent> counter = adoptPtr(new CounterContent(counterValue->identifier(),
4548 (EListStyleType)counterValue->listStyleNumber(), counterValue->separator()));
4549 m_style->setContent(counter.release(), didSet);
4550 didSet = true;
4551 break;
4552 }
4553 case CSSPrimitiveValue::CSS_IDENT:
4554 switch (contentValue->getIdent()) {
4555 case CSSValueOpenQuote:
4556 m_style->setContent(OPEN_QUOTE, didSet);
4557 didSet = true;
4558 break;
4559 case CSSValueCloseQuote:
4560 m_style->setContent(CLOSE_QUOTE, didSet);
4561 didSet = true;
4562 break;
4563 case CSSValueNoOpenQuote:
4564 m_style->setContent(NO_OPEN_QUOTE, didSet);
4565 didSet = true;
4566 break;
4567 case CSSValueNoCloseQuote:
4568 m_style->setContent(NO_CLOSE_QUOTE, didSet);
4569 didSet = true;
4570 break;
4571 default:
4572 // normal and none do not have any effect.
4573 {}
4574 }
4575 }
4576 }
4577 if (!didSet)
4578 m_style->clearContent();
4579 return;
4580 }
4581 case CSSPropertyQuotes:
4582 if (isInherit) {
4583 if (m_parentStyle)
4584 m_style->setQuotes(m_parentStyle->quotes());
4585 return;
4586 }
4587 if (isInitial) {
4588 m_style->setQuotes(0);
4589 return;
4590 }
4591 if (value->isValueList()) {
4592 CSSValueList* list = static_cast<CSSValueList*>(value);
4593 size_t length = list->length();
4594 QuotesData* data = QuotesData::create(length);
4595 if (!data)
4596 return; // Out of memory
4597 String* quotes = data->data();
4598 for (size_t i = 0; i < length; i++) {
4599 CSSValue* item = list->itemWithoutBoundsCheck(i);
4600 ASSERT(item->isPrimitiveValue());
4601 primitiveValue = static_cast<CSSPrimitiveValue*>(item);
4602 ASSERT(primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_STRING);
4603 quotes[i] = primitiveValue->getStringValue();
4604 }
4605 m_style->setQuotes(adoptRef(data));
4606 } else if (primitiveValue) {
4607 ASSERT(primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_IDENT);
4608 if (primitiveValue->getIdent() == CSSValueNone)
4609 m_style->setQuotes(adoptRef(QuotesData::create(0)));
4610 }
4611 return;
4612
4613 case CSSPropertyCounterIncrement:
4614 applyCounterList(style(), value->isValueList() ? static_cast<CSSValueList*>(value) : 0, false);
4615 return;
4616 case CSSPropertyCounterReset:
4617 applyCounterList(style(), value->isValueList() ? static_cast<CSSValueList*>(value) : 0, true);
4618 return;
4619
4620 case CSSPropertyFontFamily: {
4621 // list of strings and ids
4622 if (isInherit) {
4623 FontDescription parentFontDescription = m_parentStyle->fontDescription();
4624 FontDescription fontDescription = m_style->fontDescription();
4625 fontDescription.setGenericFamily(parentFontDescription.genericFamily());
4626 fontDescription.setFamily(parentFontDescription.firstFamily());
4627 fontDescription.setIsSpecifiedFont(parentFontDescription.isSpecifiedFont());
4628 if (m_style->setFontDescription(fontDescription))
4629 m_fontDirty = true;
4630 return;
4631 } else if (isInitial) {
4632 FontDescription initialDesc = FontDescription();
4633 FontDescription fontDescription = m_style->fontDescription();
4634 // We need to adjust the size to account for the generic family change from monospace
4635 // to non-monospace.
4636 if (fontDescription.keywordSize() && fontDescription.useFixedDefaultSize())
4637 setFontSize(fontDescription, fontSizeForKeyword(m_checker.m_document, CSSValueXxSmall + fontDescription.keywordSize() - 1, false));
4638 fontDescription.setGenericFamily(initialDesc.genericFamily());
4639 if (!initialDesc.firstFamily().familyIsEmpty())
4640 fontDescription.setFamily(initialDesc.firstFamily());
4641 if (m_style->setFontDescription(fontDescription))
4642 m_fontDirty = true;
4643 return;
4644 }
4645
4646 if (!value->isValueList())
4647 return;
4648 FontDescription fontDescription = m_style->fontDescription();
4649 CSSValueList* list = static_cast<CSSValueList*>(value);
4650 int len = list->length();
4651 FontFamily& firstFamily = fontDescription.firstFamily();
4652 FontFamily* currFamily = 0;
4653
4654 // Before mapping in a new font-family property, we should reset the generic family.
4655 bool oldFamilyUsedFixedDefaultSize = fontDescription.useFixedDefaultSize();
4656 fontDescription.setGenericFamily(FontDescription::NoFamily);
4657
4658 for (int i = 0; i < len; i++) {
4659 CSSValue* item = list->itemWithoutBoundsCheck(i);
4660 if (!item->isPrimitiveValue())
4661 continue;
4662 CSSPrimitiveValue* contentValue = static_cast<CSSPrimitiveValue*>(item);
4663 AtomicString face;
4664 Settings* settings = m_checker.m_document->settings();
4665 if (contentValue->primitiveType() == CSSPrimitiveValue::CSS_STRING) {
4666 if (contentValue->isFontFamilyValue())
4667 face = static_cast<FontFamilyValue*>(contentValue)->familyName();
4668 } else if (contentValue->primitiveType() == CSSPrimitiveValue::CSS_IDENT && settings) {
4669 switch (contentValue->getIdent()) {
4670 case CSSValueWebkitBody:
4671 face = settings->standardFontFamily();
4672 break;
4673 case CSSValueSerif:
4674 face = "-webkit-serif";
4675 fontDescription.setGenericFamily(FontDescription::SerifFamily);
4676 break;
4677 case CSSValueSansSerif:
4678 face = "-webkit-sans-serif";
4679 fontDescription.setGenericFamily(FontDescription::SansSerifFamily);
4680 break;
4681 case CSSValueCursive:
4682 face = "-webkit-cursive";
4683 fontDescription.setGenericFamily(FontDescription::CursiveFamily);
4684 break;
4685 case CSSValueFantasy:
4686 face = "-webkit-fantasy";
4687 fontDescription.setGenericFamily(FontDescription::FantasyFamily);
4688 break;
4689 case CSSValueMonospace:
4690 face = "-webkit-monospace";
4691 fontDescription.setGenericFamily(FontDescription::MonospaceFamily);
4692 break;
4693 }
4694 }
4695
4696 if (!face.isEmpty()) {
4697 if (!currFamily) {
4698 // Filling in the first family.
4699 firstFamily.setFamily(face);
4700 firstFamily.appendFamily(0); // Remove any inherited family-fallback list.
4701 currFamily = &firstFamily;
4702 fontDescription.setIsSpecifiedFont(fontDescription.genericFamily() == FontDescription::NoFamily);
4703 } else {
4704 RefPtr<SharedFontFamily> newFamily = SharedFontFamily::create();
4705 newFamily->setFamily(face);
4706 currFamily->appendFamily(newFamily);
4707 currFamily = newFamily.get();
4708 }
4709 }
4710 }
4711
4712 // We can't call useFixedDefaultSize() until all new font families have been added
4713 // If currFamily is non-zero then we set at least one family on this description.
4714 if (currFamily) {
4715 if (fontDescription.keywordSize() && fontDescription.useFixedDefaultSize() != oldFamilyUsedFixedDefaultSize)
4716 setFontSize(fontDescription, fontSizeForKeyword(m_checker.m_document, CSSValueXxSmall + fontDescription.keywordSize() - 1, !oldFamilyUsedFixedDefaultSize));
4717
4718 if (m_style->setFontDescription(fontDescription))
4719 m_fontDirty = true;
4720 }
4721 return;
4722 }
4723 case CSSPropertyTextDecoration: {
4724 // list of ident
4725 HANDLE_INHERIT_AND_INITIAL(textDecoration, TextDecoration)
4726 int t = RenderStyle::initialTextDecoration();
4727 if (primitiveValue && primitiveValue->getIdent() == CSSValueNone) {
4728 // do nothing
4729 } else {
4730 if (!value->isValueList())
4731 return;
4732 CSSValueList *list = static_cast<CSSValueList*>(value);
4733 int len = list->length();
4734 for (int i = 0; i < len; i++)
4735 {
4736 CSSValue *item = list->itemWithoutBoundsCheck(i);
4737 if (!item->isPrimitiveValue())
4738 continue;
4739 primitiveValue = static_cast<CSSPrimitiveValue*>(item);
4740 switch (primitiveValue->getIdent()) {
4741 case CSSValueNone:
4742 t = TDNONE; break;
4743 case CSSValueUnderline:
4744 t |= UNDERLINE; break;
4745 case CSSValueOverline:
4746 t |= OVERLINE; break;
4747 case CSSValueLineThrough:
4748 t |= LINE_THROUGH; break;
4749 case CSSValueBlink:
4750 t |= BLINK; break;
4751 default:
4752 return;
4753 }
4754 }
4755 }
4756
4757 m_style->setTextDecoration(t);
4758 return;
4759 }
4760
4761 case CSSPropertyZoom:
4762 {
4763 // Reset the zoom in effect before we do anything. This allows the setZoom method to accurately compute a new
4764 // zoom in effect.
4765 m_style->setEffectiveZoom(m_parentStyle ? m_parentStyle->effectiveZoom() : RenderStyle::initialZoom());
4766
4767 // Now we can handle inherit and initial.
4768 HANDLE_INHERIT_AND_INITIAL(zoom, Zoom)
4769
4770 // Handle normal/reset, numbers and percentages.
4771 int type = primitiveValue->primitiveType();
4772 if (primitiveValue->getIdent() == CSSValueNormal)
4773 m_style->setZoom(RenderStyle::initialZoom());
4774 else if (primitiveValue->getIdent() == CSSValueReset) {
4775 m_style->setEffectiveZoom(RenderStyle::initialZoom());
4776 m_style->setZoom(RenderStyle::initialZoom());
4777 } else if (primitiveValue->getIdent() == CSSValueDocument) {
4778 float docZoom = m_checker.m_document->renderer()->style()->zoom();
4779 m_style->setEffectiveZoom(docZoom);
4780 m_style->setZoom(docZoom);
4781 } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) {
4782 if (primitiveValue->getFloatValue())
4783 m_style->setZoom(primitiveValue->getFloatValue() / 100.0f);
4784 } else if (type == CSSPrimitiveValue::CSS_NUMBER) {
4785 if (primitiveValue->getFloatValue())
4786 m_style->setZoom(primitiveValue->getFloatValue());
4787 }
4788
4789 m_fontDirty = true;
4790 return;
4791 }
4792 // shorthand properties
4793 case CSSPropertyBackground:
4794 if (isInitial) {
4795 m_style->clearBackgroundLayers();
4796 m_style->setBackgroundColor(Color());
4797 }
4798 else if (isInherit) {
4799 m_style->inheritBackgroundLayers(*m_parentStyle->backgroundLayers());
4800 m_style->setBackgroundColor(m_parentStyle->backgroundColor());
4801 }
4802 return;
4803 case CSSPropertyWebkitMask:
4804 if (isInitial)
4805 m_style->clearMaskLayers();
4806 else if (isInherit)
4807 m_style->inheritMaskLayers(*m_parentStyle->maskLayers());
4808 return;
4809
4810 case CSSPropertyBorder:
4811 case CSSPropertyBorderStyle:
4812 case CSSPropertyBorderWidth:
4813 case CSSPropertyBorderColor:
4814 if (id == CSSPropertyBorder || id == CSSPropertyBorderColor)
4815 {
4816 if (isInherit) {
4817 m_style->setBorderTopColor(m_parentStyle->borderTopColor().isValid() ? m_parentStyle->borderTopColor() : m_parentStyle->color());
4818 m_style->setBorderBottomColor(m_parentStyle->borderBottomColor().isValid() ? m_parentStyle->borderBottomColor() : m_parentStyle->color());
4819 m_style->setBorderLeftColor(m_parentStyle->borderLeftColor().isValid() ? m_parentStyle->borderLeftColor() : m_parentStyle->color());
4820 m_style->setBorderRightColor(m_parentStyle->borderRightColor().isValid() ? m_parentStyle->borderRightColor(): m_parentStyle->color());
4821 }
4822 else if (isInitial) {
4823 m_style->setBorderTopColor(Color()); // Reset to invalid color so currentColor is used instead.
4824 m_style->setBorderBottomColor(Color());
4825 m_style->setBorderLeftColor(Color());
4826 m_style->setBorderRightColor(Color());
4827 }
4828 }
4829 if (id == CSSPropertyBorder || id == CSSPropertyBorderStyle)
4830 {
4831 if (isInherit) {
4832 m_style->setBorderTopStyle(m_parentStyle->borderTopStyle());
4833 m_style->setBorderBottomStyle(m_parentStyle->borderBottomStyle());
4834 m_style->setBorderLeftStyle(m_parentStyle->borderLeftStyle());
4835 m_style->setBorderRightStyle(m_parentStyle->borderRightStyle());
4836 }
4837 else if (isInitial) {
4838 m_style->setBorderTopStyle(RenderStyle::initialBorderStyle());
4839 m_style->setBorderBottomStyle(RenderStyle::initialBorderStyle());
4840 m_style->setBorderLeftStyle(RenderStyle::initialBorderStyle());
4841 m_style->setBorderRightStyle(RenderStyle::initialBorderStyle());
4842 }
4843 }
4844 if (id == CSSPropertyBorder || id == CSSPropertyBorderWidth)
4845 {
4846 if (isInherit) {
4847 m_style->setBorderTopWidth(m_parentStyle->borderTopWidth());
4848 m_style->setBorderBottomWidth(m_parentStyle->borderBottomWidth());
4849 m_style->setBorderLeftWidth(m_parentStyle->borderLeftWidth());
4850 m_style->setBorderRightWidth(m_parentStyle->borderRightWidth());
4851 }
4852 else if (isInitial) {
4853 m_style->setBorderTopWidth(RenderStyle::initialBorderWidth());
4854 m_style->setBorderBottomWidth(RenderStyle::initialBorderWidth());
4855 m_style->setBorderLeftWidth(RenderStyle::initialBorderWidth());
4856 m_style->setBorderRightWidth(RenderStyle::initialBorderWidth());
4857 }
4858 }
4859 return;
4860 case CSSPropertyBorderTop:
4861 if (isInherit) {
4862 m_style->setBorderTopColor(m_parentStyle->borderTopColor().isValid() ? m_parentStyle->borderTopColor() : m_parentStyle->color());
4863 m_style->setBorderTopStyle(m_parentStyle->borderTopStyle());
4864 m_style->setBorderTopWidth(m_parentStyle->borderTopWidth());
4865 }
4866 else if (isInitial)
4867 m_style->resetBorderTop();
4868 return;
4869 case CSSPropertyBorderRight:
4870 if (isInherit) {
4871 m_style->setBorderRightColor(m_parentStyle->borderRightColor().isValid() ? m_parentStyle->borderRightColor() : m_parentStyle->color());
4872 m_style->setBorderRightStyle(m_parentStyle->borderRightStyle());
4873 m_style->setBorderRightWidth(m_parentStyle->borderRightWidth());
4874 }
4875 else if (isInitial)
4876 m_style->resetBorderRight();
4877 return;
4878 case CSSPropertyBorderBottom:
4879 if (isInherit) {
4880 m_style->setBorderBottomColor(m_parentStyle->borderBottomColor().isValid() ? m_parentStyle->borderBottomColor() : m_parentStyle->color());
4881 m_style->setBorderBottomStyle(m_parentStyle->borderBottomStyle());
4882 m_style->setBorderBottomWidth(m_parentStyle->borderBottomWidth());
4883 }
4884 else if (isInitial)
4885 m_style->resetBorderBottom();
4886 return;
4887 case CSSPropertyBorderLeft:
4888 if (isInherit) {
4889 m_style->setBorderLeftColor(m_parentStyle->borderLeftColor().isValid() ? m_parentStyle->borderLeftColor() : m_parentStyle->color());
4890 m_style->setBorderLeftStyle(m_parentStyle->borderLeftStyle());
4891 m_style->setBorderLeftWidth(m_parentStyle->borderLeftWidth());
4892 }
4893 else if (isInitial)
4894 m_style->resetBorderLeft();
4895 return;
4896 case CSSPropertyMargin:
4897 if (isInherit) {
4898 m_style->setMarginTop(m_parentStyle->marginTop());
4899 m_style->setMarginBottom(m_parentStyle->marginBottom());
4900 m_style->setMarginLeft(m_parentStyle->marginLeft());
4901 m_style->setMarginRight(m_parentStyle->marginRight());
4902 }
4903 else if (isInitial)
4904 m_style->resetMargin();
4905 return;
4906 case CSSPropertyPadding:
4907 if (isInherit) {
4908 m_style->setPaddingTop(m_parentStyle->paddingTop());
4909 m_style->setPaddingBottom(m_parentStyle->paddingBottom());
4910 m_style->setPaddingLeft(m_parentStyle->paddingLeft());
4911 m_style->setPaddingRight(m_parentStyle->paddingRight());
4912 }
4913 else if (isInitial)
4914 m_style->resetPadding();
4915 return;
4916 case CSSPropertyFont:
4917 if (isInherit) {
4918 FontDescription fontDescription = m_parentStyle->fontDescription();
4919 m_style->setLineHeight(m_parentStyle->lineHeight());
4920 m_lineHeightValue = 0;
4921 if (m_style->setFontDescription(fontDescription))
4922 m_fontDirty = true;
4923 } else if (isInitial) {
4924 Settings* settings = m_checker.m_document->settings();
4925 ASSERT(settings); // If we're doing style resolution, this document should always be in a frame and thus have settings
4926 if (!settings)
4927 return;
4928 FontDescription fontDescription;
4929 fontDescription.setGenericFamily(FontDescription::StandardFamily);
4930 fontDescription.setRenderingMode(settings->fontRenderingMode());
4931 fontDescription.setUsePrinterFont(m_checker.m_document->printing());
4932 const AtomicString& standardFontFamily = m_checker.m_document->settings()->standardFontFamily();
4933 if (!standardFontFamily.isEmpty()) {
4934 fontDescription.firstFamily().setFamily(standardFontFamily);
4935 fontDescription.firstFamily().appendFamily(0);
4936 }
4937 fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1);
4938 setFontSize(fontDescription, fontSizeForKeyword(m_checker.m_document, CSSValueMedium, false));
4939 m_style->setLineHeight(RenderStyle::initialLineHeight());
4940 m_lineHeightValue = 0;
4941 if (m_style->setFontDescription(fontDescription))
4942 m_fontDirty = true;
4943 } else if (primitiveValue) {
4944 m_style->setLineHeight(RenderStyle::initialLineHeight());
4945 m_lineHeightValue = 0;
4946
4947 FontDescription fontDescription;
4948 RenderTheme::defaultTheme()->systemFont(primitiveValue->getIdent(), fontDescription);
4949
4950 // Double-check and see if the theme did anything. If not, don't bother updating the font.
4951 if (fontDescription.isAbsoluteSize()) {
4952 // Make sure the rendering mode and printer font settings are updated.
4953 Settings* settings = m_checker.m_document->settings();
4954 ASSERT(settings); // If we're doing style resolution, this document should always be in a frame and thus have settings
4955 if (!settings)
4956 return;
4957 fontDescription.setRenderingMode(settings->fontRenderingMode());
4958 fontDescription.setUsePrinterFont(m_checker.m_document->printing());
4959
4960 // Handle the zoom factor.
4961 fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(m_checker.m_document, m_style.get(), fontDescription.isAbsoluteSize(), fontDescription.specifiedSize(), useSVGZoomRules(m_element)));
4962 if (m_style->setFontDescription(fontDescription))
4963 m_fontDirty = true;
4964 }
4965 } else if (value->isFontValue()) {
4966 FontValue *font = static_cast<FontValue*>(value);
4967 if (!font->style || !font->variant || !font->weight ||
4968 !font->size || !font->lineHeight || !font->family)
4969 return;
4970 applyProperty(CSSPropertyFontStyle, font->style.get());
4971 applyProperty(CSSPropertyFontVariant, font->variant.get());
4972 applyProperty(CSSPropertyFontWeight, font->weight.get());
4973 // The previous properties can dirty our font but they don't try to read the font's
4974 // properties back, which is safe. However if font-size is using the 'ex' unit, it will
4975 // need query the dirtied font's x-height to get the computed size. To be safe in this
4976 // case, let's just update the font now.
4977 updateFont();
4978 applyProperty(CSSPropertyFontSize, font->size.get());
4979
4980 m_lineHeightValue = font->lineHeight.get();
4981
4982 applyProperty(CSSPropertyFontFamily, font->family.get());
4983 }
4984 return;
4985
4986 case CSSPropertyListStyle:
4987 if (isInherit) {
4988 m_style->setListStyleType(m_parentStyle->listStyleType());
4989 m_style->setListStyleImage(m_parentStyle->listStyleImage());
4990 m_style->setListStylePosition(m_parentStyle->listStylePosition());
4991 }
4992 else if (isInitial) {
4993 m_style->setListStyleType(RenderStyle::initialListStyleType());
4994 m_style->setListStyleImage(RenderStyle::initialListStyleImage());
4995 m_style->setListStylePosition(RenderStyle::initialListStylePosition());
4996 }
4997 return;
4998 case CSSPropertyOutline:
4999 if (isInherit) {
5000 m_style->setOutlineWidth(m_parentStyle->outlineWidth());
5001 m_style->setOutlineColor(m_parentStyle->outlineColor().isValid() ? m_parentStyle->outlineColor() : m_parentStyle->color());
5002 m_style->setOutlineStyle(m_parentStyle->outlineStyle());
5003 }
5004 else if (isInitial)
5005 m_style->resetOutline();
5006 return;
5007
5008 // CSS3 Properties
5009 case CSSPropertyWebkitAppearance: {
5010 HANDLE_INHERIT_AND_INITIAL(appearance, Appearance)
5011 if (!primitiveValue)
5012 return;
5013 m_style->setAppearance(*primitiveValue);
5014 return;
5015 }
5016
5017 case CSSPropertyWebkitBorderImage:
5018 case CSSPropertyWebkitMaskBoxImage: {
5019 if (isInherit) {
5020 HANDLE_INHERIT_COND(CSSPropertyWebkitBorderImage, borderImage, BorderImage)
5021 HANDLE_INHERIT_COND(CSSPropertyWebkitMaskBoxImage, maskBoxImage, MaskBoxImage)
5022 return;
5023 } else if (isInitial) {
5024 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyWebkitBorderImage, BorderImage, NinePieceImage)
5025 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyWebkitMaskBoxImage, MaskBoxImage, NinePieceImage)
5026 return;
5027 }
5028
5029 NinePieceImage image;
5030 mapNinePieceImage(property, value, image);
5031
5032 if (id == CSSPropertyWebkitBorderImage)
5033 m_style->setBorderImage(image);
5034 else
5035 m_style->setMaskBoxImage(image);
5036 return;
5037 }
5038
5039 case CSSPropertyBorderRadius:
5040 case CSSPropertyWebkitBorderRadius:
5041 if (isInherit) {
5042 m_style->setBorderTopLeftRadius(m_parentStyle->borderTopLeftRadius());
5043 m_style->setBorderTopRightRadius(m_parentStyle->borderTopRightRadius());
5044 m_style->setBorderBottomLeftRadius(m_parentStyle->borderBottomLeftRadius());
5045 m_style->setBorderBottomRightRadius(m_parentStyle->borderBottomRightRadius());
5046 return;
5047 }
5048 if (isInitial) {
5049 m_style->resetBorderRadius();
5050 return;
5051 }
5052 // Fall through
5053 case CSSPropertyBorderTopLeftRadius:
5054 case CSSPropertyBorderTopRightRadius:
5055 case CSSPropertyBorderBottomLeftRadius:
5056 case CSSPropertyBorderBottomRightRadius: {
5057 if (isInherit) {
5058 HANDLE_INHERIT_COND(CSSPropertyBorderTopLeftRadius, borderTopLeftRadius, BorderTopLeftRadius)
5059 HANDLE_INHERIT_COND(CSSPropertyBorderTopRightRadius, borderTopRightRadius, BorderTopRightRadius)
5060 HANDLE_INHERIT_COND(CSSPropertyBorderBottomLeftRadius, borderBottomLeftRadius, BorderBottomLeftRadius)
5061 HANDLE_INHERIT_COND(CSSPropertyBorderBottomRightRadius, borderBottomRightRadius, BorderBottomRightRadius)
5062 return;
5063 }
5064
5065 if (isInitial) {
5066 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderTopLeftRadius, BorderTopLeftRadius, BorderRadius)
5067 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderTopRightRadius, BorderTopRightRadius, BorderRadius)
5068 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderBottomLeftRadius, BorderBottomLeftRadius, BorderRadius)
5069 HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderBottomRightRadius, BorderBottomRightRadius, BorderRadius)
5070 return;
5071 }
5072
5073 if (!primitiveValue)
5074 return;
5075
5076 Pair* pair = primitiveValue->getPairValue();
5077 if (!pair || !pair->first() || !pair->second())
5078 return;
5079
5080 Length radiusWidth;
5081 Length radiusHeight;
5082 if (pair->first()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE)
5083 radiusWidth = Length(pair->first()->getDoubleValue(), Percent);
5084 else
5085 radiusWidth = Length(max(intMinForLength, min(intMaxForLength, pair->first()->computeLengthInt(style(), m_rootElementStyle, zoomFactor))), Fixed);
5086 if (pair->second()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE)
5087 radiusHeight = Length(pair->second()->getDoubleValue(), Percent);
5088 else
5089 radiusHeight = Length(max(intMinForLength, min(intMaxForLength, pair->second()->computeLengthInt(style(), m_rootElementStyle, zoomFactor))), Fixed);
5090 int width = radiusWidth.value();
5091 int height = radiusHeight.value();
5092 if (width < 0 || height < 0)
5093 return;
5094 if (width == 0)
5095 radiusHeight = radiusWidth; // Null out the other value.
5096 else if (height == 0)
5097 radiusWidth = radiusHeight; // Null out the other value.
5098
5099 LengthSize size(radiusWidth, radiusHeight);
5100 switch (id) {
5101 case CSSPropertyBorderTopLeftRadius:
5102 m_style->setBorderTopLeftRadius(size);
5103 break;
5104 case CSSPropertyBorderTopRightRadius:
5105 m_style->setBorderTopRightRadius(size);
5106 break;
5107 case CSSPropertyBorderBottomLeftRadius:
5108 m_style->setBorderBottomLeftRadius(size);
5109 break;
5110 case CSSPropertyBorderBottomRightRadius:
5111 m_style->setBorderBottomRightRadius(size);
5112 break;
5113 default:
5114 m_style->setBorderRadius(size);
5115 break;
5116 }
5117 return;
5118 }
5119
5120 case CSSPropertyOutlineOffset:
5121 HANDLE_INHERIT_AND_INITIAL(outlineOffset, OutlineOffset)
5122 m_style->setOutlineOffset(primitiveValue->computeLengthInt(style(), m_rootElementStyle, zoomFactor));
5123 return;
5124 case CSSPropertyTextRendering: {
5125 FontDescription fontDescription = m_style->fontDescription();
5126 if (isInherit)
5127 fontDescription.setTextRenderingMode(m_parentStyle->fontDescription().textRenderingMode());
5128 else if (isInitial)
5129 fontDescription.setTextRenderingMode(AutoTextRendering);
5130 else {
5131 if (!primitiveValue)
5132 return;
5133 fontDescription.setTextRenderingMode(*primitiveValue);
5134 }
5135 if (m_style->setFontDescription(fontDescription))
5136 m_fontDirty = true;
5137 return;
5138 }
5139 case CSSPropertyTextShadow:
5140 case CSSPropertyBoxShadow:
5141 case CSSPropertyWebkitBoxShadow: {
5142 if (isInherit) {
5143 if (id == CSSPropertyTextShadow)
5144 return m_style->setTextShadow(m_parentStyle->textShadow() ? new ShadowData(*m_parentStyle->textShadow()) : 0);
5145 return m_style->setBoxShadow(m_parentStyle->boxShadow() ? new ShadowData(*m_parentStyle->boxShadow()) : 0);
5146 }
5147 if (isInitial || primitiveValue) // initial | none
5148 return id == CSSPropertyTextShadow ? m_style->setTextShadow(0) : m_style->setBoxShadow(0);
5149
5150 if (!value->isValueList())
5151 return;
5152
5153 CSSValueList *list = static_cast<CSSValueList*>(value);
5154 int len = list->length();
5155 for (int i = 0; i < len; i++) {
5156 CSSValue* currValue = list->itemWithoutBoundsCheck(i);
5157 if (!currValue->isShadowValue())
5158 continue;
5159 ShadowValue* item = static_cast<ShadowValue*>(list->itemWithoutBoundsCheck(i));
5160 int x = item->x->computeLengthInt(style(), m_rootElementStyle, zoomFactor);
5161 int y = item->y->computeLengthInt(style(), m_rootElementStyle, zoomFactor);
5162 int blur = item->blur ? item->blur->computeLengthInt(style(), m_rootElementStyle, zoomFactor) : 0;
5163 int spread = item->spread ? item->spread->computeLengthInt(style(), m_rootElementStyle, zoomFactor) : 0;
5164 ShadowStyle shadowStyle = item->style && item->style->getIdent() == CSSValueInset ? Inset : Normal;
5165 Color color;
5166 if (item->color)
5167 color = getColorFromPrimitiveValue(item->color.get());
5168 ShadowData* shadowData = new ShadowData(x, y, blur, spread, shadowStyle, id == CSSPropertyWebkitBoxShadow, color.isValid() ? color : Color::transparent);
5169 if (id == CSSPropertyTextShadow)
5170 m_style->setTextShadow(shadowData, i != 0);
5171 else
5172 m_style->setBoxShadow(shadowData, i != 0);
5173 }
5174 return;
5175 }
5176 case CSSPropertyWebkitBoxReflect: {
5177 HANDLE_INHERIT_AND_INITIAL(boxReflect, BoxReflect)
5178 if (primitiveValue) {
5179 m_style->setBoxReflect(RenderStyle::initialBoxReflect());
5180 return;
5181 }
5182
5183 if (!value->isReflectValue())
5184 return;
5185
5186 CSSReflectValue* reflectValue = static_cast<CSSReflectValue*>(value);
5187 RefPtr<StyleReflection> reflection = StyleReflection::create();
5188 reflection->setDirection(reflectValue->direction());
5189 if (reflectValue->offset()) {
5190 int type = reflectValue->offset()->primitiveType();
5191 if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
5192 reflection->setOffset(Length(reflectValue->offset()->getDoubleValue(), Percent));
5193 else
5194 reflection->setOffset(Length(reflectValue->offset()->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed));
5195 }
5196 NinePieceImage mask;
5197 mapNinePieceImage(property, reflectValue->mask(), mask);
5198 reflection->setMask(mask);
5199
5200 m_style->setBoxReflect(reflection.release());
5201 return;
5202 }
5203 case CSSPropertyOpacity:
5204 HANDLE_INHERIT_AND_INITIAL(opacity, Opacity)
5205 if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER)
5206 return; // Error case.
5207 // Clamp opacity to the range 0-1
5208 m_style->setOpacity(min(1.0f, max(0.0f, primitiveValue->getFloatValue())));
5209 return;
5210 case CSSPropertyWebkitBoxAlign:
5211 {
5212 HANDLE_INHERIT_AND_INITIAL(boxAlign, BoxAlign)
5213 if (!primitiveValue)
5214 return;
5215 EBoxAlignment boxAlignment = *primitiveValue;
5216 if (boxAlignment != BJUSTIFY)
5217 m_style->setBoxAlign(boxAlignment);
5218 return;
5219 }
5220 case CSSPropertySrc: // Only used in @font-face rules.
5221 return;
5222 case CSSPropertyUnicodeRange: // Only used in @font-face rules.
5223 return;
5224 case CSSPropertyWebkitBackfaceVisibility:
5225 HANDLE_INHERIT_AND_INITIAL(backfaceVisibility, BackfaceVisibility)
5226 if (primitiveValue)
5227 m_style->setBackfaceVisibility((primitiveValue->getIdent() == CSSValueVisible) ? BackfaceVisibilityVisible : BackfaceVisibilityHidden);
5228 return;
5229 case CSSPropertyWebkitBoxDirection:
5230 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(boxDirection, BoxDirection)
5231 return;
5232 case CSSPropertyWebkitBoxLines:
5233 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(boxLines, BoxLines)
5234 return;
5235 case CSSPropertyWebkitBoxOrient:
5236 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(boxOrient, BoxOrient)
5237 return;
5238 case CSSPropertyWebkitBoxPack:
5239 {
5240 HANDLE_INHERIT_AND_INITIAL(boxPack, BoxPack)
5241 if (!primitiveValue)
5242 return;
5243 EBoxAlignment boxPack = *primitiveValue;
5244 if (boxPack != BSTRETCH && boxPack != BBASELINE)
5245 m_style->setBoxPack(boxPack);
5246 return;
5247 }
5248 case CSSPropertyWebkitBoxFlex:
5249 HANDLE_INHERIT_AND_INITIAL(boxFlex, BoxFlex)
5250 if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER)
5251 return; // Error case.
5252 m_style->setBoxFlex(primitiveValue->getFloatValue());
5253 return;
5254 case CSSPropertyWebkitBoxFlexGroup:
5255 HANDLE_INHERIT_AND_INITIAL(boxFlexGroup, BoxFlexGroup)
5256 if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER)
5257 return; // Error case.
5258 m_style->setBoxFlexGroup((unsigned int)(primitiveValue->getDoubleValue()));
5259 return;
5260 case CSSPropertyWebkitBoxOrdinalGroup:
5261 HANDLE_INHERIT_AND_INITIAL(boxOrdinalGroup, BoxOrdinalGroup)
5262 if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER)
5263 return; // Error case.
5264 m_style->setBoxOrdinalGroup((unsigned int)(primitiveValue->getDoubleValue()));
5265 return;
5266 case CSSPropertyBoxSizing:
5267 HANDLE_INHERIT_AND_INITIAL(boxSizing, BoxSizing)
5268 if (!primitiveValue)
5269 return;
5270 if (primitiveValue->getIdent() == CSSValueContentBox)
5271 m_style->setBoxSizing(CONTENT_BOX);
5272 else
5273 m_style->setBoxSizing(BORDER_BOX);
5274 return;
5275 case CSSPropertyWebkitColumnCount: {
5276 if (isInherit) {
5277 if (m_parentStyle->hasAutoColumnCount())
5278 m_style->setHasAutoColumnCount();
5279 else
5280 m_style->setColumnCount(m_parentStyle->columnCount());
5281 return;
5282 } else if (isInitial || primitiveValue->getIdent() == CSSValueAuto) {
5283 m_style->setHasAutoColumnCount();
5284 return;
5285 }
5286 m_style->setColumnCount(static_cast<unsigned short>(primitiveValue->getDoubleValue()));
5287 return;
5288 }
5289 case CSSPropertyWebkitColumnGap: {
5290 if (isInherit) {
5291 if (m_parentStyle->hasNormalColumnGap())
5292 m_style->setHasNormalColumnGap();
5293 else
5294 m_style->setColumnGap(m_parentStyle->columnGap());
5295 return;
5296 } else if (isInitial || primitiveValue->getIdent() == CSSValueNormal) {
5297 m_style->setHasNormalColumnGap();
5298 return;
5299 }
5300 m_style->setColumnGap(primitiveValue->computeLengthFloat(style(), m_rootElementStyle, zoomFactor));
5301 return;
5302 }
5303 case CSSPropertyWebkitColumnSpan: {
5304 HANDLE_INHERIT_AND_INITIAL(columnSpan, ColumnSpan)
5305 m_style->setColumnSpan(primitiveValue->getIdent() == CSSValueAll);
5306 return;
5307 }
5308 case CSSPropertyWebkitColumnWidth: {
5309 if (isInherit) {
5310 if (m_parentStyle->hasAutoColumnWidth())
5311 m_style->setHasAutoColumnWidth();
5312 else
5313 m_style->setColumnWidth(m_parentStyle->columnWidth());
5314 return;
5315 } else if (isInitial || primitiveValue->getIdent() == CSSValueAuto) {
5316 m_style->setHasAutoColumnWidth();
5317 return;
5318 }
5319 m_style->setColumnWidth(primitiveValue->computeLengthFloat(style(), m_rootElementStyle, zoomFactor));
5320 return;
5321 }
5322 case CSSPropertyWebkitColumnRuleStyle:
5323 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(columnRuleStyle, ColumnRuleStyle, BorderStyle)
5324 return;
5325 case CSSPropertyWebkitColumnBreakBefore:
5326 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(columnBreakBefore, ColumnBreakBefore, PageBreak)
5327 return;
5328 case CSSPropertyWebkitColumnBreakAfter:
5329 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE_WITH_VALUE(columnBreakAfter, ColumnBreakAfter, PageBreak)
5330 return;
5331 case CSSPropertyWebkitColumnBreakInside: {
5332 HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(columnBreakInside, ColumnBreakInside, PageBreak)
5333 EPageBreak pb = *primitiveValue;
5334 if (pb != PBALWAYS)
5335 m_style->setColumnBreakInside(pb);
5336 return;
5337 }
5338 case CSSPropertyWebkitColumnRule:
5339 if (isInherit) {
5340 m_style->setColumnRuleColor(m_parentStyle->columnRuleColor().isValid() ? m_parentStyle->columnRuleColor() : m_parentStyle->color());
5341 m_style->setColumnRuleStyle(m_parentStyle->columnRuleStyle());
5342 m_style->setColumnRuleWidth(m_parentStyle->columnRuleWidth());
5343 }
5344 else if (isInitial)
5345 m_style->resetColumnRule();
5346 return;
5347 case CSSPropertyWebkitColumns:
5348 if (isInherit) {
5349 if (m_parentStyle->hasAutoColumnWidth())
5350 m_style->setHasAutoColumnWidth();
5351 else
5352 m_style->setColumnWidth(m_parentStyle->columnWidth());
5353 m_style->setColumnCount(m_parentStyle->columnCount());
5354 } else if (isInitial) {
5355 m_style->setHasAutoColumnWidth();
5356 m_style->setColumnCount(RenderStyle::initialColumnCount());
5357 }
5358 return;
5359 case CSSPropertyWebkitMarquee:
5360 if (valueType != CSSValue::CSS_INHERIT || !m_parentNode) return;
5361 m_style->setMarqueeDirection(m_parentStyle->marqueeDirection());
5362 m_style->setMarqueeIncrement(m_parentStyle->marqueeIncrement());
5363 m_style->setMarqueeSpeed(m_parentStyle->marqueeSpeed());
5364 m_style->setMarqueeLoopCount(m_parentStyle->marqueeLoopCount());
5365 m_style->setMarqueeBehavior(m_parentStyle->marqueeBehavior());
5366 return;
5367 #if ENABLE(WCSS)
5368 case CSSPropertyWapMarqueeLoop:
5369 #endif
5370 case CSSPropertyWebkitMarqueeRepetition: {
5371 HANDLE_INHERIT_AND_INITIAL(marqueeLoopCount, MarqueeLoopCount)
5372 if (!primitiveValue)
5373 return;
5374 if (primitiveValue->getIdent() == CSSValueInfinite)
5375 m_style->setMarqueeLoopCount(-1); // -1 means repeat forever.
5376 else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_NUMBER)
5377 m_style->setMarqueeLoopCount(primitiveValue->getIntValue());
5378 return;
5379 }
5380 #if ENABLE(WCSS)
5381 case CSSPropertyWapMarqueeSpeed:
5382 #endif
5383 case CSSPropertyWebkitMarqueeSpeed: {
5384 HANDLE_INHERIT_AND_INITIAL(marqueeSpeed, MarqueeSpeed)
5385 if (!primitiveValue)
5386 return;
5387 if (primitiveValue->getIdent()) {
5388 switch (primitiveValue->getIdent()) {
5389 case CSSValueSlow:
5390 m_style->setMarqueeSpeed(500); // 500 msec.
5391 break;
5392 case CSSValueNormal:
5393 m_style->setMarqueeSpeed(85); // 85msec. The WinIE default.
5394 break;
5395 case CSSValueFast:
5396 m_style->setMarqueeSpeed(10); // 10msec. Super fast.
5397 break;
5398 }
5399 }
5400 else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_S)
5401 m_style->setMarqueeSpeed(1000 * primitiveValue->getIntValue());
5402 else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_MS)
5403 m_style->setMarqueeSpeed(primitiveValue->getIntValue());
5404 else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) // For scrollamount support.
5405 m_style->setMarqueeSpeed(primitiveValue->getIntValue());
5406 return;
5407 }
5408 case CSSPropertyWebkitMarqueeIncrement: {
5409 HANDLE_INHERIT_AND_INITIAL(marqueeIncrement, MarqueeIncrement)
5410 if (!primitiveValue)
5411 return;
5412 if (primitiveValue->getIdent()) {
5413 switch (primitiveValue->getIdent()) {
5414 case CSSValueSmall:
5415 m_style->setMarqueeIncrement(Length(1, Fixed)); // 1px.
5416 break;
5417 case CSSValueNormal:
5418 m_style->setMarqueeIncrement(Length(6, Fixed)); // 6px. The WinIE default.
5419 break;
5420 case CSSValueLarge:
5421 m_style->setMarqueeIncrement(Length(36, Fixed)); // 36px.
5422 break;
5423 }
5424 }
5425 else {
5426 bool ok = true;
5427 Length marqueeLength = convertToIntLength(primitiveValue, style(), m_rootElementStyle, 1, &ok);
5428 if (ok)
5429 m_style->setMarqueeIncrement(marqueeLength);
5430 }
5431 return;
5432 }
5433 #if ENABLE(WCSS)
5434 case CSSPropertyWapMarqueeStyle:
5435 #endif
5436 case CSSPropertyWebkitMarqueeStyle:
5437 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(marqueeBehavior, MarqueeBehavior)
5438 return;
5439 #if ENABLE(WCSS)
5440 case CSSPropertyWapMarqueeDir:
5441 HANDLE_INHERIT_AND_INITIAL(marqueeDirection, MarqueeDirection)
5442 if (primitiveValue && primitiveValue->getIdent()) {
5443 switch (primitiveValue->getIdent()) {
5444 case CSSValueLtr:
5445 m_style->setMarqueeDirection(MRIGHT);
5446 break;
5447 case CSSValueRtl:
5448 m_style->setMarqueeDirection(MLEFT);
5449 break;
5450 default:
5451 m_style->setMarqueeDirection(*primitiveValue);
5452 break;
5453 }
5454 }
5455 return;
5456 #endif
5457 case CSSPropertyWebkitMarqueeDirection:
5458 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(marqueeDirection, MarqueeDirection)
5459 return;
5460 case CSSPropertyWebkitUserDrag:
5461 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(userDrag, UserDrag)
5462 return;
5463 case CSSPropertyWebkitUserModify:
5464 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(userModify, UserModify)
5465 return;
5466 case CSSPropertyWebkitUserSelect:
5467 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(userSelect, UserSelect)
5468 return;
5469
5470 case CSSPropertyTextOverflow: {
5471 // This property is supported by WinIE, and so we leave off the "-webkit-" in order to
5472 // work with WinIE-specific pages that use the property.
5473 HANDLE_INHERIT_AND_INITIAL(textOverflow, TextOverflow)
5474 if (!primitiveValue || !primitiveValue->getIdent())
5475 return;
5476 m_style->setTextOverflow(primitiveValue->getIdent() == CSSValueEllipsis);
5477 return;
5478 }
5479 case CSSPropertyWebkitMarginCollapse: {
5480 if (isInherit) {
5481 m_style->setMarginBeforeCollapse(m_parentStyle->marginBeforeCollapse());
5482 m_style->setMarginAfterCollapse(m_parentStyle->marginAfterCollapse());
5483 }
5484 else if (isInitial) {
5485 m_style->setMarginBeforeCollapse(MCOLLAPSE);
5486 m_style->setMarginAfterCollapse(MCOLLAPSE);
5487 }
5488 return;
5489 }
5490
5491 case CSSPropertyWebkitMarginBeforeCollapse:
5492 case CSSPropertyWebkitMarginTopCollapse:
5493 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(marginBeforeCollapse, MarginBeforeCollapse)
5494 return;
5495 case CSSPropertyWebkitMarginAfterCollapse:
5496 case CSSPropertyWebkitMarginBottomCollapse:
5497 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(marginAfterCollapse, MarginAfterCollapse)
5498 return;
5499 case CSSPropertyWebkitLineClamp: {
5500 HANDLE_INHERIT_AND_INITIAL(lineClamp, LineClamp)
5501 if (!primitiveValue)
5502 return;
5503 int type = primitiveValue->primitiveType();
5504 if (type == CSSPrimitiveValue::CSS_NUMBER)
5505 m_style->setLineClamp(LineClampValue(primitiveValue->getIntValue(CSSPrimitiveValue::CSS_NUMBER), LineClampLineCount));
5506 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
5507 m_style->setLineClamp(LineClampValue(primitiveValue->getIntValue(CSSPrimitiveValue::CSS_PERCENTAGE), LineClampPercentage));
5508 return;
5509 }
5510 case CSSPropertyWebkitHighlight: {
5511 HANDLE_INHERIT_AND_INITIAL(highlight, Highlight);
5512 if (primitiveValue->getIdent() == CSSValueNone)
5513 m_style->setHighlight(nullAtom);
5514 else
5515 m_style->setHighlight(primitiveValue->getStringValue());
5516 return;
5517 }
5518 case CSSPropertyWebkitHyphens: {
5519 HANDLE_INHERIT_AND_INITIAL(hyphens, Hyphens);
5520 m_style->setHyphens(*primitiveValue);
5521 return;
5522 }
5523 case CSSPropertyWebkitHyphenateCharacter: {
5524 HANDLE_INHERIT_AND_INITIAL(hyphenationString, HyphenationString);
5525 if (primitiveValue->getIdent() == CSSValueAuto)
5526 m_style->setHyphenationString(nullAtom);
5527 else
5528 m_style->setHyphenationString(primitiveValue->getStringValue());
5529 return;
5530 }
5531 case CSSPropertyWebkitHyphenateLimitAfter: {
5532 HANDLE_INHERIT_AND_INITIAL(hyphenationLimitAfter, HyphenationLimitAfter);
5533 if (primitiveValue->getIdent() == CSSValueAuto)
5534 m_style->setHyphenationLimitAfter(-1);
5535 else
5536 m_style->setHyphenationLimitAfter(min(primitiveValue->getIntValue(CSSPrimitiveValue::CSS_NUMBER), static_cast<int>(numeric_limits<short>::max())));
5537 return;
5538 }
5539 case CSSPropertyWebkitHyphenateLimitBefore: {
5540 HANDLE_INHERIT_AND_INITIAL(hyphenationLimitBefore, HyphenationLimitBefore);
5541 if (primitiveValue->getIdent() == CSSValueAuto)
5542 m_style->setHyphenationLimitBefore(-1);
5543 else
5544 m_style->setHyphenationLimitBefore(min(primitiveValue->getIntValue(CSSPrimitiveValue::CSS_NUMBER), static_cast<int>(numeric_limits<short>::max())));
5545 return;
5546 }
5547 case CSSPropertyWebkitLocale: {
5548 HANDLE_INHERIT_AND_INITIAL(locale, Locale);
5549 if (primitiveValue->getIdent() == CSSValueAuto)
5550 m_style->setLocale(nullAtom);
5551 else
5552 m_style->setLocale(primitiveValue->getStringValue());
5553 return;
5554 }
5555 case CSSPropertyWebkitBorderFit: {
5556 HANDLE_INHERIT_AND_INITIAL(borderFit, BorderFit);
5557 if (primitiveValue->getIdent() == CSSValueBorder)
5558 m_style->setBorderFit(BorderFitBorder);
5559 else
5560 m_style->setBorderFit(BorderFitLines);
5561 return;
5562 }
5563 case CSSPropertyWebkitTextSizeAdjust: {
5564 HANDLE_INHERIT_AND_INITIAL(textSizeAdjust, TextSizeAdjust)
5565 if (!primitiveValue || !primitiveValue->getIdent()) return;
5566 m_style->setTextSizeAdjust(primitiveValue->getIdent() == CSSValueAuto);
5567 m_fontDirty = true;
5568 return;
5569 }
5570 case CSSPropertyWebkitTextSecurity:
5571 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(textSecurity, TextSecurity)
5572 return;
5573
5574 #if ENABLE(DASHBOARD_SUPPORT)
5575 case CSSPropertyWebkitDashboardRegion: {
5576 HANDLE_INHERIT_AND_INITIAL(dashboardRegions, DashboardRegions)
5577 if (!primitiveValue)
5578 return;
5579
5580 if (primitiveValue->getIdent() == CSSValueNone) {
5581 m_style->setDashboardRegions(RenderStyle::noneDashboardRegions());
5582 return;
5583 }
5584
5585 DashboardRegion *region = primitiveValue->getDashboardRegionValue();
5586 if (!region)
5587 return;
5588
5589 DashboardRegion *first = region;
5590 while (region) {
5591 Length top = convertToIntLength(region->top(), style(), m_rootElementStyle);
5592 Length right = convertToIntLength(region->right(), style(), m_rootElementStyle);
5593 Length bottom = convertToIntLength(region->bottom(), style(), m_rootElementStyle);
5594 Length left = convertToIntLength(region->left(), style(), m_rootElementStyle);
5595 if (region->m_isCircle)
5596 m_style->setDashboardRegion(StyleDashboardRegion::Circle, region->m_label, top, right, bottom, left, region == first ? false : true);
5597 else if (region->m_isRectangle)
5598 m_style->setDashboardRegion(StyleDashboardRegion::Rectangle, region->m_label, top, right, bottom, left, region == first ? false : true);
5599 region = region->m_next.get();
5600 }
5601
5602 m_element->document()->setHasDashboardRegions(true);
5603
5604 return;
5605 }
5606 #endif
5607 case CSSPropertyWebkitRtlOrdering:
5608 HANDLE_INHERIT_AND_INITIAL(visuallyOrdered, VisuallyOrdered)
5609 if (!primitiveValue || !primitiveValue->getIdent())
5610 return;
5611 m_style->setVisuallyOrdered(primitiveValue->getIdent() == CSSValueVisual);
5612 return;
5613 case CSSPropertyWebkitTextStrokeWidth: {
5614 HANDLE_INHERIT_AND_INITIAL(textStrokeWidth, TextStrokeWidth)
5615 float width = 0;
5616 switch (primitiveValue->getIdent()) {
5617 case CSSValueThin:
5618 case CSSValueMedium:
5619 case CSSValueThick: {
5620 double result = 1.0 / 48;
5621 if (primitiveValue->getIdent() == CSSValueMedium)
5622 result *= 3;
5623 else if (primitiveValue->getIdent() == CSSValueThick)
5624 result *= 5;
5625 width = CSSPrimitiveValue::create(result, CSSPrimitiveValue::CSS_EMS)->computeLengthFloat(style(), m_rootElementStyle, zoomFactor);
5626 break;
5627 }
5628 default:
5629 width = primitiveValue->computeLengthFloat(style(), m_rootElementStyle, zoomFactor);
5630 break;
5631 }
5632 m_style->setTextStrokeWidth(width);
5633 return;
5634 }
5635 case CSSPropertyWebkitTransform: {
5636 HANDLE_INHERIT_AND_INITIAL(transform, Transform);
5637 TransformOperations operations;
5638 createTransformOperations(value, style(), m_rootElementStyle, operations);
5639 m_style->setTransform(operations);
5640 return;
5641 }
5642 case CSSPropertyWebkitTransformOrigin:
5643 HANDLE_INHERIT_AND_INITIAL(transformOriginX, TransformOriginX)
5644 HANDLE_INHERIT_AND_INITIAL(transformOriginY, TransformOriginY)
5645 HANDLE_INHERIT_AND_INITIAL(transformOriginZ, TransformOriginZ)
5646 return;
5647 case CSSPropertyWebkitTransformOriginX: {
5648 HANDLE_INHERIT_AND_INITIAL(transformOriginX, TransformOriginX)
5649 if (!primitiveValue)
5650 return;
5651 Length l;
5652 int type = primitiveValue->primitiveType();
5653 if (CSSPrimitiveValue::isUnitTypeLength(type))
5654 l = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed);
5655 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
5656 l = Length(primitiveValue->getDoubleValue(), Percent);
5657 else
5658 return;
5659 m_style->setTransformOriginX(l);
5660 break;
5661 }
5662 case CSSPropertyWebkitTransformOriginY: {
5663 HANDLE_INHERIT_AND_INITIAL(transformOriginY, TransformOriginY)
5664 if (!primitiveValue)
5665 return;
5666 Length l;
5667 int type = primitiveValue->primitiveType();
5668 if (CSSPrimitiveValue::isUnitTypeLength(type))
5669 l = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed);
5670 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
5671 l = Length(primitiveValue->getDoubleValue(), Percent);
5672 else
5673 return;
5674 m_style->setTransformOriginY(l);
5675 break;
5676 }
5677 case CSSPropertyWebkitTransformOriginZ: {
5678 HANDLE_INHERIT_AND_INITIAL(transformOriginZ, TransformOriginZ)
5679 if (!primitiveValue)
5680 return;
5681 float f;
5682 int type = primitiveValue->primitiveType();
5683 if (CSSPrimitiveValue::isUnitTypeLength(type))
5684 f = static_cast<float>(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle));
5685 else
5686 return;
5687 m_style->setTransformOriginZ(f);
5688 break;
5689 }
5690 case CSSPropertyWebkitTransformStyle:
5691 HANDLE_INHERIT_AND_INITIAL(transformStyle3D, TransformStyle3D)
5692 if (primitiveValue)
5693 m_style->setTransformStyle3D((primitiveValue->getIdent() == CSSValuePreserve3d) ? TransformStyle3DPreserve3D : TransformStyle3DFlat);
5694 return;
5695 case CSSPropertyWebkitPerspective: {
5696 HANDLE_INHERIT_AND_INITIAL(perspective, Perspective)
5697 if (primitiveValue && primitiveValue->getIdent() == CSSValueNone) {
5698 m_style->setPerspective(0);
5699 return;
5700 }
5701
5702 float perspectiveValue;
5703 int type = primitiveValue->primitiveType();
5704 if (CSSPrimitiveValue::isUnitTypeLength(type))
5705 perspectiveValue = static_cast<float>(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor));
5706 else if (type == CSSPrimitiveValue::CSS_NUMBER) {
5707 // For backward compatibility, treat valueless numbers as px.
5708 perspectiveValue = CSSPrimitiveValue::create(primitiveValue->getDoubleValue(), CSSPrimitiveValue::CSS_PX)->computeLengthFloat(style(), m_rootElementStyle, zoomFactor);
5709 } else
5710 return;
5711
5712 if (perspectiveValue >= 0.0f)
5713 m_style->setPerspective(perspectiveValue);
5714 return;
5715 }
5716 case CSSPropertyWebkitPerspectiveOrigin:
5717 HANDLE_INHERIT_AND_INITIAL(perspectiveOriginX, PerspectiveOriginX)
5718 HANDLE_INHERIT_AND_INITIAL(perspectiveOriginY, PerspectiveOriginY)
5719 return;
5720 case CSSPropertyWebkitPerspectiveOriginX: {
5721 HANDLE_INHERIT_AND_INITIAL(perspectiveOriginX, PerspectiveOriginX)
5722 if (!primitiveValue)
5723 return;
5724 Length l;
5725 int type = primitiveValue->primitiveType();
5726 if (CSSPrimitiveValue::isUnitTypeLength(type))
5727 l = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed);
5728 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
5729 l = Length(primitiveValue->getDoubleValue(), Percent);
5730 else
5731 return;
5732 m_style->setPerspectiveOriginX(l);
5733 return;
5734 }
5735 case CSSPropertyWebkitPerspectiveOriginY: {
5736 HANDLE_INHERIT_AND_INITIAL(perspectiveOriginY, PerspectiveOriginY)
5737 if (!primitiveValue)
5738 return;
5739 Length l;
5740 int type = primitiveValue->primitiveType();
5741 if (CSSPrimitiveValue::isUnitTypeLength(type))
5742 l = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed);
5743 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
5744 l = Length(primitiveValue->getDoubleValue(), Percent);
5745 else
5746 return;
5747 m_style->setPerspectiveOriginY(l);
5748 return;
5749 }
5750 case CSSPropertyWebkitAnimation:
5751 if (isInitial)
5752 m_style->clearAnimations();
5753 else if (isInherit)
5754 m_style->inheritAnimations(m_parentStyle->animations());
5755 return;
5756 case CSSPropertyWebkitAnimationDelay:
5757 HANDLE_ANIMATION_VALUE(delay, Delay, value)
5758 return;
5759 case CSSPropertyWebkitAnimationDirection:
5760 HANDLE_ANIMATION_VALUE(direction, Direction, value)
5761 return;
5762 case CSSPropertyWebkitAnimationDuration:
5763 HANDLE_ANIMATION_VALUE(duration, Duration, value)
5764 return;
5765 case CSSPropertyWebkitAnimationFillMode:
5766 HANDLE_ANIMATION_VALUE(fillMode, FillMode, value)
5767 return;
5768 case CSSPropertyWebkitAnimationIterationCount:
5769 HANDLE_ANIMATION_VALUE(iterationCount, IterationCount, value)
5770 return;
5771 case CSSPropertyWebkitAnimationName:
5772 HANDLE_ANIMATION_VALUE(name, Name, value)
5773 return;
5774 case CSSPropertyWebkitAnimationPlayState:
5775 HANDLE_ANIMATION_VALUE(playState, PlayState, value)
5776 return;
5777 case CSSPropertyWebkitAnimationTimingFunction:
5778 HANDLE_ANIMATION_VALUE(timingFunction, TimingFunction, value)
5779 return;
5780 case CSSPropertyWebkitTransition:
5781 if (isInitial)
5782 m_style->clearTransitions();
5783 else if (isInherit)
5784 m_style->inheritTransitions(m_parentStyle->transitions());
5785 return;
5786 case CSSPropertyWebkitTransitionDelay:
5787 HANDLE_TRANSITION_VALUE(delay, Delay, value)
5788 return;
5789 case CSSPropertyWebkitTransitionDuration:
5790 HANDLE_TRANSITION_VALUE(duration, Duration, value)
5791 return;
5792 case CSSPropertyWebkitTransitionProperty:
5793 HANDLE_TRANSITION_VALUE(property, Property, value)
5794 return;
5795 case CSSPropertyWebkitTransitionTimingFunction:
5796 HANDLE_TRANSITION_VALUE(timingFunction, TimingFunction, value)
5797 return;
5798 case CSSPropertyPointerEvents:
5799 {
5800 #if ENABLE(DASHBOARD_SUPPORT)
5801 // <rdar://problem/6561077> Work around the Stocks widget's misuse of the
5802 // pointer-events property by not applying it in Dashboard.
5803 Settings* settings = m_checker.m_document->settings();
5804 if (settings && settings->usesDashboardBackwardCompatibilityMode())
5805 return;
5806 #endif
5807 HANDLE_INHERIT_AND_INITIAL(pointerEvents, PointerEvents)
5808 if (!primitiveValue)
5809 return;
5810 m_style->setPointerEvents(*primitiveValue);
5811 return;
5812 }
5813 case CSSPropertyWebkitColorCorrection:
5814 if (isInherit)
5815 m_style->setColorSpace(m_parentStyle->colorSpace());
5816 else if (isInitial)
5817 m_style->setColorSpace(ColorSpaceDeviceRGB);
5818 else {
5819 if (!primitiveValue)
5820 return;
5821 m_style->setColorSpace(*primitiveValue);
5822 }
5823 return;
5824 case CSSPropertySize:
5825 applyPageSizeProperty(value);
5826 return;
5827
5828 case CSSPropertySpeak:
5829 HANDLE_INHERIT_AND_INITIAL(speak, Speak);
5830 if (!primitiveValue)
5831 return;
5832 m_style->setSpeak(*primitiveValue);
5833 return;
5834
5835 case CSSPropertyInvalid:
5836 return;
5837
5838 // Directional properties are resolved by resolveDirectionAwareProperty() before the switch.
5839 case CSSPropertyWebkitBorderEnd:
5840 case CSSPropertyWebkitBorderEndColor:
5841 case CSSPropertyWebkitBorderEndStyle:
5842 case CSSPropertyWebkitBorderEndWidth:
5843 case CSSPropertyWebkitBorderStart:
5844 case CSSPropertyWebkitBorderStartColor:
5845 case CSSPropertyWebkitBorderStartStyle:
5846 case CSSPropertyWebkitBorderStartWidth:
5847 case CSSPropertyWebkitBorderBefore:
5848 case CSSPropertyWebkitBorderBeforeColor:
5849 case CSSPropertyWebkitBorderBeforeStyle:
5850 case CSSPropertyWebkitBorderBeforeWidth:
5851 case CSSPropertyWebkitBorderAfter:
5852 case CSSPropertyWebkitBorderAfterColor:
5853 case CSSPropertyWebkitBorderAfterStyle:
5854 case CSSPropertyWebkitBorderAfterWidth:
5855 case CSSPropertyWebkitMarginEnd:
5856 case CSSPropertyWebkitMarginStart:
5857 case CSSPropertyWebkitMarginBefore:
5858 case CSSPropertyWebkitMarginAfter:
5859 case CSSPropertyWebkitPaddingEnd:
5860 case CSSPropertyWebkitPaddingStart:
5861 case CSSPropertyWebkitPaddingBefore:
5862 case CSSPropertyWebkitPaddingAfter:
5863 case CSSPropertyWebkitLogicalWidth:
5864 case CSSPropertyWebkitLogicalHeight:
5865 case CSSPropertyWebkitMinLogicalWidth:
5866 case CSSPropertyWebkitMinLogicalHeight:
5867 case CSSPropertyWebkitMaxLogicalWidth:
5868 case CSSPropertyWebkitMaxLogicalHeight:
5869 ASSERT_NOT_REACHED();
5870 break;
5871
5872 case CSSPropertyFontStretch:
5873 case CSSPropertyPage:
5874 case CSSPropertyTextLineThrough:
5875 case CSSPropertyTextLineThroughColor:
5876 case CSSPropertyTextLineThroughMode:
5877 case CSSPropertyTextLineThroughStyle:
5878 case CSSPropertyTextLineThroughWidth:
5879 case CSSPropertyTextOverline:
5880 case CSSPropertyTextOverlineColor:
5881 case CSSPropertyTextOverlineMode:
5882 case CSSPropertyTextOverlineStyle:
5883 case CSSPropertyTextOverlineWidth:
5884 case CSSPropertyTextUnderline:
5885 case CSSPropertyTextUnderlineColor:
5886 case CSSPropertyTextUnderlineMode:
5887 case CSSPropertyTextUnderlineStyle:
5888 case CSSPropertyTextUnderlineWidth:
5889 case CSSPropertyWebkitFontSizeDelta:
5890 case CSSPropertyWebkitTextDecorationsInEffect:
5891 case CSSPropertyWebkitTextStroke:
5892 case CSSPropertyWebkitTextEmphasis:
5893 return;
5894 #if ENABLE(WCSS)
5895 case CSSPropertyWapInputFormat:
5896 if (primitiveValue && m_element->hasTagName(WebCore::inputTag)) {
5897 String mask = primitiveValue->getStringValue();
5898 static_cast<HTMLInputElement*>(m_element)->setWapInputFormat(mask);
5899 }
5900 return;
5901
5902 case CSSPropertyWapInputRequired:
5903 if (primitiveValue && m_element->isFormControlElement()) {
5904 HTMLFormControlElement* element = static_cast<HTMLFormControlElement*>(m_element);
5905 bool required = primitiveValue->getStringValue() == "true";
5906 element->setRequired(required);
5907 }
5908 return;
5909 #endif
5910
5911 // CSS Text Layout Module Level 3: Vertical writing support
5912 case CSSPropertyWebkitWritingMode: {
5913 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(writingMode, WritingMode)
5914 if (!isInherit && !isInitial && m_element && m_element == m_element->document()->documentElement())
5915 m_element->document()->setWritingModeSetOnDocumentElement(true);
5916 FontDescription fontDescription = m_style->fontDescription();
5917 fontDescription.setOrientation(m_style->isHorizontalWritingMode() ? Horizontal : Vertical);
5918 if (m_style->setFontDescription(fontDescription))
5919 m_fontDirty = true;
5920 return;
5921 }
5922
5923 case CSSPropertyWebkitTextCombine:
5924 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(textCombine, TextCombine)
5925 return;
5926
5927 case CSSPropertyWebkitTextEmphasisPosition:
5928 HANDLE_INHERIT_AND_INITIAL_AND_PRIMITIVE(textEmphasisPosition, TextEmphasisPosition)
5929 return;
5930
5931 case CSSPropertyWebkitTextEmphasisStyle:
5932 HANDLE_INHERIT_AND_INITIAL(textEmphasisFill, TextEmphasisFill)
5933 HANDLE_INHERIT_AND_INITIAL(textEmphasisMark, TextEmphasisMark)
5934 HANDLE_INHERIT_AND_INITIAL(textEmphasisCustomMark, TextEmphasisCustomMark)
5935 if (isInherit || isInitial)
5936 return;
5937
5938 if (value->isValueList()) {
5939 CSSValueList* list = static_cast<CSSValueList*>(value);
5940 ASSERT(list->length() == 2);
5941 if (list->length() != 2)
5942 return;
5943 for (unsigned i = 0; i < 2; ++i) {
5944 CSSValue* item = list->itemWithoutBoundsCheck(i);
5945 if (!item->isPrimitiveValue())
5946 continue;
5947
5948 CSSPrimitiveValue* value = static_cast<CSSPrimitiveValue*>(item);
5949 if (value->getIdent() == CSSValueFilled || value->getIdent() == CSSValueOpen)
5950 m_style->setTextEmphasisFill(*value);
5951 else
5952 m_style->setTextEmphasisMark(*value);
5953 }
5954 m_style->setTextEmphasisCustomMark(nullAtom);
5955 return;
5956 }
5957
5958 if (!primitiveValue)
5959 return;
5960
5961 if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_STRING) {
5962 m_style->setTextEmphasisFill(TextEmphasisFillFilled);
5963 m_style->setTextEmphasisMark(TextEmphasisMarkCustom);
5964 m_style->setTextEmphasisCustomMark(primitiveValue->getStringValue());
5965 return;
5966 }
5967
5968 m_style->setTextEmphasisCustomMark(nullAtom);
5969
5970 if (primitiveValue->getIdent() == CSSValueFilled || primitiveValue->getIdent() == CSSValueOpen) {
5971 m_style->setTextEmphasisFill(*primitiveValue);
5972 m_style->setTextEmphasisMark(TextEmphasisMarkAuto);
5973 } else {
5974 m_style->setTextEmphasisFill(TextEmphasisFillFilled);
5975 m_style->setTextEmphasisMark(*primitiveValue);
5976 }
5977
5978 return;
5979
5980 case CSSPropertyWebkitTextOrientation: {
5981 if (!isInherit && !isInitial && !primitiveValue)
5982 return;
5983
5984 TextOrientation result;
5985 if (isInherit)
5986 result = m_parentStyle->fontDescription().textOrientation();
5987 else if (isInitial)
5988 result = RenderStyle::initialTextOrientation();
5989 else
5990 result = *primitiveValue;
5991
5992 FontDescription fontDescription = m_style->fontDescription();
5993 if (fontDescription.textOrientation() != result) {
5994 fontDescription.setTextOrientation(result);
5995 if (m_style->setFontDescription(fontDescription))
5996 m_fontDirty = true;
5997 }
5998 return;
5999 }
6000
6001 case CSSPropertyWebkitLineBoxContain: {
6002 HANDLE_INHERIT_AND_INITIAL(lineBoxContain, LineBoxContain)
6003 if (primitiveValue && primitiveValue->getIdent() == CSSValueNone) {
6004 m_style->setLineBoxContain(LineBoxContainNone);
6005 return;
6006 }
6007
6008 if (!value->isCSSLineBoxContainValue())
6009 return;
6010
6011 CSSLineBoxContainValue* lineBoxContainValue = static_cast<CSSLineBoxContainValue*>(value);
6012 m_style->setLineBoxContain(lineBoxContainValue->value());
6013 return;
6014 }
6015
6016 // These properties are implemented in the CSSStyleApplyProperty lookup table.
6017 case CSSPropertyColor:
6018 case CSSPropertyDirection:
6019 case CSSPropertyBackgroundAttachment:
6020 case CSSPropertyBackgroundClip:
6021 case CSSPropertyWebkitBackgroundClip:
6022 case CSSPropertyWebkitBackgroundComposite:
6023 case CSSPropertyBackgroundOrigin:
6024 case CSSPropertyWebkitBackgroundOrigin:
6025 case CSSPropertyBackgroundImage:
6026 case CSSPropertyBackgroundSize:
6027 case CSSPropertyWebkitBackgroundSize:
6028 case CSSPropertyWebkitMaskAttachment:
6029 case CSSPropertyWebkitMaskClip:
6030 case CSSPropertyWebkitMaskComposite:
6031 case CSSPropertyWebkitMaskOrigin:
6032 case CSSPropertyWebkitMaskImage:
6033 case CSSPropertyWebkitMaskSize:
6034 case CSSPropertyBackgroundColor:
6035 case CSSPropertyBorderBottomColor:
6036 case CSSPropertyBorderLeftColor:
6037 case CSSPropertyBorderRightColor:
6038 case CSSPropertyBorderTopColor:
6039 case CSSPropertyBorderTopStyle:
6040 case CSSPropertyBorderRightStyle:
6041 case CSSPropertyBorderBottomStyle:
6042 case CSSPropertyBorderLeftStyle:
6043 case CSSPropertyOutlineColor:
6044 case CSSPropertyWebkitColumnRuleColor:
6045 case CSSPropertyWebkitTextEmphasisColor:
6046 case CSSPropertyWebkitTextFillColor:
6047 case CSSPropertyWebkitTextStrokeColor:
6048 case CSSPropertyBackgroundPosition:
6049 case CSSPropertyBackgroundPositionX:
6050 case CSSPropertyBackgroundPositionY:
6051 case CSSPropertyWebkitMaskPosition:
6052 case CSSPropertyWebkitMaskPositionX:
6053 case CSSPropertyWebkitMaskPositionY:
6054 case CSSPropertyBackgroundRepeat:
6055 case CSSPropertyBackgroundRepeatX:
6056 case CSSPropertyBackgroundRepeatY:
6057 case CSSPropertyWebkitMaskRepeat:
6058 case CSSPropertyWebkitMaskRepeatX:
6059 case CSSPropertyWebkitMaskRepeatY:
6060 case CSSPropertyOverflow:
6061 case CSSPropertyOverflowX:
6062 case CSSPropertyOverflowY:
6063 ASSERT_NOT_REACHED();
6064 return;
6065
6066 #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR
6067 case CSSPropertyWebkitTapHighlightColor: {
6068 HANDLE_INHERIT_AND_INITIAL(tapHighlightColor, TapHighlightColor);
6069 if (!primitiveValue)
6070 break;
6071
6072 Color col = getColorFromPrimitiveValue(primitiveValue).blendWithWhite();
6073 m_style->setTapHighlightColor(col);
6074 return;
6075 }
6076 #endif
6077
6078 #if ENABLE(SVG)
6079 default:
6080 // Try the SVG properties
6081 applySVGProperty(id, value);
6082 return;
6083 #endif
6084 }
6085 }
6086
applyPageSizeProperty(CSSValue * value)6087 void CSSStyleSelector::applyPageSizeProperty(CSSValue* value)
6088 {
6089 m_style->resetPageSizeType();
6090 if (!value->isValueList())
6091 return;
6092 CSSValueList* valueList = static_cast<CSSValueList*>(value);
6093 Length width;
6094 Length height;
6095 PageSizeType pageSizeType = PAGE_SIZE_AUTO;
6096 switch (valueList->length()) {
6097 case 2: {
6098 // <length>{2} | <page-size> <orientation>
6099 pageSizeType = PAGE_SIZE_RESOLVED;
6100 if (!valueList->item(0)->isPrimitiveValue() || !valueList->item(1)->isPrimitiveValue())
6101 return;
6102 CSSPrimitiveValue* primitiveValue0 = static_cast<CSSPrimitiveValue*>(valueList->item(0));
6103 CSSPrimitiveValue* primitiveValue1 = static_cast<CSSPrimitiveValue*>(valueList->item(1));
6104 int type0 = primitiveValue0->primitiveType();
6105 int type1 = primitiveValue1->primitiveType();
6106 if (CSSPrimitiveValue::isUnitTypeLength(type0)) {
6107 // <length>{2}
6108 if (!CSSPrimitiveValue::isUnitTypeLength(type1))
6109 return;
6110 width = Length(primitiveValue0->computeLengthIntForLength(style(), m_rootElementStyle), Fixed);
6111 height = Length(primitiveValue1->computeLengthIntForLength(style(), m_rootElementStyle), Fixed);
6112 } else {
6113 // <page-size> <orientation>
6114 // The value order is guaranteed. See CSSParser::parseSizeParameter.
6115 if (!pageSizeFromName(primitiveValue0, primitiveValue1, width, height))
6116 return;
6117 }
6118 break;
6119 }
6120 case 1: {
6121 // <length> | auto | <page-size> | [ portrait | landscape]
6122 if (!valueList->item(0)->isPrimitiveValue())
6123 return;
6124 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(valueList->item(0));
6125 int type = primitiveValue->primitiveType();
6126 if (CSSPrimitiveValue::isUnitTypeLength(type)) {
6127 // <length>
6128 pageSizeType = PAGE_SIZE_RESOLVED;
6129 width = height = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle), Fixed);
6130 } else {
6131 if (type != CSSPrimitiveValue::CSS_IDENT)
6132 return;
6133 switch (primitiveValue->getIdent()) {
6134 case CSSValueAuto:
6135 pageSizeType = PAGE_SIZE_AUTO;
6136 break;
6137 case CSSValuePortrait:
6138 pageSizeType = PAGE_SIZE_AUTO_PORTRAIT;
6139 break;
6140 case CSSValueLandscape:
6141 pageSizeType = PAGE_SIZE_AUTO_LANDSCAPE;
6142 break;
6143 default:
6144 // <page-size>
6145 pageSizeType = PAGE_SIZE_RESOLVED;
6146 if (!pageSizeFromName(primitiveValue, 0, width, height))
6147 return;
6148 }
6149 }
6150 break;
6151 }
6152 default:
6153 return;
6154 }
6155 m_style->setPageSizeType(pageSizeType);
6156 m_style->setPageSize(LengthSize(width, height));
6157 return;
6158 }
6159
pageSizeFromName(CSSPrimitiveValue * pageSizeName,CSSPrimitiveValue * pageOrientation,Length & width,Length & height)6160 bool CSSStyleSelector::pageSizeFromName(CSSPrimitiveValue* pageSizeName, CSSPrimitiveValue* pageOrientation, Length& width, Length& height)
6161 {
6162 static const Length a5Width = mmLength(148), a5Height = mmLength(210);
6163 static const Length a4Width = mmLength(210), a4Height = mmLength(297);
6164 static const Length a3Width = mmLength(297), a3Height = mmLength(420);
6165 static const Length b5Width = mmLength(176), b5Height = mmLength(250);
6166 static const Length b4Width = mmLength(250), b4Height = mmLength(353);
6167 static const Length letterWidth = inchLength(8.5), letterHeight = inchLength(11);
6168 static const Length legalWidth = inchLength(8.5), legalHeight = inchLength(14);
6169 static const Length ledgerWidth = inchLength(11), ledgerHeight = inchLength(17);
6170
6171 if (!pageSizeName || pageSizeName->primitiveType() != CSSPrimitiveValue::CSS_IDENT)
6172 return false;
6173
6174 switch (pageSizeName->getIdent()) {
6175 case CSSValueA5:
6176 width = a5Width;
6177 height = a5Height;
6178 break;
6179 case CSSValueA4:
6180 width = a4Width;
6181 height = a4Height;
6182 break;
6183 case CSSValueA3:
6184 width = a3Width;
6185 height = a3Height;
6186 break;
6187 case CSSValueB5:
6188 width = b5Width;
6189 height = b5Height;
6190 break;
6191 case CSSValueB4:
6192 width = b4Width;
6193 height = b4Height;
6194 break;
6195 case CSSValueLetter:
6196 width = letterWidth;
6197 height = letterHeight;
6198 break;
6199 case CSSValueLegal:
6200 width = legalWidth;
6201 height = legalHeight;
6202 break;
6203 case CSSValueLedger:
6204 width = ledgerWidth;
6205 height = ledgerHeight;
6206 break;
6207 default:
6208 return false;
6209 }
6210
6211 if (pageOrientation) {
6212 if (pageOrientation->primitiveType() != CSSPrimitiveValue::CSS_IDENT)
6213 return false;
6214 switch (pageOrientation->getIdent()) {
6215 case CSSValueLandscape:
6216 std::swap(width, height);
6217 break;
6218 case CSSValuePortrait:
6219 // Nothing to do.
6220 break;
6221 default:
6222 return false;
6223 }
6224 }
6225 return true;
6226 }
6227
mmLength(double mm) const6228 Length CSSStyleSelector::mmLength(double mm) const
6229 {
6230 return Length(CSSPrimitiveValue::create(mm, CSSPrimitiveValue::CSS_MM)->computeLengthIntForLength(style(), m_rootElementStyle), Fixed);
6231 }
6232
inchLength(double inch) const6233 Length CSSStyleSelector::inchLength(double inch) const
6234 {
6235 return Length(CSSPrimitiveValue::create(inch, CSSPrimitiveValue::CSS_IN)->computeLengthIntForLength(style(), m_rootElementStyle), Fixed);
6236 }
6237
mapFillAttachment(CSSPropertyID,FillLayer * layer,CSSValue * value)6238 void CSSStyleSelector::mapFillAttachment(CSSPropertyID, FillLayer* layer, CSSValue* value)
6239 {
6240 if (value->cssValueType() == CSSValue::CSS_INITIAL) {
6241 layer->setAttachment(FillLayer::initialFillAttachment(layer->type()));
6242 return;
6243 }
6244
6245 if (!value->isPrimitiveValue())
6246 return;
6247
6248 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
6249 switch (primitiveValue->getIdent()) {
6250 case CSSValueFixed:
6251 layer->setAttachment(FixedBackgroundAttachment);
6252 break;
6253 case CSSValueScroll:
6254 layer->setAttachment(ScrollBackgroundAttachment);
6255 break;
6256 case CSSValueLocal:
6257 layer->setAttachment(LocalBackgroundAttachment);
6258 break;
6259 default:
6260 return;
6261 }
6262 }
6263
mapFillClip(CSSPropertyID,FillLayer * layer,CSSValue * value)6264 void CSSStyleSelector::mapFillClip(CSSPropertyID, FillLayer* layer, CSSValue* value)
6265 {
6266 if (value->cssValueType() == CSSValue::CSS_INITIAL) {
6267 layer->setClip(FillLayer::initialFillClip(layer->type()));
6268 return;
6269 }
6270
6271 if (!value->isPrimitiveValue())
6272 return;
6273
6274 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
6275 layer->setClip(*primitiveValue);
6276 }
6277
mapFillComposite(CSSPropertyID,FillLayer * layer,CSSValue * value)6278 void CSSStyleSelector::mapFillComposite(CSSPropertyID, FillLayer* layer, CSSValue* value)
6279 {
6280 if (value->cssValueType() == CSSValue::CSS_INITIAL) {
6281 layer->setComposite(FillLayer::initialFillComposite(layer->type()));
6282 return;
6283 }
6284
6285 if (!value->isPrimitiveValue())
6286 return;
6287
6288 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
6289 layer->setComposite(*primitiveValue);
6290 }
6291
mapFillOrigin(CSSPropertyID,FillLayer * layer,CSSValue * value)6292 void CSSStyleSelector::mapFillOrigin(CSSPropertyID, FillLayer* layer, CSSValue* value)
6293 {
6294 if (value->cssValueType() == CSSValue::CSS_INITIAL) {
6295 layer->setOrigin(FillLayer::initialFillOrigin(layer->type()));
6296 return;
6297 }
6298
6299 if (!value->isPrimitiveValue())
6300 return;
6301
6302 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
6303 layer->setOrigin(*primitiveValue);
6304 }
6305
styleImage(CSSPropertyID property,CSSValue * value)6306 StyleImage* CSSStyleSelector::styleImage(CSSPropertyID property, CSSValue* value)
6307 {
6308 if (value->isImageValue())
6309 return cachedOrPendingFromValue(property, static_cast<CSSImageValue*>(value));
6310
6311 if (value->isImageGeneratorValue())
6312 return static_cast<CSSImageGeneratorValue*>(value)->generatedImage();
6313
6314 return 0;
6315 }
6316
cachedOrPendingFromValue(CSSPropertyID property,CSSImageValue * value)6317 StyleImage* CSSStyleSelector::cachedOrPendingFromValue(CSSPropertyID property, CSSImageValue* value)
6318 {
6319 StyleImage* image = value->cachedOrPendingImage();
6320 if (image && image->isPendingImage())
6321 m_pendingImageProperties.add(property);
6322 return image;
6323 }
6324
mapFillImage(CSSPropertyID property,FillLayer * layer,CSSValue * value)6325 void CSSStyleSelector::mapFillImage(CSSPropertyID property, FillLayer* layer, CSSValue* value)
6326 {
6327 if (value->cssValueType() == CSSValue::CSS_INITIAL) {
6328 layer->setImage(FillLayer::initialFillImage(layer->type()));
6329 return;
6330 }
6331
6332 layer->setImage(styleImage(property, value));
6333 }
6334
mapFillRepeatX(CSSPropertyID,FillLayer * layer,CSSValue * value)6335 void CSSStyleSelector::mapFillRepeatX(CSSPropertyID, FillLayer* layer, CSSValue* value)
6336 {
6337 if (value->cssValueType() == CSSValue::CSS_INITIAL) {
6338 layer->setRepeatX(FillLayer::initialFillRepeatX(layer->type()));
6339 return;
6340 }
6341
6342 if (!value->isPrimitiveValue())
6343 return;
6344
6345 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
6346 layer->setRepeatX(*primitiveValue);
6347 }
6348
mapFillRepeatY(CSSPropertyID,FillLayer * layer,CSSValue * value)6349 void CSSStyleSelector::mapFillRepeatY(CSSPropertyID, FillLayer* layer, CSSValue* value)
6350 {
6351 if (value->cssValueType() == CSSValue::CSS_INITIAL) {
6352 layer->setRepeatY(FillLayer::initialFillRepeatY(layer->type()));
6353 return;
6354 }
6355
6356 if (!value->isPrimitiveValue())
6357 return;
6358
6359 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
6360 layer->setRepeatY(*primitiveValue);
6361 }
6362
mapFillSize(CSSPropertyID,FillLayer * layer,CSSValue * value)6363 void CSSStyleSelector::mapFillSize(CSSPropertyID, FillLayer* layer, CSSValue* value)
6364 {
6365 if (!value->isPrimitiveValue()) {
6366 layer->setSizeType(SizeNone);
6367 return;
6368 }
6369
6370 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
6371 if (primitiveValue->getIdent() == CSSValueContain)
6372 layer->setSizeType(Contain);
6373 else if (primitiveValue->getIdent() == CSSValueCover)
6374 layer->setSizeType(Cover);
6375 else
6376 layer->setSizeType(SizeLength);
6377
6378 LengthSize b = FillLayer::initialFillSizeLength(layer->type());
6379
6380 if (value->cssValueType() == CSSValue::CSS_INITIAL || primitiveValue->getIdent() == CSSValueContain
6381 || primitiveValue->getIdent() == CSSValueCover) {
6382 layer->setSizeLength(b);
6383 return;
6384 }
6385
6386 Pair* pair = primitiveValue->getPairValue();
6387 if (!pair || !pair->first() || !pair->second())
6388 return;
6389
6390 CSSPrimitiveValue* first = static_cast<CSSPrimitiveValue*>(pair->first());
6391 CSSPrimitiveValue* second = static_cast<CSSPrimitiveValue*>(pair->second());
6392
6393 Length firstLength, secondLength;
6394 int firstType = first->primitiveType();
6395 int secondType = second->primitiveType();
6396
6397 float zoomFactor = m_style->effectiveZoom();
6398
6399 if (firstType == CSSPrimitiveValue::CSS_UNKNOWN)
6400 firstLength = Length(Auto);
6401 else if (CSSPrimitiveValue::isUnitTypeLength(firstType))
6402 firstLength = Length(first->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed);
6403 else if (firstType == CSSPrimitiveValue::CSS_PERCENTAGE)
6404 firstLength = Length(first->getDoubleValue(), Percent);
6405 else
6406 return;
6407
6408 if (secondType == CSSPrimitiveValue::CSS_UNKNOWN)
6409 secondLength = Length(Auto);
6410 else if (CSSPrimitiveValue::isUnitTypeLength(secondType))
6411 secondLength = Length(second->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed);
6412 else if (secondType == CSSPrimitiveValue::CSS_PERCENTAGE)
6413 secondLength = Length(second->getDoubleValue(), Percent);
6414 else
6415 return;
6416
6417 b.setWidth(firstLength);
6418 b.setHeight(secondLength);
6419 layer->setSizeLength(b);
6420 }
6421
mapFillXPosition(CSSPropertyID,FillLayer * layer,CSSValue * value)6422 void CSSStyleSelector::mapFillXPosition(CSSPropertyID, FillLayer* layer, CSSValue* value)
6423 {
6424 if (value->cssValueType() == CSSValue::CSS_INITIAL) {
6425 layer->setXPosition(FillLayer::initialFillXPosition(layer->type()));
6426 return;
6427 }
6428
6429 if (!value->isPrimitiveValue())
6430 return;
6431
6432 float zoomFactor = m_style->effectiveZoom();
6433
6434 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
6435 Length l;
6436 int type = primitiveValue->primitiveType();
6437 if (CSSPrimitiveValue::isUnitTypeLength(type))
6438 l = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed);
6439 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
6440 l = Length(primitiveValue->getDoubleValue(), Percent);
6441 else
6442 return;
6443 layer->setXPosition(l);
6444 }
6445
mapFillYPosition(CSSPropertyID,FillLayer * layer,CSSValue * value)6446 void CSSStyleSelector::mapFillYPosition(CSSPropertyID, FillLayer* layer, CSSValue* value)
6447 {
6448 if (value->cssValueType() == CSSValue::CSS_INITIAL) {
6449 layer->setYPosition(FillLayer::initialFillYPosition(layer->type()));
6450 return;
6451 }
6452
6453 if (!value->isPrimitiveValue())
6454 return;
6455
6456 float zoomFactor = m_style->effectiveZoom();
6457
6458 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
6459 Length l;
6460 int type = primitiveValue->primitiveType();
6461 if (CSSPrimitiveValue::isUnitTypeLength(type))
6462 l = Length(primitiveValue->computeLengthIntForLength(style(), m_rootElementStyle, zoomFactor), Fixed);
6463 else if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
6464 l = Length(primitiveValue->getDoubleValue(), Percent);
6465 else
6466 return;
6467 layer->setYPosition(l);
6468 }
6469
mapAnimationDelay(Animation * animation,CSSValue * value)6470 void CSSStyleSelector::mapAnimationDelay(Animation* animation, CSSValue* value)
6471 {
6472 if (value->cssValueType() == CSSValue::CSS_INITIAL) {
6473 animation->setDelay(Animation::initialAnimationDelay());
6474 return;
6475 }
6476
6477 if (!value->isPrimitiveValue())
6478 return;
6479
6480 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
6481 if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_S)
6482 animation->setDelay(primitiveValue->getFloatValue());
6483 else
6484 animation->setDelay(primitiveValue->getFloatValue()/1000.0f);
6485 }
6486
mapAnimationDirection(Animation * layer,CSSValue * value)6487 void CSSStyleSelector::mapAnimationDirection(Animation* layer, CSSValue* value)
6488 {
6489 if (value->cssValueType() == CSSValue::CSS_INITIAL) {
6490 layer->setDirection(Animation::initialAnimationDirection());
6491 return;
6492 }
6493
6494 if (!value->isPrimitiveValue())
6495 return;
6496
6497 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
6498 layer->setDirection(primitiveValue->getIdent() == CSSValueAlternate ? Animation::AnimationDirectionAlternate : Animation::AnimationDirectionNormal);
6499 }
6500
mapAnimationDuration(Animation * animation,CSSValue * value)6501 void CSSStyleSelector::mapAnimationDuration(Animation* animation, CSSValue* value)
6502 {
6503 if (value->cssValueType() == CSSValue::CSS_INITIAL) {
6504 animation->setDuration(Animation::initialAnimationDuration());
6505 return;
6506 }
6507
6508 if (!value->isPrimitiveValue())
6509 return;
6510
6511 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
6512 if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_S)
6513 animation->setDuration(primitiveValue->getFloatValue());
6514 else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_MS)
6515 animation->setDuration(primitiveValue->getFloatValue()/1000.0f);
6516 }
6517
mapAnimationFillMode(Animation * layer,CSSValue * value)6518 void CSSStyleSelector::mapAnimationFillMode(Animation* layer, CSSValue* value)
6519 {
6520 if (value->cssValueType() == CSSValue::CSS_INITIAL) {
6521 layer->setFillMode(Animation::initialAnimationFillMode());
6522 return;
6523 }
6524
6525 if (!value->isPrimitiveValue())
6526 return;
6527
6528 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
6529 switch (primitiveValue->getIdent()) {
6530 case CSSValueNone:
6531 layer->setFillMode(AnimationFillModeNone);
6532 break;
6533 case CSSValueForwards:
6534 layer->setFillMode(AnimationFillModeForwards);
6535 break;
6536 case CSSValueBackwards:
6537 layer->setFillMode(AnimationFillModeBackwards);
6538 break;
6539 case CSSValueBoth:
6540 layer->setFillMode(AnimationFillModeBoth);
6541 break;
6542 }
6543 }
6544
mapAnimationIterationCount(Animation * animation,CSSValue * value)6545 void CSSStyleSelector::mapAnimationIterationCount(Animation* animation, CSSValue* value)
6546 {
6547 if (value->cssValueType() == CSSValue::CSS_INITIAL) {
6548 animation->setIterationCount(Animation::initialAnimationIterationCount());
6549 return;
6550 }
6551
6552 if (!value->isPrimitiveValue())
6553 return;
6554
6555 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
6556 if (primitiveValue->getIdent() == CSSValueInfinite)
6557 animation->setIterationCount(-1);
6558 else
6559 animation->setIterationCount(int(primitiveValue->getFloatValue()));
6560 }
6561
mapAnimationName(Animation * layer,CSSValue * value)6562 void CSSStyleSelector::mapAnimationName(Animation* layer, CSSValue* value)
6563 {
6564 if (value->cssValueType() == CSSValue::CSS_INITIAL) {
6565 layer->setName(Animation::initialAnimationName());
6566 return;
6567 }
6568
6569 if (!value->isPrimitiveValue())
6570 return;
6571
6572 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
6573 if (primitiveValue->getIdent() == CSSValueNone)
6574 layer->setIsNoneAnimation(true);
6575 else
6576 layer->setName(primitiveValue->getStringValue());
6577 }
6578
mapAnimationPlayState(Animation * layer,CSSValue * value)6579 void CSSStyleSelector::mapAnimationPlayState(Animation* layer, CSSValue* value)
6580 {
6581 if (value->cssValueType() == CSSValue::CSS_INITIAL) {
6582 layer->setPlayState(Animation::initialAnimationPlayState());
6583 return;
6584 }
6585
6586 if (!value->isPrimitiveValue())
6587 return;
6588
6589 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
6590 EAnimPlayState playState = (primitiveValue->getIdent() == CSSValuePaused) ? AnimPlayStatePaused : AnimPlayStatePlaying;
6591 layer->setPlayState(playState);
6592 }
6593
mapAnimationProperty(Animation * animation,CSSValue * value)6594 void CSSStyleSelector::mapAnimationProperty(Animation* animation, CSSValue* value)
6595 {
6596 if (value->cssValueType() == CSSValue::CSS_INITIAL) {
6597 animation->setProperty(Animation::initialAnimationProperty());
6598 return;
6599 }
6600
6601 if (!value->isPrimitiveValue())
6602 return;
6603
6604 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
6605 if (primitiveValue->getIdent() == CSSValueAll)
6606 animation->setProperty(cAnimateAll);
6607 else if (primitiveValue->getIdent() == CSSValueNone)
6608 animation->setProperty(cAnimateNone);
6609 else
6610 animation->setProperty(static_cast<CSSPropertyID>(primitiveValue->getIdent()));
6611 }
6612
mapAnimationTimingFunction(Animation * animation,CSSValue * value)6613 void CSSStyleSelector::mapAnimationTimingFunction(Animation* animation, CSSValue* value)
6614 {
6615 if (value->cssValueType() == CSSValue::CSS_INITIAL) {
6616 animation->setTimingFunction(Animation::initialAnimationTimingFunction());
6617 return;
6618 }
6619
6620 if (value->isPrimitiveValue()) {
6621 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
6622 switch (primitiveValue->getIdent()) {
6623 case CSSValueLinear:
6624 animation->setTimingFunction(LinearTimingFunction::create());
6625 break;
6626 case CSSValueEase:
6627 animation->setTimingFunction(CubicBezierTimingFunction::create());
6628 break;
6629 case CSSValueEaseIn:
6630 animation->setTimingFunction(CubicBezierTimingFunction::create(0.42, 0.0, 1.0, 1.0));
6631 break;
6632 case CSSValueEaseOut:
6633 animation->setTimingFunction(CubicBezierTimingFunction::create(0.0, 0.0, 0.58, 1.0));
6634 break;
6635 case CSSValueEaseInOut:
6636 animation->setTimingFunction(CubicBezierTimingFunction::create(0.42, 0.0, 0.58, 1.0));
6637 break;
6638 case CSSValueStepStart:
6639 animation->setTimingFunction(StepsTimingFunction::create(1, true));
6640 break;
6641 case CSSValueStepEnd:
6642 animation->setTimingFunction(StepsTimingFunction::create(1, false));
6643 break;
6644 }
6645 return;
6646 }
6647
6648 if (value->isTimingFunctionValue()) {
6649 CSSTimingFunctionValue* timingFunction = static_cast<CSSTimingFunctionValue*>(value);
6650 if (timingFunction->isCubicBezierTimingFunctionValue()) {
6651 CSSCubicBezierTimingFunctionValue* cubicTimingFunction = static_cast<CSSCubicBezierTimingFunctionValue*>(value);
6652 animation->setTimingFunction(CubicBezierTimingFunction::create(cubicTimingFunction->x1(), cubicTimingFunction->y1(), cubicTimingFunction->x2(), cubicTimingFunction->y2()));
6653 } else if (timingFunction->isStepsTimingFunctionValue()) {
6654 CSSStepsTimingFunctionValue* stepsTimingFunction = static_cast<CSSStepsTimingFunctionValue*>(value);
6655 animation->setTimingFunction(StepsTimingFunction::create(stepsTimingFunction->numberOfSteps(), stepsTimingFunction->stepAtStart()));
6656 } else
6657 animation->setTimingFunction(LinearTimingFunction::create());
6658 }
6659 }
6660
mapNinePieceImage(CSSPropertyID property,CSSValue * value,NinePieceImage & image)6661 void CSSStyleSelector::mapNinePieceImage(CSSPropertyID property, CSSValue* value, NinePieceImage& image)
6662 {
6663 // If we're a primitive value, then we are "none" and don't need to alter the empty image at all.
6664 if (!value || value->isPrimitiveValue() || !value->isBorderImageValue())
6665 return;
6666
6667 // Retrieve the border image value.
6668 CSSBorderImageValue* borderImage = static_cast<CSSBorderImageValue*>(value);
6669
6670 // Set the image (this kicks off the load).
6671 image.setImage(styleImage(property, borderImage->imageValue()));
6672
6673 // Set up a length box to represent our image slices.
6674 LengthBox l;
6675 Rect* r = borderImage->m_imageSliceRect.get();
6676 if (r->top()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE)
6677 l.m_top = Length(r->top()->getDoubleValue(), Percent);
6678 else
6679 l.m_top = Length(r->top()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
6680 if (r->bottom()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE)
6681 l.m_bottom = Length(r->bottom()->getDoubleValue(), Percent);
6682 else
6683 l.m_bottom = Length((int)r->bottom()->getFloatValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
6684 if (r->left()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE)
6685 l.m_left = Length(r->left()->getDoubleValue(), Percent);
6686 else
6687 l.m_left = Length(r->left()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
6688 if (r->right()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE)
6689 l.m_right = Length(r->right()->getDoubleValue(), Percent);
6690 else
6691 l.m_right = Length(r->right()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed);
6692 image.setSlices(l);
6693
6694 // Set the appropriate rules for stretch/round/repeat of the slices
6695 ENinePieceImageRule horizontalRule;
6696 switch (borderImage->m_horizontalSizeRule) {
6697 case CSSValueStretch:
6698 horizontalRule = StretchImageRule;
6699 break;
6700 case CSSValueRound:
6701 horizontalRule = RoundImageRule;
6702 break;
6703 default: // CSSValueRepeat
6704 horizontalRule = RepeatImageRule;
6705 break;
6706 }
6707 image.setHorizontalRule(horizontalRule);
6708
6709 ENinePieceImageRule verticalRule;
6710 switch (borderImage->m_verticalSizeRule) {
6711 case CSSValueStretch:
6712 verticalRule = StretchImageRule;
6713 break;
6714 case CSSValueRound:
6715 verticalRule = RoundImageRule;
6716 break;
6717 default: // CSSValueRepeat
6718 verticalRule = RepeatImageRule;
6719 break;
6720 }
6721 image.setVerticalRule(verticalRule);
6722 }
6723
checkForTextSizeAdjust()6724 void CSSStyleSelector::checkForTextSizeAdjust()
6725 {
6726 if (m_style->textSizeAdjust())
6727 return;
6728
6729 /* TODO: Remove this when a fix for webkit bug 56543 is submitted and can
6730 * be cherry picked.
6731 * This is a quick fix for Android to prevent sites from using
6732 * -webkit-text-size-adjust: none; which breaks font size accessibility
6733 * options on all platforms. The purpose of the property is to prevent
6734 * the automatic font size changes done by platforms like iOS when the
6735 * rotation changes. Since Android doesn't do this, we can safely ignore
6736 * the 'none' option.
6737 */
6738 #if PLATFORM(ANDROID)
6739 return;
6740 #endif
6741
6742 FontDescription newFontDescription(m_style->fontDescription());
6743 newFontDescription.setComputedSize(newFontDescription.specifiedSize());
6744 m_style->setFontDescription(newFontDescription);
6745 }
6746
checkForZoomChange(RenderStyle * style,RenderStyle * parentStyle)6747 void CSSStyleSelector::checkForZoomChange(RenderStyle* style, RenderStyle* parentStyle)
6748 {
6749 if (style->effectiveZoom() == parentStyle->effectiveZoom())
6750 return;
6751
6752 const FontDescription& childFont = style->fontDescription();
6753 FontDescription newFontDescription(childFont);
6754 setFontSize(newFontDescription, childFont.specifiedSize());
6755 style->setFontDescription(newFontDescription);
6756 }
6757
checkForGenericFamilyChange(RenderStyle * style,RenderStyle * parentStyle)6758 void CSSStyleSelector::checkForGenericFamilyChange(RenderStyle* style, RenderStyle* parentStyle)
6759 {
6760 const FontDescription& childFont = style->fontDescription();
6761
6762 if (childFont.isAbsoluteSize() || !parentStyle)
6763 return;
6764
6765 const FontDescription& parentFont = parentStyle->fontDescription();
6766 if (childFont.useFixedDefaultSize() == parentFont.useFixedDefaultSize())
6767 return;
6768
6769 // For now, lump all families but monospace together.
6770 if (childFont.genericFamily() != FontDescription::MonospaceFamily &&
6771 parentFont.genericFamily() != FontDescription::MonospaceFamily)
6772 return;
6773
6774 // We know the parent is monospace or the child is monospace, and that font
6775 // size was unspecified. We want to scale our font size as appropriate.
6776 // If the font uses a keyword size, then we refetch from the table rather than
6777 // multiplying by our scale factor.
6778 float size;
6779 if (childFont.keywordSize())
6780 size = fontSizeForKeyword(m_checker.m_document, CSSValueXxSmall + childFont.keywordSize() - 1, childFont.useFixedDefaultSize());
6781 else {
6782 Settings* settings = m_checker.m_document->settings();
6783 float fixedScaleFactor = settings
6784 ? static_cast<float>(settings->defaultFixedFontSize()) / settings->defaultFontSize()
6785 : 1;
6786 size = parentFont.useFixedDefaultSize() ?
6787 childFont.specifiedSize() / fixedScaleFactor :
6788 childFont.specifiedSize() * fixedScaleFactor;
6789 }
6790
6791 FontDescription newFontDescription(childFont);
6792 setFontSize(newFontDescription, size);
6793 style->setFontDescription(newFontDescription);
6794 }
6795
setFontSize(FontDescription & fontDescription,float size)6796 void CSSStyleSelector::setFontSize(FontDescription& fontDescription, float size)
6797 {
6798 fontDescription.setSpecifiedSize(size);
6799
6800 bool useSVGZoomRules = m_element && m_element->isSVGElement();
6801 fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(m_checker.m_document, m_style.get(), fontDescription.isAbsoluteSize(), size, useSVGZoomRules));
6802 }
6803
getComputedSizeFromSpecifiedSize(Document * document,RenderStyle * style,bool isAbsoluteSize,float specifiedSize,bool useSVGZoomRules)6804 float CSSStyleSelector::getComputedSizeFromSpecifiedSize(Document* document, RenderStyle* style, bool isAbsoluteSize, float specifiedSize, bool useSVGZoomRules)
6805 {
6806 // Text with a 0px font size should not be visible and therefore needs to be
6807 // exempt from minimum font size rules. Acid3 relies on this for pixel-perfect
6808 // rendering. This is also compatible with other browsers that have minimum
6809 // font size settings (e.g. Firefox).
6810 if (fabsf(specifiedSize) < std::numeric_limits<float>::epsilon())
6811 return 0.0f;
6812
6813 float zoomFactor = 1.0f;
6814 if (!useSVGZoomRules) {
6815 zoomFactor = style->effectiveZoom();
6816 if (Frame* frame = document->frame())
6817 zoomFactor *= frame->textZoomFactor();
6818 }
6819
6820 // We support two types of minimum font size. The first is a hard override that applies to
6821 // all fonts. This is "minSize." The second type of minimum font size is a "smart minimum"
6822 // that is applied only when the Web page can't know what size it really asked for, e.g.,
6823 // when it uses logical sizes like "small" or expresses the font-size as a percentage of
6824 // the user's default font setting.
6825
6826 // With the smart minimum, we never want to get smaller than the minimum font size to keep fonts readable.
6827 // However we always allow the page to set an explicit pixel size that is smaller,
6828 // since sites will mis-render otherwise (e.g., http://www.gamespot.com with a 9px minimum).
6829
6830 Settings* settings = document->settings();
6831 if (!settings)
6832 return 1.0f;
6833
6834 int minSize = settings->minimumFontSize();
6835 int minLogicalSize = settings->minimumLogicalFontSize();
6836 float zoomedSize = specifiedSize * zoomFactor;
6837
6838 // Apply the hard minimum first. We only apply the hard minimum if after zooming we're still too small.
6839 if (zoomedSize < minSize)
6840 zoomedSize = minSize;
6841
6842 // Now apply the "smart minimum." This minimum is also only applied if we're still too small
6843 // after zooming. The font size must either be relative to the user default or the original size
6844 // must have been acceptable. In other words, we only apply the smart minimum whenever we're positive
6845 // doing so won't disrupt the layout.
6846 if (zoomedSize < minLogicalSize && (specifiedSize >= minLogicalSize || !isAbsoluteSize))
6847 zoomedSize = minLogicalSize;
6848
6849 // Also clamp to a reasonable maximum to prevent insane font sizes from causing crashes on various
6850 // platforms (I'm looking at you, Windows.)
6851 return min(1000000.0f, zoomedSize);
6852 }
6853
6854 const int fontSizeTableMax = 16;
6855 const int fontSizeTableMin = 9;
6856 const int totalKeywords = 8;
6857
6858 // WinIE/Nav4 table for font sizes. Designed to match the legacy font mapping system of HTML.
6859 static const int quirksFontSizeTable[fontSizeTableMax - fontSizeTableMin + 1][totalKeywords] =
6860 {
6861 { 9, 9, 9, 9, 11, 14, 18, 28 },
6862 { 9, 9, 9, 10, 12, 15, 20, 31 },
6863 { 9, 9, 9, 11, 13, 17, 22, 34 },
6864 { 9, 9, 10, 12, 14, 18, 24, 37 },
6865 { 9, 9, 10, 13, 16, 20, 26, 40 }, // fixed font default (13)
6866 { 9, 9, 11, 14, 17, 21, 28, 42 },
6867 { 9, 10, 12, 15, 17, 23, 30, 45 },
6868 { 9, 10, 13, 16, 18, 24, 32, 48 } // proportional font default (16)
6869 };
6870 // HTML 1 2 3 4 5 6 7
6871 // CSS xxs xs s m l xl xxl
6872 // |
6873 // user pref
6874
6875 // Strict mode table matches MacIE and Mozilla's settings exactly.
6876 static const int strictFontSizeTable[fontSizeTableMax - fontSizeTableMin + 1][totalKeywords] =
6877 {
6878 { 9, 9, 9, 9, 11, 14, 18, 27 },
6879 { 9, 9, 9, 10, 12, 15, 20, 30 },
6880 { 9, 9, 10, 11, 13, 17, 22, 33 },
6881 { 9, 9, 10, 12, 14, 18, 24, 36 },
6882 { 9, 10, 12, 13, 16, 20, 26, 39 }, // fixed font default (13)
6883 { 9, 10, 12, 14, 17, 21, 28, 42 },
6884 { 9, 10, 13, 15, 18, 23, 30, 45 },
6885 { 9, 10, 13, 16, 18, 24, 32, 48 } // proportional font default (16)
6886 };
6887 // HTML 1 2 3 4 5 6 7
6888 // CSS xxs xs s m l xl xxl
6889 // |
6890 // user pref
6891
6892 // For values outside the range of the table, we use Todd Fahrner's suggested scale
6893 // factors for each keyword value.
6894 static const float fontSizeFactors[totalKeywords] = { 0.60f, 0.75f, 0.89f, 1.0f, 1.2f, 1.5f, 2.0f, 3.0f };
6895
fontSizeForKeyword(Document * document,int keyword,bool shouldUseFixedDefaultSize)6896 float CSSStyleSelector::fontSizeForKeyword(Document* document, int keyword, bool shouldUseFixedDefaultSize)
6897 {
6898 Settings* settings = document->settings();
6899 if (!settings)
6900 return 1.0f;
6901
6902 bool quirksMode = document->inQuirksMode();
6903 int mediumSize = shouldUseFixedDefaultSize ? settings->defaultFixedFontSize() : settings->defaultFontSize();
6904 if (mediumSize >= fontSizeTableMin && mediumSize <= fontSizeTableMax) {
6905 // Look up the entry in the table.
6906 int row = mediumSize - fontSizeTableMin;
6907 int col = (keyword - CSSValueXxSmall);
6908 return quirksMode ? quirksFontSizeTable[row][col] : strictFontSizeTable[row][col];
6909 }
6910
6911 // Value is outside the range of the table. Apply the scale factor instead.
6912 float minLogicalSize = max(settings->minimumLogicalFontSize(), 1);
6913 return max(fontSizeFactors[keyword - CSSValueXxSmall]*mediumSize, minLogicalSize);
6914 }
6915
6916 template<typename T>
findNearestLegacyFontSize(int pixelFontSize,const T * table,int multiplier)6917 static int findNearestLegacyFontSize(int pixelFontSize, const T* table, int multiplier)
6918 {
6919 // Ignore table[0] because xx-small does not correspond to any legacy font size.
6920 for (int i = 1; i < totalKeywords - 1; i++) {
6921 if (pixelFontSize * 2 < (table[i] + table[i + 1]) * multiplier)
6922 return i;
6923 }
6924 return totalKeywords - 1;
6925 }
6926
legacyFontSize(Document * document,int pixelFontSize,bool shouldUseFixedDefaultSize)6927 int CSSStyleSelector::legacyFontSize(Document* document, int pixelFontSize, bool shouldUseFixedDefaultSize)
6928 {
6929 Settings* settings = document->settings();
6930 if (!settings)
6931 return 1;
6932
6933 bool quirksMode = document->inQuirksMode();
6934 int mediumSize = shouldUseFixedDefaultSize ? settings->defaultFixedFontSize() : settings->defaultFontSize();
6935 if (mediumSize >= fontSizeTableMin && mediumSize <= fontSizeTableMax) {
6936 int row = mediumSize - fontSizeTableMin;
6937 return findNearestLegacyFontSize<int>(pixelFontSize, quirksMode ? quirksFontSizeTable[row] : strictFontSizeTable[row], 1);
6938 }
6939
6940 return findNearestLegacyFontSize<float>(pixelFontSize, fontSizeFactors, mediumSize);
6941 }
6942
largerFontSize(float size,bool) const6943 float CSSStyleSelector::largerFontSize(float size, bool) const
6944 {
6945 // FIXME: Figure out where we fall in the size ranges (xx-small to xxx-large) and scale up to
6946 // the next size level.
6947 return size * 1.2f;
6948 }
6949
smallerFontSize(float size,bool) const6950 float CSSStyleSelector::smallerFontSize(float size, bool) const
6951 {
6952 // FIXME: Figure out where we fall in the size ranges (xx-small to xxx-large) and scale down to
6953 // the next size level.
6954 return size / 1.2f;
6955 }
6956
colorForCSSValue(int cssValueId)6957 static Color colorForCSSValue(int cssValueId)
6958 {
6959 struct ColorValue {
6960 int cssValueId;
6961 RGBA32 color;
6962 };
6963
6964 static const ColorValue colorValues[] = {
6965 { CSSValueAqua, 0xFF00FFFF },
6966 { CSSValueBlack, 0xFF000000 },
6967 { CSSValueBlue, 0xFF0000FF },
6968 { CSSValueFuchsia, 0xFFFF00FF },
6969 { CSSValueGray, 0xFF808080 },
6970 { CSSValueGreen, 0xFF008000 },
6971 { CSSValueGrey, 0xFF808080 },
6972 { CSSValueLime, 0xFF00FF00 },
6973 { CSSValueMaroon, 0xFF800000 },
6974 { CSSValueNavy, 0xFF000080 },
6975 { CSSValueOlive, 0xFF808000 },
6976 { CSSValueOrange, 0xFFFFA500 },
6977 { CSSValuePurple, 0xFF800080 },
6978 { CSSValueRed, 0xFFFF0000 },
6979 { CSSValueSilver, 0xFFC0C0C0 },
6980 { CSSValueTeal, 0xFF008080 },
6981 { CSSValueTransparent, 0x00000000 },
6982 { CSSValueWhite, 0xFFFFFFFF },
6983 { CSSValueYellow, 0xFFFFFF00 },
6984 { 0, 0 }
6985 };
6986
6987 for (const ColorValue* col = colorValues; col->cssValueId; ++col) {
6988 if (col->cssValueId == cssValueId)
6989 return col->color;
6990 }
6991 return RenderTheme::defaultTheme()->systemColor(cssValueId);
6992 }
6993
getColorFromPrimitiveValue(CSSPrimitiveValue * primitiveValue) const6994 Color CSSStyleSelector::getColorFromPrimitiveValue(CSSPrimitiveValue* primitiveValue) const
6995 {
6996 Color col;
6997 int ident = primitiveValue->getIdent();
6998 if (ident) {
6999 if (ident == CSSValueWebkitText)
7000 col = m_element->document()->textColor();
7001 else if (ident == CSSValueWebkitLink)
7002 col = m_element->isLink() && m_checker.m_matchVisitedPseudoClass ? m_element->document()->visitedLinkColor() : m_element->document()->linkColor();
7003 else if (ident == CSSValueWebkitActivelink)
7004 col = m_element->document()->activeLinkColor();
7005 else if (ident == CSSValueWebkitFocusRingColor)
7006 col = RenderTheme::focusRingColor();
7007 else if (ident == CSSValueCurrentcolor)
7008 col = m_style->color();
7009 else
7010 col = colorForCSSValue(ident);
7011 } else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_RGBCOLOR)
7012 col.setRGB(primitiveValue->getRGBA32Value());
7013 return col;
7014 }
7015
hasSelectorForAttribute(const AtomicString & attrname) const7016 bool CSSStyleSelector::hasSelectorForAttribute(const AtomicString &attrname) const
7017 {
7018 return m_selectorAttrs.contains(attrname.impl());
7019 }
7020
addViewportDependentMediaQueryResult(const MediaQueryExp * expr,bool result)7021 void CSSStyleSelector::addViewportDependentMediaQueryResult(const MediaQueryExp* expr, bool result)
7022 {
7023 m_viewportDependentMediaQueryResults.append(new MediaQueryResult(*expr, result));
7024 }
7025
affectedByViewportChange() const7026 bool CSSStyleSelector::affectedByViewportChange() const
7027 {
7028 unsigned s = m_viewportDependentMediaQueryResults.size();
7029 for (unsigned i = 0; i < s; i++) {
7030 if (m_medium->eval(&m_viewportDependentMediaQueryResults[i]->m_expression) != m_viewportDependentMediaQueryResults[i]->m_result)
7031 return true;
7032 }
7033 return false;
7034 }
7035
allVisitedStateChanged()7036 void CSSStyleSelector::SelectorChecker::allVisitedStateChanged()
7037 {
7038 if (m_linksCheckedForVisitedState.isEmpty())
7039 return;
7040 for (Node* node = m_document; node; node = node->traverseNextNode()) {
7041 if (node->isLink())
7042 node->setNeedsStyleRecalc();
7043 }
7044 }
7045
visitedStateChanged(LinkHash visitedHash)7046 void CSSStyleSelector::SelectorChecker::visitedStateChanged(LinkHash visitedHash)
7047 {
7048 if (!m_linksCheckedForVisitedState.contains(visitedHash))
7049 return;
7050 for (Node* node = m_document; node; node = node->traverseNextNode()) {
7051 const AtomicString* attr = linkAttribute(node);
7052 if (attr && visitedLinkHash(m_document->baseURL(), *attr) == visitedHash)
7053 node->setNeedsStyleRecalc();
7054 }
7055 }
7056
getTransformOperationType(WebKitCSSTransformValue::TransformOperationType type)7057 static TransformOperation::OperationType getTransformOperationType(WebKitCSSTransformValue::TransformOperationType type)
7058 {
7059 switch (type) {
7060 case WebKitCSSTransformValue::ScaleTransformOperation: return TransformOperation::SCALE;
7061 case WebKitCSSTransformValue::ScaleXTransformOperation: return TransformOperation::SCALE_X;
7062 case WebKitCSSTransformValue::ScaleYTransformOperation: return TransformOperation::SCALE_Y;
7063 case WebKitCSSTransformValue::ScaleZTransformOperation: return TransformOperation::SCALE_Z;
7064 case WebKitCSSTransformValue::Scale3DTransformOperation: return TransformOperation::SCALE_3D;
7065 case WebKitCSSTransformValue::TranslateTransformOperation: return TransformOperation::TRANSLATE;
7066 case WebKitCSSTransformValue::TranslateXTransformOperation: return TransformOperation::TRANSLATE_X;
7067 case WebKitCSSTransformValue::TranslateYTransformOperation: return TransformOperation::TRANSLATE_Y;
7068 case WebKitCSSTransformValue::TranslateZTransformOperation: return TransformOperation::TRANSLATE_Z;
7069 case WebKitCSSTransformValue::Translate3DTransformOperation: return TransformOperation::TRANSLATE_3D;
7070 case WebKitCSSTransformValue::RotateTransformOperation: return TransformOperation::ROTATE;
7071 case WebKitCSSTransformValue::RotateXTransformOperation: return TransformOperation::ROTATE_X;
7072 case WebKitCSSTransformValue::RotateYTransformOperation: return TransformOperation::ROTATE_Y;
7073 case WebKitCSSTransformValue::RotateZTransformOperation: return TransformOperation::ROTATE_Z;
7074 case WebKitCSSTransformValue::Rotate3DTransformOperation: return TransformOperation::ROTATE_3D;
7075 case WebKitCSSTransformValue::SkewTransformOperation: return TransformOperation::SKEW;
7076 case WebKitCSSTransformValue::SkewXTransformOperation: return TransformOperation::SKEW_X;
7077 case WebKitCSSTransformValue::SkewYTransformOperation: return TransformOperation::SKEW_Y;
7078 case WebKitCSSTransformValue::MatrixTransformOperation: return TransformOperation::MATRIX;
7079 case WebKitCSSTransformValue::Matrix3DTransformOperation: return TransformOperation::MATRIX_3D;
7080 case WebKitCSSTransformValue::PerspectiveTransformOperation: return TransformOperation::PERSPECTIVE;
7081 case WebKitCSSTransformValue::UnknownTransformOperation: return TransformOperation::NONE;
7082 }
7083 return TransformOperation::NONE;
7084 }
7085
createTransformOperations(CSSValue * inValue,RenderStyle * style,RenderStyle * rootStyle,TransformOperations & outOperations)7086 bool CSSStyleSelector::createTransformOperations(CSSValue* inValue, RenderStyle* style, RenderStyle* rootStyle, TransformOperations& outOperations)
7087 {
7088 if (!inValue || !inValue->isValueList()) {
7089 outOperations.clear();
7090 return false;
7091 }
7092
7093 float zoomFactor = style ? style->effectiveZoom() : 1;
7094 TransformOperations operations;
7095 CSSValueList* list = static_cast<CSSValueList*>(inValue);
7096 unsigned size = list->length();
7097 for (unsigned i = 0; i < size; i++) {
7098 CSSValue* currValue = list->itemWithoutBoundsCheck(i);
7099 if (!currValue->isWebKitCSSTransformValue())
7100 continue;
7101
7102 WebKitCSSTransformValue* transformValue = static_cast<WebKitCSSTransformValue*>(list->itemWithoutBoundsCheck(i));
7103 if (!transformValue->length())
7104 continue;
7105
7106 bool haveNonPrimitiveValue = false;
7107 for (unsigned j = 0; j < transformValue->length(); ++j) {
7108 if (!transformValue->itemWithoutBoundsCheck(j)->isPrimitiveValue()) {
7109 haveNonPrimitiveValue = true;
7110 break;
7111 }
7112 }
7113 if (haveNonPrimitiveValue)
7114 continue;
7115
7116 CSSPrimitiveValue* firstValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(0));
7117
7118 switch (transformValue->operationType()) {
7119 case WebKitCSSTransformValue::ScaleTransformOperation:
7120 case WebKitCSSTransformValue::ScaleXTransformOperation:
7121 case WebKitCSSTransformValue::ScaleYTransformOperation: {
7122 double sx = 1.0;
7123 double sy = 1.0;
7124 if (transformValue->operationType() == WebKitCSSTransformValue::ScaleYTransformOperation)
7125 sy = firstValue->getDoubleValue();
7126 else {
7127 sx = firstValue->getDoubleValue();
7128 if (transformValue->operationType() != WebKitCSSTransformValue::ScaleXTransformOperation) {
7129 if (transformValue->length() > 1) {
7130 CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1));
7131 sy = secondValue->getDoubleValue();
7132 } else
7133 sy = sx;
7134 }
7135 }
7136 operations.operations().append(ScaleTransformOperation::create(sx, sy, 1.0, getTransformOperationType(transformValue->operationType())));
7137 break;
7138 }
7139 case WebKitCSSTransformValue::ScaleZTransformOperation:
7140 case WebKitCSSTransformValue::Scale3DTransformOperation: {
7141 double sx = 1.0;
7142 double sy = 1.0;
7143 double sz = 1.0;
7144 if (transformValue->operationType() == WebKitCSSTransformValue::ScaleZTransformOperation)
7145 sz = firstValue->getDoubleValue();
7146 else if (transformValue->operationType() == WebKitCSSTransformValue::ScaleYTransformOperation)
7147 sy = firstValue->getDoubleValue();
7148 else {
7149 sx = firstValue->getDoubleValue();
7150 if (transformValue->operationType() != WebKitCSSTransformValue::ScaleXTransformOperation) {
7151 if (transformValue->length() > 2) {
7152 CSSPrimitiveValue* thirdValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(2));
7153 sz = thirdValue->getDoubleValue();
7154 }
7155 if (transformValue->length() > 1) {
7156 CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1));
7157 sy = secondValue->getDoubleValue();
7158 } else
7159 sy = sx;
7160 }
7161 }
7162 operations.operations().append(ScaleTransformOperation::create(sx, sy, sz, getTransformOperationType(transformValue->operationType())));
7163 break;
7164 }
7165 case WebKitCSSTransformValue::TranslateTransformOperation:
7166 case WebKitCSSTransformValue::TranslateXTransformOperation:
7167 case WebKitCSSTransformValue::TranslateYTransformOperation: {
7168 bool ok = true;
7169 Length tx = Length(0, Fixed);
7170 Length ty = Length(0, Fixed);
7171 if (transformValue->operationType() == WebKitCSSTransformValue::TranslateYTransformOperation)
7172 ty = convertToFloatLength(firstValue, style, rootStyle, zoomFactor, &ok);
7173 else {
7174 tx = convertToFloatLength(firstValue, style, rootStyle, zoomFactor, &ok);
7175 if (transformValue->operationType() != WebKitCSSTransformValue::TranslateXTransformOperation) {
7176 if (transformValue->length() > 1) {
7177 CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1));
7178 ty = convertToFloatLength(secondValue, style, rootStyle, zoomFactor, &ok);
7179 }
7180 }
7181 }
7182
7183 if (!ok)
7184 return false;
7185
7186 operations.operations().append(TranslateTransformOperation::create(tx, ty, Length(0, Fixed), getTransformOperationType(transformValue->operationType())));
7187 break;
7188 }
7189 case WebKitCSSTransformValue::TranslateZTransformOperation:
7190 case WebKitCSSTransformValue::Translate3DTransformOperation: {
7191 bool ok = true;
7192 Length tx = Length(0, Fixed);
7193 Length ty = Length(0, Fixed);
7194 Length tz = Length(0, Fixed);
7195 if (transformValue->operationType() == WebKitCSSTransformValue::TranslateZTransformOperation)
7196 tz = convertToFloatLength(firstValue, style, rootStyle, zoomFactor, &ok);
7197 else if (transformValue->operationType() == WebKitCSSTransformValue::TranslateYTransformOperation)
7198 ty = convertToFloatLength(firstValue, style, rootStyle, zoomFactor, &ok);
7199 else {
7200 tx = convertToFloatLength(firstValue, style, rootStyle, zoomFactor, &ok);
7201 if (transformValue->operationType() != WebKitCSSTransformValue::TranslateXTransformOperation) {
7202 if (transformValue->length() > 2) {
7203 CSSPrimitiveValue* thirdValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(2));
7204 tz = convertToFloatLength(thirdValue, style, rootStyle, zoomFactor, &ok);
7205 }
7206 if (transformValue->length() > 1) {
7207 CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1));
7208 ty = convertToFloatLength(secondValue, style, rootStyle, zoomFactor, &ok);
7209 }
7210 }
7211 }
7212
7213 if (!ok)
7214 return false;
7215
7216 operations.operations().append(TranslateTransformOperation::create(tx, ty, tz, getTransformOperationType(transformValue->operationType())));
7217 break;
7218 }
7219 case WebKitCSSTransformValue::RotateTransformOperation: {
7220 double angle = firstValue->getDoubleValue();
7221 if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_RAD)
7222 angle = rad2deg(angle);
7223 else if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_GRAD)
7224 angle = grad2deg(angle);
7225 else if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_TURN)
7226 angle = turn2deg(angle);
7227
7228 operations.operations().append(RotateTransformOperation::create(0, 0, 1, angle, getTransformOperationType(transformValue->operationType())));
7229 break;
7230 }
7231 case WebKitCSSTransformValue::RotateXTransformOperation:
7232 case WebKitCSSTransformValue::RotateYTransformOperation:
7233 case WebKitCSSTransformValue::RotateZTransformOperation: {
7234 double x = 0;
7235 double y = 0;
7236 double z = 0;
7237 double angle = firstValue->getDoubleValue();
7238 if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_RAD)
7239 angle = rad2deg(angle);
7240 else if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_GRAD)
7241 angle = grad2deg(angle);
7242
7243 if (transformValue->operationType() == WebKitCSSTransformValue::RotateXTransformOperation)
7244 x = 1;
7245 else if (transformValue->operationType() == WebKitCSSTransformValue::RotateYTransformOperation)
7246 y = 1;
7247 else
7248 z = 1;
7249 operations.operations().append(RotateTransformOperation::create(x, y, z, angle, getTransformOperationType(transformValue->operationType())));
7250 break;
7251 }
7252 case WebKitCSSTransformValue::Rotate3DTransformOperation: {
7253 if (transformValue->length() < 4)
7254 break;
7255 CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1));
7256 CSSPrimitiveValue* thirdValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(2));
7257 CSSPrimitiveValue* fourthValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(3));
7258 double x = firstValue->getDoubleValue();
7259 double y = secondValue->getDoubleValue();
7260 double z = thirdValue->getDoubleValue();
7261 double angle = fourthValue->getDoubleValue();
7262 if (fourthValue->primitiveType() == CSSPrimitiveValue::CSS_RAD)
7263 angle = rad2deg(angle);
7264 else if (fourthValue->primitiveType() == CSSPrimitiveValue::CSS_GRAD)
7265 angle = grad2deg(angle);
7266 operations.operations().append(RotateTransformOperation::create(x, y, z, angle, getTransformOperationType(transformValue->operationType())));
7267 break;
7268 }
7269 case WebKitCSSTransformValue::SkewTransformOperation:
7270 case WebKitCSSTransformValue::SkewXTransformOperation:
7271 case WebKitCSSTransformValue::SkewYTransformOperation: {
7272 double angleX = 0;
7273 double angleY = 0;
7274 double angle = firstValue->getDoubleValue();
7275 if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_RAD)
7276 angle = rad2deg(angle);
7277 else if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_GRAD)
7278 angle = grad2deg(angle);
7279 else if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_TURN)
7280 angle = turn2deg(angle);
7281 if (transformValue->operationType() == WebKitCSSTransformValue::SkewYTransformOperation)
7282 angleY = angle;
7283 else {
7284 angleX = angle;
7285 if (transformValue->operationType() == WebKitCSSTransformValue::SkewTransformOperation) {
7286 if (transformValue->length() > 1) {
7287 CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1));
7288 angleY = secondValue->getDoubleValue();
7289 if (secondValue->primitiveType() == CSSPrimitiveValue::CSS_RAD)
7290 angleY = rad2deg(angleY);
7291 else if (secondValue->primitiveType() == CSSPrimitiveValue::CSS_GRAD)
7292 angleY = grad2deg(angleY);
7293 else if (secondValue->primitiveType() == CSSPrimitiveValue::CSS_TURN)
7294 angleY = turn2deg(angleY);
7295 }
7296 }
7297 }
7298 operations.operations().append(SkewTransformOperation::create(angleX, angleY, getTransformOperationType(transformValue->operationType())));
7299 break;
7300 }
7301 case WebKitCSSTransformValue::MatrixTransformOperation: {
7302 if (transformValue->length() < 6)
7303 break;
7304 double a = firstValue->getDoubleValue();
7305 double b = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1))->getDoubleValue();
7306 double c = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(2))->getDoubleValue();
7307 double d = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(3))->getDoubleValue();
7308 double e = zoomFactor * static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(4))->getDoubleValue();
7309 double f = zoomFactor * static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(5))->getDoubleValue();
7310 operations.operations().append(MatrixTransformOperation::create(a, b, c, d, e, f));
7311 break;
7312 }
7313 case WebKitCSSTransformValue::Matrix3DTransformOperation: {
7314 if (transformValue->length() < 16)
7315 break;
7316 TransformationMatrix matrix(static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(0))->getDoubleValue(),
7317 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1))->getDoubleValue(),
7318 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(2))->getDoubleValue(),
7319 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(3))->getDoubleValue(),
7320 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(4))->getDoubleValue(),
7321 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(5))->getDoubleValue(),
7322 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(6))->getDoubleValue(),
7323 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(7))->getDoubleValue(),
7324 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(8))->getDoubleValue(),
7325 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(9))->getDoubleValue(),
7326 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(10))->getDoubleValue(),
7327 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(11))->getDoubleValue(),
7328 zoomFactor * static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(12))->getDoubleValue(),
7329 zoomFactor * static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(13))->getDoubleValue(),
7330 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(14))->getDoubleValue(),
7331 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(15))->getDoubleValue());
7332 operations.operations().append(Matrix3DTransformOperation::create(matrix));
7333 break;
7334 }
7335 case WebKitCSSTransformValue::PerspectiveTransformOperation: {
7336 bool ok = true;
7337 Length p = Length(0, Fixed);
7338 if (CSSPrimitiveValue::isUnitTypeLength(firstValue->primitiveType()))
7339 p = convertToFloatLength(firstValue, style, rootStyle, zoomFactor, &ok);
7340 else {
7341 // This is a quirk that should go away when 3d transforms are finalized.
7342 double val = firstValue->getDoubleValue();
7343 ok = val >= 0;
7344 val = clampToPositiveInteger(val);
7345 p = Length(static_cast<int>(val), Fixed);
7346 }
7347
7348 if (!ok)
7349 return false;
7350
7351 operations.operations().append(PerspectiveTransformOperation::create(p));
7352 break;
7353 }
7354 case WebKitCSSTransformValue::UnknownTransformOperation:
7355 ASSERT_NOT_REACHED();
7356 break;
7357 }
7358 }
7359
7360 outOperations = operations;
7361 return true;
7362 }
7363
loadPendingImages()7364 void CSSStyleSelector::loadPendingImages()
7365 {
7366 if (m_pendingImageProperties.isEmpty())
7367 return;
7368
7369 HashSet<int>::const_iterator end = m_pendingImageProperties.end();
7370 for (HashSet<int>::const_iterator it = m_pendingImageProperties.begin(); it != end; ++it) {
7371 CSSPropertyID currentProperty = static_cast<CSSPropertyID>(*it);
7372
7373 CachedResourceLoader* cachedResourceLoader = m_element->document()->cachedResourceLoader();
7374
7375 switch (currentProperty) {
7376 case CSSPropertyBackgroundImage: {
7377 for (FillLayer* backgroundLayer = m_style->accessBackgroundLayers(); backgroundLayer; backgroundLayer = backgroundLayer->next()) {
7378 if (backgroundLayer->image() && backgroundLayer->image()->isPendingImage()) {
7379 CSSImageValue* imageValue = static_cast<StylePendingImage*>(backgroundLayer->image())->cssImageValue();
7380 backgroundLayer->setImage(imageValue->cachedImage(cachedResourceLoader));
7381 }
7382 }
7383 break;
7384 }
7385
7386 case CSSPropertyContent: {
7387 for (ContentData* contentData = const_cast<ContentData*>(m_style->contentData()); contentData; contentData = contentData->next()) {
7388 if (contentData->isImage() && contentData->image()->isPendingImage()) {
7389 CSSImageValue* imageValue = static_cast<StylePendingImage*>(contentData->image())->cssImageValue();
7390 if (StyleCachedImage* cachedImage = imageValue->cachedImage(cachedResourceLoader))
7391 contentData->setImage(cachedImage);
7392 }
7393 }
7394 break;
7395 }
7396
7397 case CSSPropertyCursor: {
7398 if (CursorList* cursorList = m_style->cursors()) {
7399 for (size_t i = 0; i < cursorList->size(); ++i) {
7400 CursorData& currentCursor = cursorList->at(i);
7401 if (StyleImage* image = currentCursor.image()) {
7402 if (image->isPendingImage()) {
7403 CSSImageValue* imageValue = static_cast<StylePendingImage*>(image)->cssImageValue();
7404 currentCursor.setImage(imageValue->cachedImage(cachedResourceLoader));
7405 }
7406 }
7407 }
7408 }
7409 break;
7410 }
7411
7412 case CSSPropertyListStyleImage: {
7413 if (m_style->listStyleImage() && m_style->listStyleImage()->isPendingImage()) {
7414 CSSImageValue* imageValue = static_cast<StylePendingImage*>(m_style->listStyleImage())->cssImageValue();
7415 m_style->setListStyleImage(imageValue->cachedImage(cachedResourceLoader));
7416 }
7417 break;
7418 }
7419
7420 case CSSPropertyWebkitBorderImage: {
7421 const NinePieceImage& borderImage = m_style->borderImage();
7422 if (borderImage.image() && borderImage.image()->isPendingImage()) {
7423 CSSImageValue* imageValue = static_cast<StylePendingImage*>(borderImage.image())->cssImageValue();
7424 m_style->setBorderImage(NinePieceImage(imageValue->cachedImage(cachedResourceLoader), borderImage.slices(), borderImage.horizontalRule(), borderImage.verticalRule()));
7425 }
7426 break;
7427 }
7428
7429 case CSSPropertyWebkitBoxReflect: {
7430 if (StyleReflection* reflection = m_style->boxReflect()) {
7431 const NinePieceImage& maskImage = reflection->mask();
7432 if (maskImage.image() && maskImage.image()->isPendingImage()) {
7433 CSSImageValue* imageValue = static_cast<StylePendingImage*>(maskImage.image())->cssImageValue();
7434 reflection->setMask(NinePieceImage(imageValue->cachedImage(cachedResourceLoader), maskImage.slices(), maskImage.horizontalRule(), maskImage.verticalRule()));
7435 }
7436 }
7437 break;
7438 }
7439
7440 case CSSPropertyWebkitMaskBoxImage: {
7441 const NinePieceImage& maskBoxImage = m_style->maskBoxImage();
7442 if (maskBoxImage.image() && maskBoxImage.image()->isPendingImage()) {
7443 CSSImageValue* imageValue = static_cast<StylePendingImage*>(maskBoxImage.image())->cssImageValue();
7444 m_style->setMaskBoxImage(NinePieceImage(imageValue->cachedImage(cachedResourceLoader), maskBoxImage.slices(), maskBoxImage.horizontalRule(), maskBoxImage.verticalRule()));
7445 }
7446 break;
7447 }
7448
7449 case CSSPropertyWebkitMaskImage: {
7450 for (FillLayer* maskLayer = m_style->accessMaskLayers(); maskLayer; maskLayer = maskLayer->next()) {
7451 if (maskLayer->image() && maskLayer->image()->isPendingImage()) {
7452 CSSImageValue* imageValue = static_cast<StylePendingImage*>(maskLayer->image())->cssImageValue();
7453 maskLayer->setImage(imageValue->cachedImage(cachedResourceLoader));
7454 }
7455 }
7456 break;
7457 }
7458 default:
7459 ASSERT_NOT_REACHED();
7460 }
7461 }
7462
7463 m_pendingImageProperties.clear();
7464 }
7465
7466 } // namespace WebCore
7467