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