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, 2012, 2013 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 * Copyright (C) Research In Motion Limited 2011. All rights reserved. 11 * Copyright (C) 2012 Google Inc. All rights reserved. 12 * 13 * This library is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU Library General Public 15 * License as published by the Free Software Foundation; either 16 * version 2 of the License, or (at your option) any later version. 17 * 18 * This library is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 * Library General Public License for more details. 22 * 23 * You should have received a copy of the GNU Library General Public License 24 * along with this library; see the file COPYING.LIB. If not, write to 25 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 26 * Boston, MA 02110-1301, USA. 27 */ 28 29#include "config.h" 30#include "StyleResolver.h" 31 32#include "Attribute.h" 33#include "CSSBorderImage.h" 34#include "CSSCalculationValue.h" 35#include "CSSCursorImageValue.h" 36#include "CSSDefaultStyleSheets.h" 37#include "CSSFontFaceRule.h" 38#include "CSSFontSelector.h" 39#include "CSSLineBoxContainValue.h" 40#include "CSSPageRule.h" 41#include "CSSParser.h" 42#include "CSSPrimitiveValueMappings.h" 43#include "CSSPropertyNames.h" 44#include "CSSReflectValue.h" 45#include "CSSSelector.h" 46#include "CSSSelectorList.h" 47#include "CSSStyleRule.h" 48#include "CSSSupportsRule.h" 49#include "CSSTimingFunctionValue.h" 50#include "CSSValueList.h" 51#if ENABLE(CSS_VARIABLES) 52#include "CSSVariableValue.h" 53#endif 54#include "CachedImage.h" 55#include "CalculationValue.h" 56#include "ContentData.h" 57#include "ContextFeatures.h" 58#include "Counter.h" 59#include "CounterContent.h" 60#include "CursorList.h" 61#include "DeprecatedStyleBuilder.h" 62#include "DocumentStyleSheetCollection.h" 63#include "ElementRuleCollector.h" 64#include "ElementShadow.h" 65#include "FontFeatureValue.h" 66#include "FontValue.h" 67#include "Frame.h" 68#include "FrameSelection.h" 69#include "FrameView.h" 70#include "HTMLDocument.h" 71#include "HTMLIFrameElement.h" 72#include "HTMLInputElement.h" 73#include "HTMLNames.h" 74#include "HTMLOptionElement.h" 75#include "HTMLProgressElement.h" 76#include "HTMLStyleElement.h" 77#include "HTMLTextAreaElement.h" 78#include "InsertionPoint.h" 79#include "InspectorInstrumentation.h" 80#include "KeyframeList.h" 81#include "LinkHash.h" 82#include "LocaleToScriptMapping.h" 83#include "MathMLNames.h" 84#include "MediaList.h" 85#include "MediaQueryEvaluator.h" 86#include "NodeRenderStyle.h" 87#include "NodeRenderingContext.h" 88#include "Page.h" 89#include "PageRuleCollector.h" 90#include "Pair.h" 91#include "QuotesData.h" 92#include "Rect.h" 93#include "RenderRegion.h" 94#include "RenderScrollbar.h" 95#include "RenderScrollbarTheme.h" 96#include "RenderStyleConstants.h" 97#include "RenderTheme.h" 98#include "RenderView.h" 99#include "RuleSet.h" 100#include "SVGDocumentExtensions.h" 101#include "SVGFontFaceElement.h" 102#include "SecurityOrigin.h" 103#include "SelectorCheckerFastPath.h" 104#include "Settings.h" 105#include "ShadowData.h" 106#include "ShadowRoot.h" 107#include "ShadowValue.h" 108#include "StyleCachedImage.h" 109#include "StyleGeneratedImage.h" 110#include "StylePendingImage.h" 111#include "StylePropertySet.h" 112#include "StylePropertyShorthand.h" 113#include "StyleRule.h" 114#include "StyleRuleImport.h" 115#include "StyleSheetContents.h" 116#include "StyleSheetList.h" 117#include "Text.h" 118#include "TransformFunctions.h" 119#include "TransformOperations.h" 120#include "UserAgentStyleSheets.h" 121#include "ViewportStyleResolver.h" 122#include "VisitedLinkState.h" 123#include "WebKitCSSKeyframeRule.h" 124#include "WebKitCSSKeyframesRule.h" 125#include "WebKitCSSRegionRule.h" 126#include "WebKitCSSTransformValue.h" 127#include "WebKitFontFamilyNames.h" 128#include "XMLNames.h" 129#include <wtf/StdLibExtras.h> 130#include <wtf/Vector.h> 131 132#if ENABLE(CSS_FILTERS) 133#include "FilterOperation.h" 134#include "WebKitCSSFilterValue.h" 135#endif 136 137#if ENABLE(DASHBOARD_SUPPORT) 138#include "DashboardRegion.h" 139#endif 140 141#if ENABLE(SVG) 142#include "CachedSVGDocument.h" 143#include "CachedSVGDocumentReference.h" 144#include "SVGDocument.h" 145#include "SVGElement.h" 146#include "SVGNames.h" 147#include "SVGURIReference.h" 148#include "WebKitCSSSVGDocumentValue.h" 149#endif 150 151#if ENABLE(CSS_SHADERS) 152#include "CustomFilterArrayParameter.h" 153#include "CustomFilterColorParameter.h" 154#include "CustomFilterConstants.h" 155#include "CustomFilterNumberParameter.h" 156#include "CustomFilterOperation.h" 157#include "CustomFilterParameter.h" 158#include "CustomFilterProgramInfo.h" 159#include "CustomFilterTransformParameter.h" 160#include "StyleCachedShader.h" 161#include "StyleCustomFilterProgram.h" 162#include "StyleCustomFilterProgramCache.h" 163#include "StylePendingShader.h" 164#include "StyleShader.h" 165#include "WebKitCSSMixFunctionValue.h" 166#include "WebKitCSSShaderValue.h" 167#endif 168 169#if ENABLE(CSS_IMAGE_SET) 170#include "CSSImageSetValue.h" 171#include "StyleCachedImageSet.h" 172#endif 173 174#if ENABLE(VIDEO_TRACK) 175#include "WebVTTElement.h" 176#endif 177 178using namespace std; 179 180namespace WebCore { 181 182using namespace HTMLNames; 183 184#define HANDLE_INHERIT(prop, Prop) \ 185if (isInherit) { \ 186 m_state.style()->set##Prop(m_state.parentStyle()->prop()); \ 187 return; \ 188} 189 190#define HANDLE_INHERIT_AND_INITIAL(prop, Prop) \ 191HANDLE_INHERIT(prop, Prop) \ 192if (isInitial) { \ 193 m_state.style()->set##Prop(RenderStyle::initial##Prop()); \ 194 return; \ 195} 196 197RenderStyle* StyleResolver::s_styleNotYetAvailable; 198 199inline void StyleResolver::State::cacheBorderAndBackground() 200{ 201 m_hasUAAppearance = m_style->hasAppearance(); 202 if (m_hasUAAppearance) { 203 m_borderData = m_style->border(); 204 m_backgroundData = *m_style->backgroundLayers(); 205 m_backgroundColor = m_style->backgroundColor(); 206 } 207} 208 209inline void StyleResolver::State::clear() 210{ 211 m_element = 0; 212 m_styledElement = 0; 213 m_parentStyle = 0; 214 m_parentNode = 0; 215 m_regionForStyling = 0; 216 m_pendingImageProperties.clear(); 217#if ENABLE(CSS_SHADERS) 218 m_hasPendingShaders = false; 219#endif 220#if ENABLE(CSS_FILTERS) && ENABLE(SVG) 221 m_pendingSVGDocuments.clear(); 222#endif 223} 224 225void StyleResolver::MatchResult::addMatchedProperties(const StylePropertySet* properties, StyleRule* rule, unsigned linkMatchType, PropertyWhitelistType propertyWhitelistType) 226{ 227 matchedProperties.grow(matchedProperties.size() + 1); 228 StyleResolver::MatchedProperties& newProperties = matchedProperties.last(); 229 newProperties.properties = const_cast<StylePropertySet*>(properties); 230 newProperties.linkMatchType = linkMatchType; 231 newProperties.whitelistType = propertyWhitelistType; 232 matchedRules.append(rule); 233} 234 235StyleResolver::StyleResolver(Document* document, bool matchAuthorAndUserStyles) 236 : m_matchedPropertiesCacheAdditionsSinceLastSweep(0) 237 , m_matchedPropertiesCacheSweepTimer(this, &StyleResolver::sweepMatchedPropertiesCache) 238 , m_document(document) 239 , m_matchAuthorAndUserStyles(matchAuthorAndUserStyles) 240 , m_fontSelector(CSSFontSelector::create(document)) 241#if ENABLE(CSS_DEVICE_ADAPTATION) 242 , m_viewportStyleResolver(ViewportStyleResolver::create(document)) 243#endif 244 , m_deprecatedStyleBuilder(DeprecatedStyleBuilder::sharedStyleBuilder()) 245 , m_styleMap(this) 246{ 247 Element* root = document->documentElement(); 248 249 CSSDefaultStyleSheets::initDefaultStyle(root); 250 251 // construct document root element default style. this is needed 252 // to evaluate media queries that contain relative constraints, like "screen and (max-width: 10em)" 253 // This is here instead of constructor, because when constructor is run, 254 // document doesn't have documentElement 255 // NOTE: this assumes that element that gets passed to styleForElement -call 256 // is always from the document that owns the style selector 257 FrameView* view = document->view(); 258 if (view) 259 m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType())); 260 else 261 m_medium = adoptPtr(new MediaQueryEvaluator("all")); 262 263 if (root) 264 m_rootDefaultStyle = styleForElement(root, 0, DisallowStyleSharing, MatchOnlyUserAgentRules); 265 266 if (m_rootDefaultStyle && view) 267 m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType(), view->frame(), m_rootDefaultStyle.get())); 268 269 m_ruleSets.resetAuthorStyle(); 270 271 DocumentStyleSheetCollection* styleSheetCollection = document->styleSheetCollection(); 272 m_ruleSets.initUserStyle(styleSheetCollection, *m_medium, *this); 273 274#if ENABLE(SVG_FONTS) 275 if (document->svgExtensions()) { 276 const HashSet<SVGFontFaceElement*>& svgFontFaceElements = document->svgExtensions()->svgFontFaceElements(); 277 HashSet<SVGFontFaceElement*>::const_iterator end = svgFontFaceElements.end(); 278 for (HashSet<SVGFontFaceElement*>::const_iterator it = svgFontFaceElements.begin(); it != end; ++it) 279 fontSelector()->addFontFaceRule((*it)->fontFaceRule()); 280 } 281#endif 282 283 appendAuthorStyleSheets(0, styleSheetCollection->activeAuthorStyleSheets()); 284} 285 286void StyleResolver::appendAuthorStyleSheets(unsigned firstNew, const Vector<RefPtr<CSSStyleSheet> >& styleSheets) 287{ 288 m_ruleSets.appendAuthorStyleSheets(firstNew, styleSheets, m_medium.get(), m_inspectorCSSOMWrappers, document()->isViewSource(), this); 289 if (document()->renderer() && document()->renderer()->style()) 290 document()->renderer()->style()->font().update(fontSelector()); 291 292#if ENABLE(CSS_DEVICE_ADAPTATION) 293 viewportStyleResolver()->resolve(); 294#endif 295} 296 297void StyleResolver::pushParentElement(Element* parent) 298{ 299 const ContainerNode* parentsParent = parent->parentOrShadowHostElement(); 300 301 // We are not always invoked consistently. For example, script execution can cause us to enter 302 // style recalc in the middle of tree building. We may also be invoked from somewhere within the tree. 303 // Reset the stack in this case, or if we see a new root element. 304 // Otherwise just push the new parent. 305 if (!parentsParent || m_selectorFilter.parentStackIsEmpty()) 306 m_selectorFilter.setupParentStack(parent); 307 else 308 m_selectorFilter.pushParent(parent); 309 310 // Note: We mustn't skip ShadowRoot nodes for the scope stack. 311 if (m_scopeResolver) 312 m_scopeResolver->push(parent, parent->parentOrShadowHostNode()); 313} 314 315void StyleResolver::popParentElement(Element* parent) 316{ 317 // Note that we may get invoked for some random elements in some wacky cases during style resolve. 318 // Pause maintaining the stack in this case. 319 if (m_selectorFilter.parentStackIsConsistent(parent)) 320 m_selectorFilter.popParent(); 321 if (m_scopeResolver) 322 m_scopeResolver->pop(parent); 323} 324 325void StyleResolver::pushParentShadowRoot(const ShadowRoot* shadowRoot) 326{ 327 ASSERT(shadowRoot->host()); 328 if (m_scopeResolver) 329 m_scopeResolver->push(shadowRoot, shadowRoot->host()); 330} 331 332void StyleResolver::popParentShadowRoot(const ShadowRoot* shadowRoot) 333{ 334 ASSERT(shadowRoot->host()); 335 if (m_scopeResolver) 336 m_scopeResolver->pop(shadowRoot); 337} 338 339// This is a simplified style setting function for keyframe styles 340void StyleResolver::addKeyframeStyle(PassRefPtr<StyleRuleKeyframes> rule) 341{ 342 AtomicString s(rule->name()); 343 m_keyframesRuleMap.set(s.impl(), rule); 344} 345 346StyleResolver::~StyleResolver() 347{ 348 m_fontSelector->clearDocument(); 349 350#if ENABLE(CSS_DEVICE_ADAPTATION) 351 m_viewportStyleResolver->clearDocument(); 352#endif 353} 354 355void StyleResolver::sweepMatchedPropertiesCache(Timer<StyleResolver>*) 356{ 357 // Look for cache entries containing a style declaration with a single ref and remove them. 358 // This may happen when an element attribute mutation causes it to generate a new inlineStyle() 359 // or presentationAttributeStyle(), potentially leaving this cache with the last ref on the old one. 360 Vector<unsigned, 16> toRemove; 361 MatchedPropertiesCache::iterator it = m_matchedPropertiesCache.begin(); 362 MatchedPropertiesCache::iterator end = m_matchedPropertiesCache.end(); 363 for (; it != end; ++it) { 364 Vector<MatchedProperties>& matchedProperties = it->value.matchedProperties; 365 for (size_t i = 0; i < matchedProperties.size(); ++i) { 366 if (matchedProperties[i].properties->hasOneRef()) { 367 toRemove.append(it->key); 368 break; 369 } 370 } 371 } 372 for (size_t i = 0; i < toRemove.size(); ++i) 373 m_matchedPropertiesCache.remove(toRemove[i]); 374 375 m_matchedPropertiesCacheAdditionsSinceLastSweep = 0; 376} 377 378inline bool StyleResolver::styleSharingCandidateMatchesHostRules() 379{ 380#if ENABLE(SHADOW_DOM) 381 return m_scopeResolver && m_scopeResolver->styleSharingCandidateMatchesHostRules(m_state.element()); 382#else 383 return false; 384#endif 385} 386 387bool StyleResolver::classNamesAffectedByRules(const SpaceSplitString& classNames) const 388{ 389 for (unsigned i = 0; i < classNames.size(); ++i) { 390 if (m_ruleSets.features().classesInRules.contains(classNames[i].impl())) 391 return true; 392 } 393 return false; 394} 395 396inline void StyleResolver::State::initElement(Element* e) 397{ 398 m_element = e; 399 m_styledElement = e && e->isStyledElement() ? static_cast<StyledElement*>(e) : 0; 400 m_elementLinkState = e ? e->document()->visitedLinkState()->determineLinkState(e) : NotInsideLink; 401} 402 403inline void StyleResolver::initElement(Element* e) 404{ 405 if (m_state.element() != e) { 406 m_state.initElement(e); 407 if (e && e == e->document()->documentElement()) { 408 e->document()->setDirectionSetOnDocumentElement(false); 409 e->document()->setWritingModeSetOnDocumentElement(false); 410 } 411 } 412} 413 414inline void StyleResolver::State::initForStyleResolve(Document* document, Element* e, RenderStyle* parentStyle, RenderRegion* regionForStyling) 415{ 416 m_regionForStyling = regionForStyling; 417 418 if (e) { 419 NodeRenderingContext context(e); 420 m_parentNode = context.parentNodeForRenderingAndStyle(); 421 m_parentStyle = context.resetStyleInheritance() ? 0 : 422 parentStyle ? parentStyle : 423 m_parentNode ? m_parentNode->renderStyle() : 0; 424 m_distributedToInsertionPoint = context.insertionPoint(); 425 } else { 426 m_parentNode = 0; 427 m_parentStyle = parentStyle; 428 m_distributedToInsertionPoint = false; 429 } 430 431 Node* docElement = e ? e->document()->documentElement() : 0; 432 RenderStyle* docStyle = document->renderStyle(); 433 m_rootElementStyle = docElement && e != docElement ? docElement->renderStyle() : docStyle; 434 435 m_style = 0; 436 m_pendingImageProperties.clear(); 437 m_fontDirty = false; 438} 439 440static const unsigned cStyleSearchThreshold = 10; 441static const unsigned cStyleSearchLevelThreshold = 10; 442 443static inline bool parentElementPreventsSharing(const Element* parentElement) 444{ 445 if (!parentElement) 446 return false; 447 return parentElement->hasFlagsSetDuringStylingOfChildren(); 448} 449 450Node* StyleResolver::locateCousinList(Element* parent, unsigned& visitedNodeCount) const 451{ 452 if (visitedNodeCount >= cStyleSearchThreshold * cStyleSearchLevelThreshold) 453 return 0; 454 if (!parent || !parent->isStyledElement()) 455 return 0; 456 if (parent->hasScopedHTMLStyleChild()) 457 return 0; 458 StyledElement* p = static_cast<StyledElement*>(parent); 459 if (p->inlineStyle()) 460 return 0; 461#if ENABLE(SVG) 462 if (p->isSVGElement() && toSVGElement(p)->animatedSMILStyleProperties()) 463 return 0; 464#endif 465 if (p->hasID() && m_ruleSets.features().idsInRules.contains(p->idForStyleResolution().impl())) 466 return 0; 467 468 RenderStyle* parentStyle = p->renderStyle(); 469 unsigned subcount = 0; 470 Node* thisCousin = p; 471 Node* currentNode = p->previousSibling(); 472 473 // Reserve the tries for this level. This effectively makes sure that the algorithm 474 // will never go deeper than cStyleSearchLevelThreshold levels into recursion. 475 visitedNodeCount += cStyleSearchThreshold; 476 while (thisCousin) { 477 while (currentNode) { 478 ++subcount; 479 if (currentNode->renderStyle() == parentStyle && currentNode->lastChild() 480 && currentNode->isElementNode() && !parentElementPreventsSharing(toElement(currentNode)) 481#if ENABLE(SHADOW_DOM) 482 && !toElement(currentNode)->shadow() 483#endif 484 ) { 485 // Adjust for unused reserved tries. 486 visitedNodeCount -= cStyleSearchThreshold - subcount; 487 return currentNode->lastChild(); 488 } 489 if (subcount >= cStyleSearchThreshold) 490 return 0; 491 currentNode = currentNode->previousSibling(); 492 } 493 currentNode = locateCousinList(thisCousin->parentElement(), visitedNodeCount); 494 thisCousin = currentNode; 495 } 496 497 return 0; 498} 499 500bool StyleResolver::styleSharingCandidateMatchesRuleSet(RuleSet* ruleSet) 501{ 502 if (!ruleSet) 503 return false; 504 505 ElementRuleCollector collector(this, m_state); 506 return collector.hasAnyMatchingRules(ruleSet); 507} 508 509bool StyleResolver::canShareStyleWithControl(StyledElement* element) const 510{ 511 const State& state = m_state; 512 HTMLInputElement* thisInputElement = element->toInputElement(); 513 HTMLInputElement* otherInputElement = state.element()->toInputElement(); 514 515 if (!thisInputElement || !otherInputElement) 516 return false; 517 518 if (thisInputElement->elementData() != otherInputElement->elementData()) { 519 if (thisInputElement->fastGetAttribute(typeAttr) != otherInputElement->fastGetAttribute(typeAttr)) 520 return false; 521 if (thisInputElement->fastGetAttribute(readonlyAttr) != otherInputElement->fastGetAttribute(readonlyAttr)) 522 return false; 523 } 524 525 if (thisInputElement->isAutofilled() != otherInputElement->isAutofilled()) 526 return false; 527 if (thisInputElement->shouldAppearChecked() != otherInputElement->shouldAppearChecked()) 528 return false; 529 if (thisInputElement->shouldAppearIndeterminate() != otherInputElement->shouldAppearIndeterminate()) 530 return false; 531 if (thisInputElement->isRequired() != otherInputElement->isRequired()) 532 return false; 533 534 if (element->isDisabledFormControl() != state.element()->isDisabledFormControl()) 535 return false; 536 537 if (element->isDefaultButtonForForm() != state.element()->isDefaultButtonForForm()) 538 return false; 539 540 if (state.document()->containsValidityStyleRules()) { 541 bool willValidate = element->willValidate(); 542 543 if (willValidate != state.element()->willValidate()) 544 return false; 545 546 if (willValidate && (element->isValidFormControlElement() != state.element()->isValidFormControlElement())) 547 return false; 548 549 if (element->isInRange() != state.element()->isInRange()) 550 return false; 551 552 if (element->isOutOfRange() != state.element()->isOutOfRange()) 553 return false; 554 } 555 556 return true; 557} 558 559static inline bool elementHasDirectionAuto(Element* element) 560{ 561 // FIXME: This line is surprisingly hot, we may wish to inline hasDirectionAuto into StyleResolver. 562 return element->isHTMLElement() && toHTMLElement(element)->hasDirectionAuto(); 563} 564 565bool StyleResolver::sharingCandidateHasIdenticalStyleAffectingAttributes(StyledElement* sharingCandidate) const 566{ 567 const State& state = m_state; 568 if (state.element()->elementData() == sharingCandidate->elementData()) 569 return true; 570 if (state.element()->fastGetAttribute(XMLNames::langAttr) != sharingCandidate->fastGetAttribute(XMLNames::langAttr)) 571 return false; 572 if (state.element()->fastGetAttribute(langAttr) != sharingCandidate->fastGetAttribute(langAttr)) 573 return false; 574 575 if (!state.elementAffectedByClassRules()) { 576 if (sharingCandidate->hasClass() && classNamesAffectedByRules(sharingCandidate->classNames())) 577 return false; 578 } else if (sharingCandidate->hasClass()) { 579#if ENABLE(SVG) 580 // SVG elements require a (slow!) getAttribute comparision because "class" is an animatable attribute for SVG. 581 if (state.element()->isSVGElement()) { 582 if (state.element()->getAttribute(classAttr) != sharingCandidate->getAttribute(classAttr)) 583 return false; 584 } else { 585#endif 586 if (state.element()->classNames() != sharingCandidate->classNames()) 587 return false; 588#if ENABLE(SVG) 589 } 590#endif 591 } else 592 return false; 593 594 if (state.styledElement()->presentationAttributeStyle() != sharingCandidate->presentationAttributeStyle()) 595 return false; 596 597#if ENABLE(PROGRESS_ELEMENT) 598 if (state.element()->hasTagName(progressTag)) { 599 if (state.element()->shouldAppearIndeterminate() != sharingCandidate->shouldAppearIndeterminate()) 600 return false; 601 } 602#endif 603 604 return true; 605} 606 607bool StyleResolver::canShareStyleWithElement(StyledElement* element) const 608{ 609 RenderStyle* style = element->renderStyle(); 610 const State& state = m_state; 611 612 if (!style) 613 return false; 614 if (style->unique()) 615 return false; 616 if (style->hasUniquePseudoStyle()) 617 return false; 618 if (element->tagQName() != state.element()->tagQName()) 619 return false; 620 if (element->inlineStyle()) 621 return false; 622 if (element->needsStyleRecalc()) 623 return false; 624#if ENABLE(SVG) 625 if (element->isSVGElement() && toSVGElement(element)->animatedSMILStyleProperties()) 626 return false; 627#endif 628 if (element->isLink() != state.element()->isLink()) 629 return false; 630 if (element->hovered() != state.element()->hovered()) 631 return false; 632 if (element->active() != state.element()->active()) 633 return false; 634 if (element->focused() != state.element()->focused()) 635 return false; 636 if (element->shadowPseudoId() != state.element()->shadowPseudoId()) 637 return false; 638 if (element == element->document()->cssTarget()) 639 return false; 640 if (!sharingCandidateHasIdenticalStyleAffectingAttributes(element)) 641 return false; 642 if (element->additionalPresentationAttributeStyle() != state.styledElement()->additionalPresentationAttributeStyle()) 643 return false; 644 645 if (element->hasID() && m_ruleSets.features().idsInRules.contains(element->idForStyleResolution().impl())) 646 return false; 647 if (element->hasScopedHTMLStyleChild()) 648 return false; 649 650 // FIXME: We should share style for option and optgroup whenever possible. 651 // Before doing so, we need to resolve issues in HTMLSelectElement::recalcListItems 652 // and RenderMenuList::setText. See also https://bugs.webkit.org/show_bug.cgi?id=88405 653 if (element->hasTagName(optionTag) || element->hasTagName(optgroupTag)) 654 return false; 655 656 bool isControl = element->isFormControlElement(); 657 658 if (isControl != state.element()->isFormControlElement()) 659 return false; 660 661 if (isControl && !canShareStyleWithControl(element)) 662 return false; 663 664 if (style->transitions() || style->animations()) 665 return false; 666 667#if USE(ACCELERATED_COMPOSITING) 668 // Turn off style sharing for elements that can gain layers for reasons outside of the style system. 669 // See comments in RenderObject::setStyle(). 670 if (element->hasTagName(iframeTag) || element->hasTagName(frameTag) || element->hasTagName(embedTag) || element->hasTagName(objectTag) || element->hasTagName(appletTag) || element->hasTagName(canvasTag) 671#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) 672 // With proxying, the media elements are backed by a RenderEmbeddedObject. 673 || element->hasTagName(videoTag) || element->hasTagName(audioTag) 674#endif 675 ) 676 return false; 677#endif 678 679 if (elementHasDirectionAuto(element)) 680 return false; 681 682 if (element->isLink() && state.elementLinkState() != style->insideLink()) 683 return false; 684 685#if ENABLE(VIDEO_TRACK) 686 // Deny sharing styles between WebVTT and non-WebVTT nodes. 687 if (element->isWebVTTElement() != state.element()->isWebVTTElement()) 688 return false; 689 690 if (element->isWebVTTElement() && state.element()->isWebVTTElement() && toWebVTTElement(element)->isPastNode() != toWebVTTElement(state.element())->isPastNode()) 691 return false; 692#endif 693 694#if ENABLE(FULLSCREEN_API) 695 if (element == element->document()->webkitCurrentFullScreenElement() || state.element() == state.document()->webkitCurrentFullScreenElement()) 696 return false; 697#endif 698 return true; 699} 700 701inline StyledElement* StyleResolver::findSiblingForStyleSharing(Node* node, unsigned& count) const 702{ 703 for (; node; node = node->previousSibling()) { 704 if (!node->isStyledElement()) 705 continue; 706 if (canShareStyleWithElement(static_cast<StyledElement*>(node))) 707 break; 708 if (count++ == cStyleSearchThreshold) 709 return 0; 710 } 711 return static_cast<StyledElement*>(node); 712} 713 714RenderStyle* StyleResolver::locateSharedStyle() 715{ 716 State& state = m_state; 717 if (!state.styledElement() || !state.parentStyle()) 718 return 0; 719 720 // If the element has inline style it is probably unique. 721 if (state.styledElement()->inlineStyle()) 722 return 0; 723#if ENABLE(SVG) 724 if (state.styledElement()->isSVGElement() && toSVGElement(state.styledElement())->animatedSMILStyleProperties()) 725 return 0; 726#endif 727 // Ids stop style sharing if they show up in the stylesheets. 728 if (state.styledElement()->hasID() && m_ruleSets.features().idsInRules.contains(state.styledElement()->idForStyleResolution().impl())) 729 return 0; 730 if (parentElementPreventsSharing(state.element()->parentElement())) 731 return 0; 732 if (state.styledElement()->hasScopedHTMLStyleChild()) 733 return 0; 734 if (state.element() == state.document()->cssTarget()) 735 return 0; 736 if (elementHasDirectionAuto(state.element())) 737 return 0; 738 739 // Cache whether state.element is affected by any known class selectors. 740 // FIXME: This shouldn't be a member variable. The style sharing code could be factored out of StyleResolver. 741 state.setElementAffectedByClassRules(state.element() && state.element()->hasClass() && classNamesAffectedByRules(state.element()->classNames())); 742 743 // Check previous siblings and their cousins. 744 unsigned count = 0; 745 unsigned visitedNodeCount = 0; 746 StyledElement* shareElement = 0; 747 Node* cousinList = state.styledElement()->previousSibling(); 748 while (cousinList) { 749 shareElement = findSiblingForStyleSharing(cousinList, count); 750 if (shareElement) 751 break; 752 cousinList = locateCousinList(cousinList->parentElement(), visitedNodeCount); 753 } 754 755 // If we have exhausted all our budget or our cousins. 756 if (!shareElement) 757 return 0; 758 759 // Can't share if sibling rules apply. This is checked at the end as it should rarely fail. 760 if (styleSharingCandidateMatchesRuleSet(m_ruleSets.sibling())) 761 return 0; 762 // Can't share if attribute rules apply. 763 if (styleSharingCandidateMatchesRuleSet(m_ruleSets.uncommonAttribute())) 764 return 0; 765 // Can't share if @host @-rules apply. 766 if (styleSharingCandidateMatchesHostRules()) 767 return 0; 768 // Tracking child index requires unique style for each node. This may get set by the sibling rule match above. 769 if (parentElementPreventsSharing(state.element()->parentElement())) 770 return 0; 771 return shareElement->renderStyle(); 772} 773 774static void getFontAndGlyphOrientation(const RenderStyle* style, FontOrientation& fontOrientation, NonCJKGlyphOrientation& glyphOrientation) 775{ 776 if (style->isHorizontalWritingMode()) { 777 fontOrientation = Horizontal; 778 glyphOrientation = NonCJKGlyphOrientationVerticalRight; 779 return; 780 } 781 782 switch (style->textOrientation()) { 783 case TextOrientationVerticalRight: 784 fontOrientation = Vertical; 785 glyphOrientation = NonCJKGlyphOrientationVerticalRight; 786 return; 787 case TextOrientationUpright: 788 fontOrientation = Vertical; 789 glyphOrientation = NonCJKGlyphOrientationUpright; 790 return; 791 case TextOrientationSideways: 792 if (style->writingMode() == LeftToRightWritingMode) { 793 // FIXME: This should map to sideways-left, which is not supported yet. 794 fontOrientation = Vertical; 795 glyphOrientation = NonCJKGlyphOrientationVerticalRight; 796 return; 797 } 798 fontOrientation = Horizontal; 799 glyphOrientation = NonCJKGlyphOrientationVerticalRight; 800 return; 801 case TextOrientationSidewaysRight: 802 fontOrientation = Horizontal; 803 glyphOrientation = NonCJKGlyphOrientationVerticalRight; 804 return; 805 default: 806 ASSERT_NOT_REACHED(); 807 fontOrientation = Horizontal; 808 glyphOrientation = NonCJKGlyphOrientationVerticalRight; 809 return; 810 } 811} 812 813PassRefPtr<RenderStyle> StyleResolver::styleForDocument(Document* document, CSSFontSelector* fontSelector) 814{ 815 Frame* frame = document->frame(); 816 817 // HTML5 states that seamless iframes should replace default CSS values 818 // with values inherited from the containing iframe element. However, 819 // some values (such as the case of designMode = "on") still need to 820 // be set by this "document style". 821 RefPtr<RenderStyle> documentStyle = RenderStyle::create(); 822 bool seamlessWithParent = document->shouldDisplaySeamlesslyWithParent(); 823 if (seamlessWithParent) { 824 RenderStyle* iframeStyle = document->seamlessParentIFrame()->renderStyle(); 825 if (iframeStyle) 826 documentStyle->inheritFrom(iframeStyle); 827 } 828 829 // FIXME: It's not clear which values below we want to override in the seamless case! 830 documentStyle->setDisplay(BLOCK); 831 if (!seamlessWithParent) { 832 documentStyle->setRTLOrdering(document->visuallyOrdered() ? VisualOrder : LogicalOrder); 833 documentStyle->setZoom(frame && !document->printing() ? frame->pageZoomFactor() : 1); 834 documentStyle->setPageScaleTransform(frame ? frame->frameScaleFactor() : 1); 835 documentStyle->setLocale(document->contentLanguage()); 836 } 837 // This overrides any -webkit-user-modify inherited from the parent iframe. 838 documentStyle->setUserModify(document->inDesignMode() ? READ_WRITE : READ_ONLY); 839 840 Element* docElement = document->documentElement(); 841 RenderObject* docElementRenderer = docElement ? docElement->renderer() : 0; 842 if (docElementRenderer) { 843 // Use the direction and writing-mode of the body to set the 844 // viewport's direction and writing-mode unless the property is set on the document element. 845 // If there is no body, then use the document element. 846 RenderObject* bodyRenderer = document->body() ? document->body()->renderer() : 0; 847 if (bodyRenderer && !document->writingModeSetOnDocumentElement()) 848 documentStyle->setWritingMode(bodyRenderer->style()->writingMode()); 849 else 850 documentStyle->setWritingMode(docElementRenderer->style()->writingMode()); 851 if (bodyRenderer && !document->directionSetOnDocumentElement()) 852 documentStyle->setDirection(bodyRenderer->style()->direction()); 853 else 854 documentStyle->setDirection(docElementRenderer->style()->direction()); 855 } 856 857 if (frame) { 858 if (FrameView* frameView = frame->view()) { 859 const Pagination& pagination = frameView->pagination(); 860 if (pagination.mode != Pagination::Unpaginated) { 861 documentStyle->setColumnStylesFromPaginationMode(pagination.mode); 862 documentStyle->setColumnGap(pagination.gap); 863 if (RenderView* view = document->renderView()) { 864 if (view->hasColumns()) 865 view->updateColumnInfoFromStyle(documentStyle.get()); 866 } 867 } 868 } 869 } 870 871 // Seamless iframes want to inherit their font from their parent iframe, so early return before setting the font. 872 if (seamlessWithParent) 873 return documentStyle.release(); 874 875 FontDescription fontDescription; 876 fontDescription.setScript(localeToScriptCodeForFontSelection(documentStyle->locale())); 877 if (Settings* settings = document->settings()) { 878 fontDescription.setUsePrinterFont(document->printing() || !settings->screenFontSubstitutionEnabled()); 879 fontDescription.setRenderingMode(settings->fontRenderingMode()); 880 const AtomicString& standardFont = settings->standardFontFamily(fontDescription.script()); 881 if (!standardFont.isEmpty()) { 882 fontDescription.setGenericFamily(FontDescription::StandardFamily); 883 fontDescription.setOneFamily(standardFont); 884 } 885 fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1); 886 int size = StyleResolver::fontSizeForKeyword(document, CSSValueMedium, false); 887 fontDescription.setSpecifiedSize(size); 888 bool useSVGZoomRules = document->isSVGDocument(); 889 fontDescription.setComputedSize(StyleResolver::getComputedSizeFromSpecifiedSize(document, documentStyle.get(), fontDescription.isAbsoluteSize(), size, useSVGZoomRules)); 890 } else 891 fontDescription.setUsePrinterFont(document->printing()); 892 893 FontOrientation fontOrientation; 894 NonCJKGlyphOrientation glyphOrientation; 895 getFontAndGlyphOrientation(documentStyle.get(), fontOrientation, glyphOrientation); 896 fontDescription.setOrientation(fontOrientation); 897 fontDescription.setNonCJKGlyphOrientation(glyphOrientation); 898 899 documentStyle->setFontDescription(fontDescription); 900 documentStyle->font().update(fontSelector); 901 902 return documentStyle.release(); 903} 904 905static inline bool isAtShadowBoundary(const Element* element) 906{ 907 if (!element) 908 return false; 909 ContainerNode* parentNode = element->parentNode(); 910 return parentNode && parentNode->isShadowRoot(); 911} 912 913PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderStyle* defaultParent, 914 StyleSharingBehavior sharingBehavior, RuleMatchingBehavior matchingBehavior, RenderRegion* regionForStyling) 915{ 916 // Once an element has a renderer, we don't try to destroy it, since otherwise the renderer 917 // will vanish if a style recalc happens during loading. 918 if (sharingBehavior == AllowStyleSharing && !element->document()->haveStylesheetsLoaded() && !element->renderer()) { 919 if (!s_styleNotYetAvailable) { 920 s_styleNotYetAvailable = RenderStyle::create().leakRef(); 921 s_styleNotYetAvailable->setDisplay(NONE); 922 s_styleNotYetAvailable->font().update(m_fontSelector); 923 } 924 element->document()->setHasNodesWithPlaceholderStyle(); 925 return s_styleNotYetAvailable; 926 } 927 928 State& state = m_state; 929 initElement(element); 930 state.initForStyleResolve(document(), element, defaultParent, regionForStyling); 931 if (sharingBehavior == AllowStyleSharing && !state.distributedToInsertionPoint()) { 932 RenderStyle* sharedStyle = locateSharedStyle(); 933 if (sharedStyle) { 934 state.clear(); 935 return sharedStyle; 936 } 937 } 938 939 if (state.parentStyle()) { 940 state.setStyle(RenderStyle::create()); 941 state.style()->inheritFrom(state.parentStyle(), isAtShadowBoundary(element) ? RenderStyle::AtShadowBoundary : RenderStyle::NotAtShadowBoundary); 942 } else { 943 state.setStyle(defaultStyleForElement()); 944 state.setParentStyle(RenderStyle::clone(state.style())); 945 } 946 // contenteditable attribute (implemented by -webkit-user-modify) should 947 // be propagated from shadow host to distributed node. 948 if (state.distributedToInsertionPoint()) { 949 if (Element* parent = element->parentElement()) { 950 if (RenderStyle* styleOfShadowHost = parent->renderStyle()) 951 state.style()->setUserModify(styleOfShadowHost->userModify()); 952 } 953 } 954 955 if (element->isLink()) { 956 state.style()->setIsLink(true); 957 EInsideLink linkState = state.elementLinkState(); 958 if (linkState != NotInsideLink) { 959 bool forceVisited = InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoVisited); 960 if (forceVisited) 961 linkState = InsideVisitedLink; 962 } 963 state.style()->setInsideLink(linkState); 964 } 965 966 bool needsCollection = false; 967 CSSDefaultStyleSheets::ensureDefaultStyleSheetsForElement(element, needsCollection); 968 if (needsCollection) 969 m_ruleSets.collectFeatures(document()->isViewSource(), m_scopeResolver.get()); 970 971 ElementRuleCollector collector(this, state); 972 collector.setRegionForStyling(regionForStyling); 973 collector.setMedium(m_medium.get()); 974 975 if (matchingBehavior == MatchOnlyUserAgentRules) 976 collector.matchUARules(); 977 else 978 collector.matchAllRules(m_matchAuthorAndUserStyles, matchingBehavior != MatchAllRulesExcludingSMIL); 979 980 applyMatchedProperties(collector.matchedResult(), element); 981 982 // Clean up our style object's display and text decorations (among other fixups). 983 adjustRenderStyle(state.style(), state.parentStyle(), element); 984 985 state.clear(); // Clear out for the next resolve. 986 987 document()->didAccessStyleResolver(); 988 989 // Now return the style. 990 return state.takeStyle(); 991} 992 993PassRefPtr<RenderStyle> StyleResolver::styleForKeyframe(const RenderStyle* elementStyle, const StyleKeyframe* keyframe, KeyframeValue& keyframeValue) 994{ 995 MatchResult result; 996 if (keyframe->properties()) 997 result.addMatchedProperties(keyframe->properties()); 998 999 ASSERT(!m_state.style()); 1000 1001 State& state = m_state; 1002 1003 // Create the style 1004 state.setStyle(RenderStyle::clone(elementStyle)); 1005 state.setLineHeightValue(0); 1006 1007 // We don't need to bother with !important. Since there is only ever one 1008 // decl, there's nothing to override. So just add the first properties. 1009 bool inheritedOnly = false; 1010 if (keyframe->properties()) 1011 applyMatchedProperties<HighPriorityProperties>(result, false, 0, result.matchedProperties.size() - 1, inheritedOnly); 1012 1013 // If our font got dirtied, go ahead and update it now. 1014 updateFont(); 1015 1016 // Line-height is set when we are sure we decided on the font-size 1017 if (state.lineHeightValue()) 1018 applyProperty(CSSPropertyLineHeight, state.lineHeightValue()); 1019 1020 // Now do rest of the properties. 1021 if (keyframe->properties()) 1022 applyMatchedProperties<LowPriorityProperties>(result, false, 0, result.matchedProperties.size() - 1, inheritedOnly); 1023 1024 // If our font got dirtied by one of the non-essential font props, 1025 // go ahead and update it a second time. 1026 updateFont(); 1027 1028 // Start loading resources referenced by this style. 1029 loadPendingResources(); 1030 1031 // Add all the animating properties to the keyframe. 1032 if (const StylePropertySet* styleDeclaration = keyframe->properties()) { 1033 unsigned propertyCount = styleDeclaration->propertyCount(); 1034 for (unsigned i = 0; i < propertyCount; ++i) { 1035 CSSPropertyID property = styleDeclaration->propertyAt(i).id(); 1036 // Timing-function within keyframes is special, because it is not animated; it just 1037 // describes the timing function between this keyframe and the next. 1038 if (property != CSSPropertyWebkitAnimationTimingFunction) 1039 keyframeValue.addProperty(property); 1040 } 1041 } 1042 1043 document()->didAccessStyleResolver(); 1044 1045 return state.takeStyle(); 1046} 1047 1048void StyleResolver::keyframeStylesForAnimation(Element* e, const RenderStyle* elementStyle, KeyframeList& list) 1049{ 1050 list.clear(); 1051 1052 // Get the keyframesRule for this name 1053 if (!e || list.animationName().isEmpty()) 1054 return; 1055 1056 m_keyframesRuleMap.checkConsistency(); 1057 1058 KeyframesRuleMap::iterator it = m_keyframesRuleMap.find(list.animationName().impl()); 1059 if (it == m_keyframesRuleMap.end()) 1060 return; 1061 1062 const StyleRuleKeyframes* keyframesRule = it->value.get(); 1063 1064 // Construct and populate the style for each keyframe 1065 const Vector<RefPtr<StyleKeyframe> >& keyframes = keyframesRule->keyframes(); 1066 for (unsigned i = 0; i < keyframes.size(); ++i) { 1067 // Apply the declaration to the style. This is a simplified version of the logic in styleForElement 1068 initElement(e); 1069 m_state.initForStyleResolve(document(), e); 1070 1071 const StyleKeyframe* keyframe = keyframes[i].get(); 1072 1073 KeyframeValue keyframeValue(0, 0); 1074 keyframeValue.setStyle(styleForKeyframe(elementStyle, keyframe, keyframeValue)); 1075 1076 // Add this keyframe style to all the indicated key times 1077 Vector<float> keys; 1078 keyframe->getKeys(keys); 1079 for (size_t keyIndex = 0; keyIndex < keys.size(); ++keyIndex) { 1080 keyframeValue.setKey(keys[keyIndex]); 1081 list.insert(keyframeValue); 1082 } 1083 } 1084 1085 // If the 0% keyframe is missing, create it (but only if there is at least one other keyframe) 1086 int initialListSize = list.size(); 1087 if (initialListSize > 0 && list[0].key()) { 1088 static StyleKeyframe* zeroPercentKeyframe; 1089 if (!zeroPercentKeyframe) { 1090 zeroPercentKeyframe = StyleKeyframe::create().leakRef(); 1091 zeroPercentKeyframe->setKeyText("0%"); 1092 } 1093 KeyframeValue keyframeValue(0, 0); 1094 keyframeValue.setStyle(styleForKeyframe(elementStyle, zeroPercentKeyframe, keyframeValue)); 1095 list.insert(keyframeValue); 1096 } 1097 1098 // If the 100% keyframe is missing, create it (but only if there is at least one other keyframe) 1099 if (initialListSize > 0 && (list[list.size() - 1].key() != 1)) { 1100 static StyleKeyframe* hundredPercentKeyframe; 1101 if (!hundredPercentKeyframe) { 1102 hundredPercentKeyframe = StyleKeyframe::create().leakRef(); 1103 hundredPercentKeyframe->setKeyText("100%"); 1104 } 1105 KeyframeValue keyframeValue(1, 0); 1106 keyframeValue.setStyle(styleForKeyframe(elementStyle, hundredPercentKeyframe, keyframeValue)); 1107 list.insert(keyframeValue); 1108 } 1109} 1110 1111PassRefPtr<RenderStyle> StyleResolver::pseudoStyleForElement(Element* e, const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle) 1112{ 1113 ASSERT(parentStyle); 1114 if (!e) 1115 return 0; 1116 1117 State& state = m_state; 1118 1119 initElement(e); 1120 1121 state.initForStyleResolve(document(), e, parentStyle); 1122 1123 if (m_state.parentStyle()) { 1124 state.setStyle(RenderStyle::create()); 1125 state.style()->inheritFrom(m_state.parentStyle()); 1126 } else { 1127 state.setStyle(defaultStyleForElement()); 1128 state.setParentStyle(RenderStyle::clone(state.style())); 1129 } 1130 1131 // Since we don't use pseudo-elements in any of our quirk/print user agent rules, don't waste time walking 1132 // those rules. 1133 1134 // Check UA, user and author rules. 1135 ElementRuleCollector collector(this, state); 1136 collector.setPseudoStyleRequest(pseudoStyleRequest); 1137 collector.setMedium(m_medium.get()); 1138 collector.matchUARules(); 1139 1140 if (m_matchAuthorAndUserStyles) { 1141 collector.matchUserRules(false); 1142 collector.matchAuthorRules(false); 1143 } 1144 1145 if (collector.matchedResult().matchedProperties.isEmpty()) 1146 return 0; 1147 1148 state.style()->setStyleType(pseudoStyleRequest.pseudoId); 1149 1150 applyMatchedProperties(collector.matchedResult(), e); 1151 1152 // Clean up our style object's display and text decorations (among other fixups). 1153 adjustRenderStyle(state.style(), m_state.parentStyle(), 0); 1154 1155 // Start loading resources referenced by this style. 1156 loadPendingResources(); 1157 1158 document()->didAccessStyleResolver(); 1159 1160 // Now return the style. 1161 return state.takeStyle(); 1162} 1163 1164PassRefPtr<RenderStyle> StyleResolver::styleForPage(int pageIndex) 1165{ 1166 m_state.initForStyleResolve(document(), document()->documentElement()); // m_rootElementStyle will be set to the document style. 1167 1168 m_state.setStyle(RenderStyle::create()); 1169 m_state.style()->inheritFrom(m_state.rootElementStyle()); 1170 1171 PageRuleCollector collector(m_state, m_ruleSets); 1172 collector.matchAllPageRules(pageIndex); 1173 m_state.setLineHeightValue(0); 1174 bool inheritedOnly = false; 1175 1176 MatchResult& result = collector.matchedResult(); 1177#if ENABLE(CSS_VARIABLES) 1178 applyMatchedProperties<VariableDefinitions>(result, false, 0, result.matchedProperties.size() - 1, inheritedOnly); 1179#endif 1180 applyMatchedProperties<HighPriorityProperties>(result, false, 0, result.matchedProperties.size() - 1, inheritedOnly); 1181 1182 // If our font got dirtied, go ahead and update it now. 1183 updateFont(); 1184 1185 // Line-height is set when we are sure we decided on the font-size. 1186 if (m_state.lineHeightValue()) 1187 applyProperty(CSSPropertyLineHeight, m_state.lineHeightValue()); 1188 1189 applyMatchedProperties<LowPriorityProperties>(result, false, 0, result.matchedProperties.size() - 1, inheritedOnly); 1190 1191 // Start loading resources referenced by this style. 1192 loadPendingResources(); 1193 1194 document()->didAccessStyleResolver(); 1195 1196 // Now return the style. 1197 return m_state.takeStyle(); 1198} 1199 1200PassRefPtr<RenderStyle> StyleResolver::defaultStyleForElement() 1201{ 1202 m_state.setStyle(RenderStyle::create()); 1203 // Make sure our fonts are initialized if we don't inherit them from our parent style. 1204 if (Settings* settings = documentSettings()) { 1205 initializeFontStyle(settings); 1206 m_state.style()->font().update(fontSelector()); 1207 } else 1208 m_state.style()->font().update(0); 1209 1210 return m_state.takeStyle(); 1211} 1212 1213PassRefPtr<RenderStyle> StyleResolver::styleForText(Text* textNode) 1214{ 1215 ASSERT(textNode); 1216 1217 NodeRenderingContext context(textNode); 1218 Node* parentNode = context.parentNodeForRenderingAndStyle(); 1219 return context.resetStyleInheritance() || !parentNode || !parentNode->renderStyle() ? 1220 defaultStyleForElement() : parentNode->renderStyle(); 1221} 1222 1223static void addIntrinsicMargins(RenderStyle* style) 1224{ 1225 // Intrinsic margin value. 1226 const int intrinsicMargin = 2 * style->effectiveZoom(); 1227 1228 // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed. 1229 // FIXME: Using "quirk" to decide the margin wasn't set is kind of lame. 1230 if (style->width().isIntrinsicOrAuto()) { 1231 if (style->marginLeft().quirk()) 1232 style->setMarginLeft(Length(intrinsicMargin, Fixed)); 1233 if (style->marginRight().quirk()) 1234 style->setMarginRight(Length(intrinsicMargin, Fixed)); 1235 } 1236 1237 if (style->height().isAuto()) { 1238 if (style->marginTop().quirk()) 1239 style->setMarginTop(Length(intrinsicMargin, Fixed)); 1240 if (style->marginBottom().quirk()) 1241 style->setMarginBottom(Length(intrinsicMargin, Fixed)); 1242 } 1243} 1244 1245static EDisplay equivalentBlockDisplay(EDisplay display, bool isFloating, bool strictParsing) 1246{ 1247 switch (display) { 1248 case BLOCK: 1249 case TABLE: 1250 case BOX: 1251 case FLEX: 1252 case GRID: 1253 return display; 1254 1255 case LIST_ITEM: 1256 // It is a WinIE bug that floated list items lose their bullets, so we'll emulate the quirk, but only in quirks mode. 1257 if (!strictParsing && isFloating) 1258 return BLOCK; 1259 return display; 1260 case INLINE_TABLE: 1261 return TABLE; 1262 case INLINE_BOX: 1263 return BOX; 1264 case INLINE_FLEX: 1265 return FLEX; 1266 case INLINE_GRID: 1267 return GRID; 1268 1269 case INLINE: 1270 case RUN_IN: 1271 case COMPACT: 1272 case INLINE_BLOCK: 1273 case TABLE_ROW_GROUP: 1274 case TABLE_HEADER_GROUP: 1275 case TABLE_FOOTER_GROUP: 1276 case TABLE_ROW: 1277 case TABLE_COLUMN_GROUP: 1278 case TABLE_COLUMN: 1279 case TABLE_CELL: 1280 case TABLE_CAPTION: 1281 return BLOCK; 1282 case NONE: 1283 ASSERT_NOT_REACHED(); 1284 return NONE; 1285 } 1286 ASSERT_NOT_REACHED(); 1287 return BLOCK; 1288} 1289 1290// CSS requires text-decoration to be reset at each DOM element for tables, 1291// inline blocks, inline tables, run-ins, shadow DOM crossings, floating elements, 1292// and absolute or relatively positioned elements. 1293static bool doesNotInheritTextDecoration(RenderStyle* style, Element* e) 1294{ 1295 return style->display() == TABLE || style->display() == INLINE_TABLE || style->display() == RUN_IN 1296 || style->display() == INLINE_BLOCK || style->display() == INLINE_BOX || isAtShadowBoundary(e) 1297 || style->isFloating() || style->hasOutOfFlowPosition(); 1298} 1299 1300static bool isDisplayFlexibleBox(EDisplay display) 1301{ 1302 return display == FLEX || display == INLINE_FLEX; 1303} 1304 1305void StyleResolver::adjustRenderStyle(RenderStyle* style, RenderStyle* parentStyle, Element *e) 1306{ 1307 ASSERT(parentStyle); 1308 1309 // Cache our original display. 1310 style->setOriginalDisplay(style->display()); 1311 1312 if (style->display() != NONE) { 1313 // If we have a <td> that specifies a float property, in quirks mode we just drop the float 1314 // property. 1315 // Sites also commonly use display:inline/block on <td>s and <table>s. In quirks mode we force 1316 // these tags to retain their display types. 1317 if (document()->inQuirksMode() && e) { 1318 if (e->hasTagName(tdTag)) { 1319 style->setDisplay(TABLE_CELL); 1320 style->setFloating(NoFloat); 1321 } else if (e->hasTagName(tableTag)) 1322 style->setDisplay(style->isDisplayInlineType() ? INLINE_TABLE : TABLE); 1323 } 1324 1325 if (e && (e->hasTagName(tdTag) || e->hasTagName(thTag))) { 1326 if (style->whiteSpace() == KHTML_NOWRAP) { 1327 // Figure out if we are really nowrapping or if we should just 1328 // use normal instead. If the width of the cell is fixed, then 1329 // we don't actually use NOWRAP. 1330 if (style->width().isFixed()) 1331 style->setWhiteSpace(NORMAL); 1332 else 1333 style->setWhiteSpace(NOWRAP); 1334 } 1335 } 1336 1337 // Tables never support the -webkit-* values for text-align and will reset back to the default. 1338 if (e && e->hasTagName(tableTag) && (style->textAlign() == WEBKIT_LEFT || style->textAlign() == WEBKIT_CENTER || style->textAlign() == WEBKIT_RIGHT)) 1339 style->setTextAlign(TASTART); 1340 1341 // Frames and framesets never honor position:relative or position:absolute. This is necessary to 1342 // fix a crash where a site tries to position these objects. They also never honor display. 1343 if (e && (e->hasTagName(frameTag) || e->hasTagName(framesetTag))) { 1344 style->setPosition(StaticPosition); 1345 style->setDisplay(BLOCK); 1346 } 1347 1348 // Ruby text does not support float or position. This might change with evolution of the specification. 1349 if (e && e->hasTagName(rtTag)) { 1350 style->setPosition(StaticPosition); 1351 style->setFloating(NoFloat); 1352 } 1353 1354 // FIXME: We shouldn't be overriding start/-webkit-auto like this. Do it in html.css instead. 1355 // Table headers with a text-align of -webkit-auto will change the text-align to center. 1356 if (e && e->hasTagName(thTag) && style->textAlign() == TASTART) 1357 style->setTextAlign(CENTER); 1358 1359 if (e && e->hasTagName(legendTag)) 1360 style->setDisplay(BLOCK); 1361 1362 // Absolute/fixed positioned elements, floating elements and the document element need block-like outside display. 1363 if (style->hasOutOfFlowPosition() || style->isFloating() || (e && e->document()->documentElement() == e)) 1364 style->setDisplay(equivalentBlockDisplay(style->display(), style->isFloating(), !document()->inQuirksMode())); 1365 1366 // FIXME: Don't support this mutation for pseudo styles like first-letter or first-line, since it's not completely 1367 // clear how that should work. 1368 if (style->display() == INLINE && style->styleType() == NOPSEUDO && style->writingMode() != parentStyle->writingMode()) 1369 style->setDisplay(INLINE_BLOCK); 1370 1371 // After performing the display mutation, check table rows. We do not honor position:relative or position:sticky on 1372 // table rows or cells. This has been established for position:relative in CSS2.1 (and caused a crash in containingBlock() 1373 // on some sites). 1374 if ((style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_ROW_GROUP 1375 || style->display() == TABLE_FOOTER_GROUP || style->display() == TABLE_ROW) 1376 && style->hasInFlowPosition()) 1377 style->setPosition(StaticPosition); 1378 1379 // writing-mode does not apply to table row groups, table column groups, table rows, and table columns. 1380 // FIXME: Table cells should be allowed to be perpendicular or flipped with respect to the table, though. 1381 if (style->display() == TABLE_COLUMN || style->display() == TABLE_COLUMN_GROUP || style->display() == TABLE_FOOTER_GROUP 1382 || style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_ROW || style->display() == TABLE_ROW_GROUP 1383 || style->display() == TABLE_CELL) 1384 style->setWritingMode(parentStyle->writingMode()); 1385 1386 // FIXME: Since we don't support block-flow on flexible boxes yet, disallow setting 1387 // of block-flow to anything other than TopToBottomWritingMode. 1388 // https://bugs.webkit.org/show_bug.cgi?id=46418 - Flexible box support. 1389 if (style->writingMode() != TopToBottomWritingMode && (style->display() == BOX || style->display() == INLINE_BOX)) 1390 style->setWritingMode(TopToBottomWritingMode); 1391 1392 if (isDisplayFlexibleBox(parentStyle->display())) { 1393 style->setFloating(NoFloat); 1394 style->setDisplay(equivalentBlockDisplay(style->display(), style->isFloating(), !document()->inQuirksMode())); 1395 } 1396 1397#if ENABLE(DIALOG_ELEMENT) 1398 // Per the spec, position 'static' and 'relative' in the top layer compute to 'absolute'. 1399 if (e && e->isInTopLayer() && (style->position() == StaticPosition || style->position() == RelativePosition)) { 1400 style->setPosition(AbsolutePosition); 1401 style->setDisplay(BLOCK); 1402 } 1403#endif 1404 } 1405 1406 // Make sure our z-index value is only applied if the object is positioned. 1407 if (style->position() == StaticPosition && !isDisplayFlexibleBox(parentStyle->display())) 1408 style->setHasAutoZIndex(); 1409 1410 // Auto z-index becomes 0 for the root element and transparent objects. This prevents 1411 // cases where objects that should be blended as a single unit end up with a non-transparent 1412 // object wedged in between them. Auto z-index also becomes 0 for objects that specify transforms/masks/reflections. 1413 if (style->hasAutoZIndex() && ((e && e->document()->documentElement() == e) 1414 || style->opacity() < 1.0f 1415 || style->hasTransformRelatedProperty() 1416 || style->hasMask() 1417 || style->clipPath() 1418 || style->boxReflect() 1419 || style->hasFilter() 1420 || style->hasBlendMode() 1421 || style->position() == StickyPosition 1422 || (style->position() == FixedPosition && e && e->document()->page() && e->document()->page()->settings()->fixedPositionCreatesStackingContext()) 1423#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING) 1424 // Touch overflow scrolling creates a stacking context. 1425 || ((style->overflowX() != OHIDDEN || style->overflowY() != OHIDDEN) && style->useTouchOverflowScrolling()) 1426#endif 1427#if ENABLE(DIALOG_ELEMENT) 1428 || (e && e->isInTopLayer()) 1429#endif 1430 )) 1431 style->setZIndex(0); 1432 1433 // Textarea considers overflow visible as auto. 1434 if (e && e->hasTagName(textareaTag)) { 1435 style->setOverflowX(style->overflowX() == OVISIBLE ? OAUTO : style->overflowX()); 1436 style->setOverflowY(style->overflowY() == OVISIBLE ? OAUTO : style->overflowY()); 1437 } 1438 1439 if (doesNotInheritTextDecoration(style, e)) 1440 style->setTextDecorationsInEffect(style->textDecoration()); 1441 else 1442 style->addToTextDecorationsInEffect(style->textDecoration()); 1443 1444 // If either overflow value is not visible, change to auto. 1445 if (style->overflowX() == OMARQUEE && style->overflowY() != OMARQUEE) 1446 style->setOverflowY(OMARQUEE); 1447 else if (style->overflowY() == OMARQUEE && style->overflowX() != OMARQUEE) 1448 style->setOverflowX(OMARQUEE); 1449 else if (style->overflowX() == OVISIBLE && style->overflowY() != OVISIBLE) { 1450 // FIXME: Once we implement pagination controls, overflow-x should default to hidden 1451 // if overflow-y is set to -webkit-paged-x or -webkit-page-y. For now, we'll let it 1452 // default to auto so we can at least scroll through the pages. 1453 style->setOverflowX(OAUTO); 1454 } else if (style->overflowY() == OVISIBLE && style->overflowX() != OVISIBLE) 1455 style->setOverflowY(OAUTO); 1456 1457 // Call setStylesForPaginationMode() if a pagination mode is set for any non-root elements. If these 1458 // styles are specified on a root element, then they will be incorporated in 1459 // StyleResolver::styleForDocument(). 1460 if ((style->overflowY() == OPAGEDX || style->overflowY() == OPAGEDY) && !(e && (e->hasTagName(htmlTag) || e->hasTagName(bodyTag)))) 1461 style->setColumnStylesFromPaginationMode(WebCore::paginationModeForRenderStyle(style)); 1462 1463 // Table rows, sections and the table itself will support overflow:hidden and will ignore scroll/auto. 1464 // FIXME: Eventually table sections will support auto and scroll. 1465 if (style->display() == TABLE || style->display() == INLINE_TABLE 1466 || style->display() == TABLE_ROW_GROUP || style->display() == TABLE_ROW) { 1467 if (style->overflowX() != OVISIBLE && style->overflowX() != OHIDDEN) 1468 style->setOverflowX(OVISIBLE); 1469 if (style->overflowY() != OVISIBLE && style->overflowY() != OHIDDEN) 1470 style->setOverflowY(OVISIBLE); 1471 } 1472 1473 // Menulists should have visible overflow 1474 if (style->appearance() == MenulistPart) { 1475 style->setOverflowX(OVISIBLE); 1476 style->setOverflowY(OVISIBLE); 1477 } 1478 1479 // Cull out any useless layers and also repeat patterns into additional layers. 1480 style->adjustBackgroundLayers(); 1481 style->adjustMaskLayers(); 1482 1483 // Do the same for animations and transitions. 1484 style->adjustAnimations(); 1485 style->adjustTransitions(); 1486 1487 // Important: Intrinsic margins get added to controls before the theme has adjusted the style, since the theme will 1488 // alter fonts and heights/widths. 1489 if (e && e->isFormControlElement() && style->fontSize() >= 11) { 1490 // Don't apply intrinsic margins to image buttons. The designer knows how big the images are, 1491 // so we have to treat all image buttons as though they were explicitly sized. 1492 if (!e->hasTagName(inputTag) || !static_cast<HTMLInputElement*>(e)->isImageButton()) 1493 addIntrinsicMargins(style); 1494 } 1495 1496 // Let the theme also have a crack at adjusting the style. 1497 if (style->hasAppearance()) 1498 RenderTheme::defaultTheme()->adjustStyle(this, style, e, m_state.hasUAAppearance(), m_state.borderData(), m_state.backgroundData(), m_state.backgroundColor()); 1499 1500 // If we have first-letter pseudo style, do not share this style. 1501 if (style->hasPseudoStyle(FIRST_LETTER)) 1502 style->setUnique(); 1503 1504 // FIXME: when dropping the -webkit prefix on transform-style, we should also have opacity < 1 cause flattening. 1505 if (style->preserves3D() && (style->overflowX() != OVISIBLE 1506 || style->overflowY() != OVISIBLE 1507 || style->hasFilter())) 1508 style->setTransformStyle3D(TransformStyle3DFlat); 1509 1510 // Seamless iframes behave like blocks. Map their display to inline-block when marked inline. 1511 if (e && e->hasTagName(iframeTag) && style->display() == INLINE && toHTMLIFrameElement(e)->shouldDisplaySeamlessly()) 1512 style->setDisplay(INLINE_BLOCK); 1513 1514#if ENABLE(SVG) 1515 if (e && e->isSVGElement()) { 1516 // Spec: http://www.w3.org/TR/SVG/masking.html#OverflowProperty 1517 if (style->overflowY() == OSCROLL) 1518 style->setOverflowY(OHIDDEN); 1519 else if (style->overflowY() == OAUTO) 1520 style->setOverflowY(OVISIBLE); 1521 1522 if (style->overflowX() == OSCROLL) 1523 style->setOverflowX(OHIDDEN); 1524 else if (style->overflowX() == OAUTO) 1525 style->setOverflowX(OVISIBLE); 1526 1527 // Only the root <svg> element in an SVG document fragment tree honors css position 1528 if (!(e->hasTagName(SVGNames::svgTag) && e->parentNode() && !e->parentNode()->isSVGElement())) 1529 style->setPosition(RenderStyle::initialPosition()); 1530 1531 // RenderSVGRoot handles zooming for the whole SVG subtree, so foreignObject content should 1532 // not be scaled again. 1533 if (e->hasTagName(SVGNames::foreignObjectTag)) 1534 style->setEffectiveZoom(RenderStyle::initialZoom()); 1535 } 1536#endif 1537} 1538 1539bool StyleResolver::checkRegionStyle(Element* regionElement) 1540{ 1541 // FIXME (BUG 72472): We don't add @-webkit-region rules of scoped style sheets for the moment, 1542 // so all region rules are global by default. Verify whether that can stand or needs changing. 1543 1544 unsigned rulesSize = m_ruleSets.authorStyle()->m_regionSelectorsAndRuleSets.size(); 1545 for (unsigned i = 0; i < rulesSize; ++i) { 1546 ASSERT(m_ruleSets.authorStyle()->m_regionSelectorsAndRuleSets.at(i).ruleSet.get()); 1547 if (checkRegionSelector(m_ruleSets.authorStyle()->m_regionSelectorsAndRuleSets.at(i).selector, regionElement)) 1548 return true; 1549 } 1550 1551 if (m_ruleSets.userStyle()) { 1552 rulesSize = m_ruleSets.userStyle()->m_regionSelectorsAndRuleSets.size(); 1553 for (unsigned i = 0; i < rulesSize; ++i) { 1554 ASSERT(m_ruleSets.userStyle()->m_regionSelectorsAndRuleSets.at(i).ruleSet.get()); 1555 if (checkRegionSelector(m_ruleSets.userStyle()->m_regionSelectorsAndRuleSets.at(i).selector, regionElement)) 1556 return true; 1557 } 1558 } 1559 1560 return false; 1561} 1562 1563static void checkForOrientationChange(RenderStyle* style) 1564{ 1565 FontOrientation fontOrientation; 1566 NonCJKGlyphOrientation glyphOrientation; 1567 getFontAndGlyphOrientation(style, fontOrientation, glyphOrientation); 1568 1569 const FontDescription& fontDescription = style->fontDescription(); 1570 if (fontDescription.orientation() == fontOrientation && fontDescription.nonCJKGlyphOrientation() == glyphOrientation) 1571 return; 1572 1573 FontDescription newFontDescription(fontDescription); 1574 newFontDescription.setNonCJKGlyphOrientation(glyphOrientation); 1575 newFontDescription.setOrientation(fontOrientation); 1576 style->setFontDescription(newFontDescription); 1577} 1578 1579void StyleResolver::updateFont() 1580{ 1581 if (!m_state.fontDirty()) 1582 return; 1583 1584 RenderStyle* style = m_state.style(); 1585 checkForGenericFamilyChange(style, m_state.parentStyle()); 1586 checkForZoomChange(style, m_state.parentStyle()); 1587 checkForOrientationChange(style); 1588 style->font().update(m_fontSelector); 1589 m_state.setFontDirty(false); 1590} 1591 1592Vector<RefPtr<StyleRuleBase> > StyleResolver::styleRulesForElement(Element* e, unsigned rulesToInclude) 1593{ 1594 return pseudoStyleRulesForElement(e, NOPSEUDO, rulesToInclude); 1595} 1596 1597Vector<RefPtr<StyleRuleBase> > StyleResolver::pseudoStyleRulesForElement(Element* e, PseudoId pseudoId, unsigned rulesToInclude) 1598{ 1599 if (!e || !e->document()->haveStylesheetsLoaded()) 1600 return Vector<RefPtr<StyleRuleBase> >(); 1601 1602 initElement(e); 1603 m_state.initForStyleResolve(document(), e, 0); 1604 1605 ElementRuleCollector collector(this, m_state); 1606 collector.setMode(SelectorChecker::CollectingRules); 1607 collector.setPseudoStyleRequest(PseudoStyleRequest(pseudoId)); 1608 collector.setMedium(m_medium.get()); 1609 1610 if (rulesToInclude & UAAndUserCSSRules) { 1611 // First we match rules from the user agent sheet. 1612 collector.matchUARules(); 1613 1614 // Now we check user sheet rules. 1615 if (m_matchAuthorAndUserStyles) 1616 collector.matchUserRules(rulesToInclude & EmptyCSSRules); 1617 } 1618 1619 if (m_matchAuthorAndUserStyles && (rulesToInclude & AuthorCSSRules)) { 1620 collector.setSameOriginOnly(!(rulesToInclude & CrossOriginCSSRules)); 1621 1622 // Check the rules in author sheets. 1623 collector.matchAuthorRules(rulesToInclude & EmptyCSSRules); 1624 } 1625 1626 return collector.matchedRuleList(); 1627} 1628 1629// ------------------------------------------------------------------------------------- 1630// this is mostly boring stuff on how to apply a certain rule to the renderstyle... 1631 1632Length StyleResolver::convertToIntLength(const CSSPrimitiveValue* primitiveValue, const RenderStyle* style, const RenderStyle* rootStyle, double multiplier) 1633{ 1634 return primitiveValue ? primitiveValue->convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion | FractionConversion | ViewportPercentageConversion>(style, rootStyle, multiplier) : Length(Undefined); 1635} 1636 1637Length StyleResolver::convertToFloatLength(const CSSPrimitiveValue* primitiveValue, const RenderStyle* style, const RenderStyle* rootStyle, double multiplier) 1638{ 1639 return primitiveValue ? primitiveValue->convertToLength<FixedFloatConversion | PercentConversion | CalculatedConversion | FractionConversion | ViewportPercentageConversion>(style, rootStyle, multiplier) : Length(Undefined); 1640} 1641 1642template <StyleResolver::StyleApplicationPass pass> 1643void StyleResolver::applyProperties(const StylePropertySet* properties, StyleRule* rule, bool isImportant, bool inheritedOnly, PropertyWhitelistType propertyWhitelistType) 1644{ 1645 ASSERT((propertyWhitelistType != PropertyWhitelistRegion) || m_state.regionForStyling()); 1646 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willProcessRule(document(), rule, this); 1647 1648 unsigned propertyCount = properties->propertyCount(); 1649 for (unsigned i = 0; i < propertyCount; ++i) { 1650 StylePropertySet::PropertyReference current = properties->propertyAt(i); 1651 if (isImportant != current.isImportant()) 1652 continue; 1653 if (inheritedOnly && !current.isInherited()) { 1654 // If the property value is explicitly inherited, we need to apply further non-inherited properties 1655 // as they might override the value inherited here. For this reason we don't allow declarations with 1656 // explicitly inherited properties to be cached. 1657 ASSERT(!current.value()->isInheritedValue()); 1658 continue; 1659 } 1660 CSSPropertyID property = current.id(); 1661 1662 if (propertyWhitelistType == PropertyWhitelistRegion && !StyleResolver::isValidRegionStyleProperty(property)) 1663 continue; 1664#if ENABLE(VIDEO_TRACK) 1665 if (propertyWhitelistType == PropertyWhitelistCue && !StyleResolver::isValidCueStyleProperty(property)) 1666 continue; 1667#endif 1668 switch (pass) { 1669#if ENABLE(CSS_VARIABLES) 1670 case VariableDefinitions: 1671 COMPILE_ASSERT(CSSPropertyVariable < firstCSSProperty, CSS_variable_is_before_first_property); 1672 if (property == CSSPropertyVariable) 1673 applyProperty(current.id(), current.value()); 1674 break; 1675#endif 1676 case HighPriorityProperties: 1677 COMPILE_ASSERT(firstCSSProperty == CSSPropertyColor, CSS_color_is_first_property); 1678 COMPILE_ASSERT(CSSPropertyZoom == CSSPropertyColor + 17, CSS_zoom_is_end_of_first_prop_range); 1679 COMPILE_ASSERT(CSSPropertyLineHeight == CSSPropertyZoom + 1, CSS_line_height_is_after_zoom); 1680#if ENABLE(CSS_VARIABLES) 1681 if (property == CSSPropertyVariable) 1682 continue; 1683#endif 1684 // give special priority to font-xxx, color properties, etc 1685 if (property < CSSPropertyLineHeight) 1686 applyProperty(current.id(), current.value()); 1687 // we apply line-height later 1688 else if (property == CSSPropertyLineHeight) 1689 m_state.setLineHeightValue(current.value()); 1690 break; 1691 case LowPriorityProperties: 1692 if (property > CSSPropertyLineHeight) 1693 applyProperty(current.id(), current.value()); 1694 } 1695 } 1696 InspectorInstrumentation::didProcessRule(cookie); 1697} 1698 1699template <StyleResolver::StyleApplicationPass pass> 1700void StyleResolver::applyMatchedProperties(const MatchResult& matchResult, bool isImportant, int startIndex, int endIndex, bool inheritedOnly) 1701{ 1702 if (startIndex == -1) 1703 return; 1704 1705 State& state = m_state; 1706 if (state.style()->insideLink() != NotInsideLink) { 1707 for (int i = startIndex; i <= endIndex; ++i) { 1708 const MatchedProperties& matchedProperties = matchResult.matchedProperties[i]; 1709 unsigned linkMatchType = matchedProperties.linkMatchType; 1710 // FIXME: It would be nicer to pass these as arguments but that requires changes in many places. 1711 state.setApplyPropertyToRegularStyle(linkMatchType & SelectorChecker::MatchLink); 1712 state.setApplyPropertyToVisitedLinkStyle(linkMatchType & SelectorChecker::MatchVisited); 1713 1714 applyProperties<pass>(matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType)); 1715 } 1716 state.setApplyPropertyToRegularStyle(true); 1717 state.setApplyPropertyToVisitedLinkStyle(false); 1718 return; 1719 } 1720 for (int i = startIndex; i <= endIndex; ++i) { 1721 const MatchedProperties& matchedProperties = matchResult.matchedProperties[i]; 1722 applyProperties<pass>(matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType)); 1723 } 1724} 1725 1726unsigned StyleResolver::computeMatchedPropertiesHash(const MatchedProperties* properties, unsigned size) 1727{ 1728 1729 return StringHasher::hashMemory(properties, sizeof(MatchedProperties) * size); 1730} 1731 1732bool operator==(const StyleResolver::MatchRanges& a, const StyleResolver::MatchRanges& b) 1733{ 1734 return a.firstUARule == b.firstUARule 1735 && a.lastUARule == b.lastUARule 1736 && a.firstAuthorRule == b.firstAuthorRule 1737 && a.lastAuthorRule == b.lastAuthorRule 1738 && a.firstUserRule == b.firstUserRule 1739 && a.lastUserRule == b.lastUserRule; 1740} 1741 1742bool operator!=(const StyleResolver::MatchRanges& a, const StyleResolver::MatchRanges& b) 1743{ 1744 return !(a == b); 1745} 1746 1747bool operator==(const StyleResolver::MatchedProperties& a, const StyleResolver::MatchedProperties& b) 1748{ 1749 return a.properties == b.properties && a.linkMatchType == b.linkMatchType; 1750} 1751 1752bool operator!=(const StyleResolver::MatchedProperties& a, const StyleResolver::MatchedProperties& b) 1753{ 1754 return !(a == b); 1755} 1756 1757const StyleResolver::MatchedPropertiesCacheItem* StyleResolver::findFromMatchedPropertiesCache(unsigned hash, const MatchResult& matchResult) 1758{ 1759 ASSERT(hash); 1760 1761 MatchedPropertiesCache::iterator it = m_matchedPropertiesCache.find(hash); 1762 if (it == m_matchedPropertiesCache.end()) 1763 return 0; 1764 MatchedPropertiesCacheItem& cacheItem = it->value; 1765 1766 size_t size = matchResult.matchedProperties.size(); 1767 if (size != cacheItem.matchedProperties.size()) 1768 return 0; 1769 for (size_t i = 0; i < size; ++i) { 1770 if (matchResult.matchedProperties[i] != cacheItem.matchedProperties[i]) 1771 return 0; 1772 } 1773 if (cacheItem.ranges != matchResult.ranges) 1774 return 0; 1775 return &cacheItem; 1776} 1777 1778void StyleResolver::addToMatchedPropertiesCache(const RenderStyle* style, const RenderStyle* parentStyle, unsigned hash, const MatchResult& matchResult) 1779{ 1780 static const unsigned matchedDeclarationCacheAdditionsBetweenSweeps = 100; 1781 if (++m_matchedPropertiesCacheAdditionsSinceLastSweep >= matchedDeclarationCacheAdditionsBetweenSweeps 1782 && !m_matchedPropertiesCacheSweepTimer.isActive()) { 1783 static const unsigned matchedDeclarationCacheSweepTimeInSeconds = 60; 1784 m_matchedPropertiesCacheSweepTimer.startOneShot(matchedDeclarationCacheSweepTimeInSeconds); 1785 } 1786 1787 ASSERT(hash); 1788 MatchedPropertiesCacheItem cacheItem; 1789 cacheItem.matchedProperties.appendVector(matchResult.matchedProperties); 1790 cacheItem.ranges = matchResult.ranges; 1791 // Note that we don't cache the original RenderStyle instance. It may be further modified. 1792 // The RenderStyle in the cache is really just a holder for the substructures and never used as-is. 1793 cacheItem.renderStyle = RenderStyle::clone(style); 1794 cacheItem.parentRenderStyle = RenderStyle::clone(parentStyle); 1795 m_matchedPropertiesCache.add(hash, cacheItem); 1796} 1797 1798void StyleResolver::invalidateMatchedPropertiesCache() 1799{ 1800 m_matchedPropertiesCache.clear(); 1801} 1802 1803static bool isCacheableInMatchedPropertiesCache(const Element* element, const RenderStyle* style, const RenderStyle* parentStyle) 1804{ 1805 // FIXME: CSSPropertyWebkitWritingMode modifies state when applying to document element. We can't skip the applying by caching. 1806 if (element == element->document()->documentElement() && element->document()->writingModeSetOnDocumentElement()) 1807 return false; 1808 if (style->unique() || (style->styleType() != NOPSEUDO && parentStyle->unique())) 1809 return false; 1810 if (style->hasAppearance()) 1811 return false; 1812 if (style->zoom() != RenderStyle::initialZoom()) 1813 return false; 1814 if (style->writingMode() != RenderStyle::initialWritingMode()) 1815 return false; 1816 // The cache assumes static knowledge about which properties are inherited. 1817 if (parentStyle->hasExplicitlyInheritedProperties()) 1818 return false; 1819 return true; 1820} 1821 1822void StyleResolver::applyMatchedProperties(const MatchResult& matchResult, const Element* element) 1823{ 1824 ASSERT(element); 1825 State& state = m_state; 1826 unsigned cacheHash = matchResult.isCacheable ? computeMatchedPropertiesHash(matchResult.matchedProperties.data(), matchResult.matchedProperties.size()) : 0; 1827 bool applyInheritedOnly = false; 1828 const MatchedPropertiesCacheItem* cacheItem = 0; 1829 if (cacheHash && (cacheItem = findFromMatchedPropertiesCache(cacheHash, matchResult))) { 1830 // We can build up the style by copying non-inherited properties from an earlier style object built using the same exact 1831 // style declarations. We then only need to apply the inherited properties, if any, as their values can depend on the 1832 // element context. This is fast and saves memory by reusing the style data structures. 1833 state.style()->copyNonInheritedFrom(cacheItem->renderStyle.get()); 1834 if (state.parentStyle()->inheritedDataShared(cacheItem->parentRenderStyle.get()) && !isAtShadowBoundary(element)) { 1835 EInsideLink linkStatus = state.style()->insideLink(); 1836 // If the cache item parent style has identical inherited properties to the current parent style then the 1837 // resulting style will be identical too. We copy the inherited properties over from the cache and are done. 1838 state.style()->inheritFrom(cacheItem->renderStyle.get()); 1839 1840 // Unfortunately the link status is treated like an inherited property. We need to explicitly restore it. 1841 state.style()->setInsideLink(linkStatus); 1842 return; 1843 } 1844 applyInheritedOnly = true; 1845 } 1846 1847#if ENABLE(CSS_VARIABLES) 1848 // First apply all variable definitions, as they may be used during application of later properties. 1849 applyMatchedProperties<VariableDefinitions>(matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly); 1850 applyMatchedProperties<VariableDefinitions>(matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly); 1851 applyMatchedProperties<VariableDefinitions>(matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly); 1852 applyMatchedProperties<VariableDefinitions>(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly); 1853#endif 1854 1855 // Now we have all of the matched rules in the appropriate order. Walk the rules and apply 1856 // high-priority properties first, i.e., those properties that other properties depend on. 1857 // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important 1858 // and (4) normal important. 1859 state.setLineHeightValue(0); 1860 applyMatchedProperties<HighPriorityProperties>(matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly); 1861 applyMatchedProperties<HighPriorityProperties>(matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly); 1862 applyMatchedProperties<HighPriorityProperties>(matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly); 1863 applyMatchedProperties<HighPriorityProperties>(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly); 1864 1865 if (cacheItem && cacheItem->renderStyle->effectiveZoom() != state.style()->effectiveZoom()) { 1866 state.setFontDirty(true); 1867 applyInheritedOnly = false; 1868 } 1869 1870 // If our font got dirtied, go ahead and update it now. 1871 updateFont(); 1872 1873 // Line-height is set when we are sure we decided on the font-size. 1874 if (state.lineHeightValue()) 1875 applyProperty(CSSPropertyLineHeight, state.lineHeightValue()); 1876 1877 // Many properties depend on the font. If it changes we just apply all properties. 1878 if (cacheItem && cacheItem->renderStyle->fontDescription() != state.style()->fontDescription()) 1879 applyInheritedOnly = false; 1880 1881 // Now do the normal priority UA properties. 1882 applyMatchedProperties<LowPriorityProperties>(matchResult, false, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly); 1883 1884 // Cache our border and background so that we can examine them later. 1885 state.cacheBorderAndBackground(); 1886 1887 // Now do the author and user normal priority properties and all the !important properties. 1888 applyMatchedProperties<LowPriorityProperties>(matchResult, false, matchResult.ranges.lastUARule + 1, matchResult.matchedProperties.size() - 1, applyInheritedOnly); 1889 applyMatchedProperties<LowPriorityProperties>(matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly); 1890 applyMatchedProperties<LowPriorityProperties>(matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly); 1891 applyMatchedProperties<LowPriorityProperties>(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly); 1892 1893 // Start loading resources referenced by this style. 1894 loadPendingResources(); 1895 1896 ASSERT(!state.fontDirty()); 1897 1898 if (cacheItem || !cacheHash) 1899 return; 1900 if (!isCacheableInMatchedPropertiesCache(state.element(), state.style(), state.parentStyle())) 1901 return; 1902 addToMatchedPropertiesCache(state.style(), state.parentStyle(), cacheHash, matchResult); 1903} 1904 1905void StyleResolver::applyPropertyToStyle(CSSPropertyID id, CSSValue* value, RenderStyle* style) 1906{ 1907 initElement(0); 1908 m_state.initForStyleResolve(document(), 0, style); 1909 m_state.setStyle(style); 1910 applyPropertyToCurrentStyle(id, value); 1911} 1912 1913void StyleResolver::applyPropertyToCurrentStyle(CSSPropertyID id, CSSValue* value) 1914{ 1915 if (value) 1916 applyProperty(id, value); 1917} 1918 1919inline bool isValidVisitedLinkProperty(CSSPropertyID id) 1920{ 1921 switch (id) { 1922 case CSSPropertyBackgroundColor: 1923 case CSSPropertyBorderLeftColor: 1924 case CSSPropertyBorderRightColor: 1925 case CSSPropertyBorderTopColor: 1926 case CSSPropertyBorderBottomColor: 1927 case CSSPropertyColor: 1928 case CSSPropertyOutlineColor: 1929 case CSSPropertyWebkitColumnRuleColor: 1930#if ENABLE(CSS3_TEXT) 1931 case CSSPropertyWebkitTextDecorationColor: 1932#endif // CSS3_TEXT 1933 case CSSPropertyWebkitTextEmphasisColor: 1934 case CSSPropertyWebkitTextFillColor: 1935 case CSSPropertyWebkitTextStrokeColor: 1936#if ENABLE(SVG) 1937 case CSSPropertyFill: 1938 case CSSPropertyStroke: 1939#endif 1940 return true; 1941 default: 1942 break; 1943 } 1944 1945 return false; 1946} 1947 1948// http://dev.w3.org/csswg/css3-regions/#the-at-region-style-rule 1949// FIXME: add incremental support for other region styling properties. 1950inline bool StyleResolver::isValidRegionStyleProperty(CSSPropertyID id) 1951{ 1952 switch (id) { 1953 case CSSPropertyBackgroundColor: 1954 case CSSPropertyColor: 1955 return true; 1956 default: 1957 break; 1958 } 1959 1960 return false; 1961} 1962 1963#if ENABLE(VIDEO_TRACK) 1964inline bool StyleResolver::isValidCueStyleProperty(CSSPropertyID id) 1965{ 1966 switch (id) { 1967 case CSSPropertyBackground: 1968 case CSSPropertyBackgroundAttachment: 1969 case CSSPropertyBackgroundClip: 1970 case CSSPropertyBackgroundColor: 1971 case CSSPropertyBackgroundImage: 1972 case CSSPropertyBackgroundOrigin: 1973 case CSSPropertyBackgroundPosition: 1974 case CSSPropertyBackgroundPositionX: 1975 case CSSPropertyBackgroundPositionY: 1976 case CSSPropertyBackgroundRepeat: 1977 case CSSPropertyBackgroundRepeatX: 1978 case CSSPropertyBackgroundRepeatY: 1979 case CSSPropertyBackgroundSize: 1980 case CSSPropertyColor: 1981 case CSSPropertyFont: 1982 case CSSPropertyFontFamily: 1983 case CSSPropertyFontSize: 1984 case CSSPropertyFontStyle: 1985 case CSSPropertyFontVariant: 1986 case CSSPropertyFontWeight: 1987 case CSSPropertyLineHeight: 1988 case CSSPropertyOpacity: 1989 case CSSPropertyOutline: 1990 case CSSPropertyOutlineColor: 1991 case CSSPropertyOutlineOffset: 1992 case CSSPropertyOutlineStyle: 1993 case CSSPropertyOutlineWidth: 1994 case CSSPropertyVisibility: 1995 case CSSPropertyWhiteSpace: 1996 case CSSPropertyTextDecoration: 1997 case CSSPropertyTextShadow: 1998 case CSSPropertyBorderStyle: 1999 return true; 2000 default: 2001 break; 2002 } 2003 return false; 2004} 2005#endif 2006// SVG handles zooming in a different way compared to CSS. The whole document is scaled instead 2007// of each individual length value in the render style / tree. CSSPrimitiveValue::computeLength*() 2008// multiplies each resolved length with the zoom multiplier - so for SVG we need to disable that. 2009// Though all CSS values that can be applied to outermost <svg> elements (width/height/border/padding...) 2010// need to respect the scaling. RenderBox (the parent class of RenderSVGRoot) grabs values like 2011// width/height/border/padding/... from the RenderStyle -> for SVG these values would never scale, 2012// if we'd pass a 1.0 zoom factor everyhwere. So we only pass a zoom factor of 1.0 for specific 2013// properties that are NOT allowed to scale within a zoomed SVG document (letter/word-spacing/font-size). 2014bool StyleResolver::useSVGZoomRules() 2015{ 2016 return m_state.element() && m_state.element()->isSVGElement(); 2017} 2018 2019static bool createGridTrackBreadth(CSSPrimitiveValue* primitiveValue, const StyleResolver::State& state, Length& workingLength) 2020{ 2021 if (primitiveValue->getIdent() == CSSValueWebkitMinContent) { 2022 workingLength = Length(MinContent); 2023 return true; 2024 } 2025 2026 if (primitiveValue->getIdent() == CSSValueWebkitMaxContent) { 2027 workingLength = Length(MaxContent); 2028 return true; 2029 } 2030 2031 workingLength = primitiveValue->convertToLength<FixedIntegerConversion | PercentConversion | ViewportPercentageConversion | AutoConversion>(state.style(), state.rootElementStyle(), state.style()->effectiveZoom()); 2032 if (workingLength.isUndefined()) 2033 return false; 2034 2035 if (primitiveValue->isLength()) 2036 workingLength.setQuirk(primitiveValue->isQuirkValue()); 2037 2038 return true; 2039} 2040 2041static bool createGridTrackSize(CSSValue* value, GridTrackSize& trackSize, const StyleResolver::State& state) 2042{ 2043 if (!value->isPrimitiveValue()) 2044 return false; 2045 2046 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); 2047 Pair* minMaxTrackBreadth = primitiveValue->getPairValue(); 2048 if (!minMaxTrackBreadth) { 2049 Length workingLength; 2050 if (!createGridTrackBreadth(primitiveValue, state, workingLength)) 2051 return false; 2052 2053 trackSize.setLength(workingLength); 2054 return true; 2055 } 2056 2057 Length minTrackBreadth; 2058 Length maxTrackBreadth; 2059 if (!createGridTrackBreadth(minMaxTrackBreadth->first(), state, minTrackBreadth) || !createGridTrackBreadth(minMaxTrackBreadth->second(), state, maxTrackBreadth)) 2060 return false; 2061 2062 trackSize.setMinMax(minTrackBreadth, maxTrackBreadth); 2063 return true; 2064} 2065 2066static bool createGridTrackList(CSSValue* value, Vector<GridTrackSize>& trackSizes, const StyleResolver::State& state) 2067{ 2068 // Handle 'none'. 2069 if (value->isPrimitiveValue()) { 2070 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); 2071 return primitiveValue->getIdent() == CSSValueNone; 2072 } 2073 2074 if (!value->isValueList()) 2075 return false; 2076 2077 for (CSSValueListIterator i = value; i.hasMore(); i.advance()) { 2078 CSSValue* currValue = i.value(); 2079 GridTrackSize trackSize; 2080 if (!createGridTrackSize(currValue, trackSize, state)) 2081 return false; 2082 2083 trackSizes.append(trackSize); 2084 } 2085 return true; 2086} 2087 2088 2089static bool createGridPosition(CSSValue* value, GridPosition& position) 2090{ 2091 // For now, we only accept: <integer> | 'auto' 2092 if (!value->isPrimitiveValue()) 2093 return false; 2094 2095 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); 2096 if (primitiveValue->getIdent() == CSSValueAuto) 2097 return true; 2098 2099 ASSERT_WITH_SECURITY_IMPLICATION(primitiveValue->isNumber()); 2100 position.setIntegerPosition(primitiveValue->getIntValue()); 2101 return true; 2102} 2103 2104#if ENABLE(CSS_VARIABLES) 2105static bool hasVariableReference(CSSValue* value) 2106{ 2107 if (value->isPrimitiveValue()) { 2108 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); 2109 return primitiveValue->hasVariableReference(); 2110 } 2111 2112 if (value->isCalculationValue()) 2113 return static_cast<CSSCalcValue*>(value)->hasVariableReference(); 2114 2115 if (value->isReflectValue()) { 2116 CSSReflectValue* reflectValue = static_cast<CSSReflectValue*>(value); 2117 CSSPrimitiveValue* direction = reflectValue->direction(); 2118 CSSPrimitiveValue* offset = reflectValue->offset(); 2119 CSSValue* mask = reflectValue->mask(); 2120 return (direction && hasVariableReference(direction)) || (offset && hasVariableReference(offset)) || (mask && hasVariableReference(mask)); 2121 } 2122 2123 for (CSSValueListIterator i = value; i.hasMore(); i.advance()) { 2124 if (hasVariableReference(i.value())) 2125 return true; 2126 } 2127 2128 return false; 2129} 2130 2131void StyleResolver::resolveVariables(CSSPropertyID id, CSSValue* value, Vector<std::pair<CSSPropertyID, String> >& knownExpressions) 2132{ 2133 std::pair<CSSPropertyID, String> expression(id, value->serializeResolvingVariables(*m_state.style()->variables())); 2134 2135 if (knownExpressions.contains(expression)) 2136 return; // cycle detected. 2137 2138 knownExpressions.append(expression); 2139 2140 // FIXME: It would be faster not to re-parse from strings, but for now CSS property validation lives inside the parser so we do it there. 2141 RefPtr<MutableStylePropertySet> resultSet = MutableStylePropertySet::create(); 2142 if (!CSSParser::parseValue(resultSet.get(), id, expression.second, false, document())) 2143 return; // expression failed to parse. 2144 2145 for (unsigned i = 0; i < resultSet->propertyCount(); i++) { 2146 StylePropertySet::PropertyReference property = resultSet->propertyAt(i); 2147 if (property.id() != CSSPropertyVariable && hasVariableReference(property.value())) 2148 resolveVariables(property.id(), property.value(), knownExpressions); 2149 else 2150 applyProperty(property.id(), property.value()); 2151 } 2152} 2153#endif 2154 2155void StyleResolver::applyProperty(CSSPropertyID id, CSSValue* value) 2156{ 2157#if ENABLE(CSS_VARIABLES) 2158 if (id != CSSPropertyVariable && hasVariableReference(value)) { 2159 Vector<std::pair<CSSPropertyID, String> > knownExpressions; 2160 resolveVariables(id, value, knownExpressions); 2161 return; 2162 } 2163#endif 2164 2165 // CSS variables don't resolve shorthands at parsing time, so this should be *after* handling variables. 2166 ASSERT_WITH_MESSAGE(!isExpandedShorthand(id), "Shorthand property id = %d wasn't expanded at parsing time", id); 2167 2168 State& state = m_state; 2169 bool isInherit = state.parentNode() && value->isInheritedValue(); 2170 bool isInitial = value->isInitialValue() || (!state.parentNode() && value->isInheritedValue()); 2171 2172 ASSERT(!isInherit || !isInitial); // isInherit -> !isInitial && isInitial -> !isInherit 2173 ASSERT(!isInherit || (state.parentNode() && state.parentStyle())); // isInherit -> (state.parentNode() && state.parentStyle()) 2174 2175 if (!state.applyPropertyToRegularStyle() && (!state.applyPropertyToVisitedLinkStyle() || !isValidVisitedLinkProperty(id))) { 2176 // Limit the properties that can be applied to only the ones honored by :visited. 2177 return; 2178 } 2179 2180 if (isInherit && !state.parentStyle()->hasExplicitlyInheritedProperties() && !CSSProperty::isInheritedProperty(id)) 2181 state.parentStyle()->setHasExplicitlyInheritedProperties(); 2182 2183#if ENABLE(CSS_VARIABLES) 2184 if (id == CSSPropertyVariable) { 2185 ASSERT_WITH_SECURITY_IMPLICATION(value->isVariableValue()); 2186 CSSVariableValue* variable = static_cast<CSSVariableValue*>(value); 2187 ASSERT(!variable->name().isEmpty()); 2188 ASSERT(!variable->value().isEmpty()); 2189 state.style()->setVariable(variable->name(), variable->value()); 2190 return; 2191 } 2192#endif 2193 2194 // Check lookup table for implementations and use when available. 2195 const PropertyHandler& handler = m_deprecatedStyleBuilder.propertyHandler(id); 2196 if (handler.isValid()) { 2197 if (isInherit) 2198 handler.applyInheritValue(id, this); 2199 else if (isInitial) 2200 handler.applyInitialValue(id, this); 2201 else 2202 handler.applyValue(id, this, value); 2203 return; 2204 } 2205 2206 CSSPrimitiveValue* primitiveValue = value->isPrimitiveValue() ? static_cast<CSSPrimitiveValue*>(value) : 0; 2207 2208 float zoomFactor = state.style()->effectiveZoom(); 2209 2210 // What follows is a list that maps the CSS properties into their corresponding front-end 2211 // RenderStyle values. 2212 switch (id) { 2213 // lists 2214 case CSSPropertyContent: 2215 // list of string, uri, counter, attr, i 2216 { 2217 // FIXME: In CSS3, it will be possible to inherit content. In CSS2 it is not. This 2218 // note is a reminder that eventually "inherit" needs to be supported. 2219 2220 if (isInitial) { 2221 state.style()->clearContent(); 2222 return; 2223 } 2224 2225 if (!value->isValueList()) 2226 return; 2227 2228 bool didSet = false; 2229 for (CSSValueListIterator i = value; i.hasMore(); i.advance()) { 2230 CSSValue* item = i.value(); 2231 if (item->isImageGeneratorValue()) { 2232 if (item->isGradientValue()) 2233 state.style()->setContent(StyleGeneratedImage::create(static_cast<CSSGradientValue*>(item)->gradientWithStylesResolved(this).get()), didSet); 2234 else 2235 state.style()->setContent(StyleGeneratedImage::create(static_cast<CSSImageGeneratorValue*>(item)), didSet); 2236 didSet = true; 2237#if ENABLE(CSS_IMAGE_SET) 2238 } else if (item->isImageSetValue()) { 2239 state.style()->setContent(setOrPendingFromValue(CSSPropertyContent, static_cast<CSSImageSetValue*>(item)), didSet); 2240 didSet = true; 2241#endif 2242 } 2243 2244 if (item->isImageValue()) { 2245 state.style()->setContent(cachedOrPendingFromValue(CSSPropertyContent, static_cast<CSSImageValue*>(item)), didSet); 2246 didSet = true; 2247 continue; 2248 } 2249 2250 if (!item->isPrimitiveValue()) 2251 continue; 2252 2253 CSSPrimitiveValue* contentValue = static_cast<CSSPrimitiveValue*>(item); 2254 2255 if (contentValue->isString()) { 2256 state.style()->setContent(contentValue->getStringValue().impl(), didSet); 2257 didSet = true; 2258 } else if (contentValue->isAttr()) { 2259 // FIXME: Can a namespace be specified for an attr(foo)? 2260 if (state.style()->styleType() == NOPSEUDO) 2261 state.style()->setUnique(); 2262 else 2263 state.parentStyle()->setUnique(); 2264 QualifiedName attr(nullAtom, contentValue->getStringValue().impl(), nullAtom); 2265 const AtomicString& value = state.element()->getAttribute(attr); 2266 state.style()->setContent(value.isNull() ? emptyAtom : value.impl(), didSet); 2267 didSet = true; 2268 // register the fact that the attribute value affects the style 2269 m_ruleSets.features().attrsInRules.add(attr.localName().impl()); 2270 } else if (contentValue->isCounter()) { 2271 Counter* counterValue = contentValue->getCounterValue(); 2272 EListStyleType listStyleType = NoneListStyle; 2273 int listStyleIdent = counterValue->listStyleIdent(); 2274 if (listStyleIdent != CSSValueNone) 2275 listStyleType = static_cast<EListStyleType>(listStyleIdent - CSSValueDisc); 2276 OwnPtr<CounterContent> counter = adoptPtr(new CounterContent(counterValue->identifier(), listStyleType, counterValue->separator())); 2277 state.style()->setContent(counter.release(), didSet); 2278 didSet = true; 2279 } else { 2280 switch (contentValue->getIdent()) { 2281 case CSSValueOpenQuote: 2282 state.style()->setContent(OPEN_QUOTE, didSet); 2283 didSet = true; 2284 break; 2285 case CSSValueCloseQuote: 2286 state.style()->setContent(CLOSE_QUOTE, didSet); 2287 didSet = true; 2288 break; 2289 case CSSValueNoOpenQuote: 2290 state.style()->setContent(NO_OPEN_QUOTE, didSet); 2291 didSet = true; 2292 break; 2293 case CSSValueNoCloseQuote: 2294 state.style()->setContent(NO_CLOSE_QUOTE, didSet); 2295 didSet = true; 2296 break; 2297 default: 2298 // normal and none do not have any effect. 2299 { } 2300 } 2301 } 2302 } 2303 if (!didSet) 2304 state.style()->clearContent(); 2305 return; 2306 } 2307 case CSSPropertyQuotes: 2308 if (isInherit) { 2309 state.style()->setQuotes(state.parentStyle()->quotes()); 2310 return; 2311 } 2312 if (isInitial) { 2313 state.style()->setQuotes(0); 2314 return; 2315 } 2316 if (value->isValueList()) { 2317 CSSValueList* list = static_cast<CSSValueList*>(value); 2318 Vector<std::pair<String, String> > quotes; 2319 for (size_t i = 0; i < list->length(); i += 2) { 2320 CSSValue* first = list->itemWithoutBoundsCheck(i); 2321 // item() returns null if out of bounds so this is safe. 2322 CSSValue* second = list->item(i + 1); 2323 if (!second) 2324 continue; 2325 ASSERT_WITH_SECURITY_IMPLICATION(first->isPrimitiveValue()); 2326 ASSERT_WITH_SECURITY_IMPLICATION(second->isPrimitiveValue()); 2327 String startQuote = static_cast<CSSPrimitiveValue*>(first)->getStringValue(); 2328 String endQuote = static_cast<CSSPrimitiveValue*>(second)->getStringValue(); 2329 quotes.append(std::make_pair(startQuote, endQuote)); 2330 } 2331 state.style()->setQuotes(QuotesData::create(quotes)); 2332 return; 2333 } 2334 if (primitiveValue) { 2335 if (primitiveValue->getIdent() == CSSValueNone) 2336 state.style()->setQuotes(QuotesData::create(Vector<std::pair<String, String> >())); 2337 } 2338 return; 2339 // Shorthand properties. 2340 case CSSPropertyFont: 2341 if (isInherit) { 2342 FontDescription fontDescription = state.parentStyle()->fontDescription(); 2343 state.style()->setLineHeight(state.parentStyle()->specifiedLineHeight()); 2344 state.setLineHeightValue(0); 2345 setFontDescription(fontDescription); 2346 } else if (isInitial) { 2347 Settings* settings = documentSettings(); 2348 ASSERT(settings); // If we're doing style resolution, this document should always be in a frame and thus have settings 2349 if (!settings) 2350 return; 2351 initializeFontStyle(settings); 2352 } else if (primitiveValue) { 2353 state.style()->setLineHeight(RenderStyle::initialLineHeight()); 2354 state.setLineHeightValue(0); 2355 2356 FontDescription fontDescription; 2357 RenderTheme::defaultTheme()->systemFont(primitiveValue->getIdent(), fontDescription); 2358 2359 // Double-check and see if the theme did anything. If not, don't bother updating the font. 2360 if (fontDescription.isAbsoluteSize()) { 2361 // Make sure the rendering mode and printer font settings are updated. 2362 Settings* settings = documentSettings(); 2363 ASSERT(settings); // If we're doing style resolution, this document should always be in a frame and thus have settings 2364 if (!settings) 2365 return; 2366 fontDescription.setRenderingMode(settings->fontRenderingMode()); 2367 fontDescription.setUsePrinterFont(document()->printing() || !settings->screenFontSubstitutionEnabled()); 2368 2369 // Handle the zoom factor. 2370 fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(document(), state.style(), fontDescription.isAbsoluteSize(), fontDescription.specifiedSize(), useSVGZoomRules())); 2371 setFontDescription(fontDescription); 2372 } 2373 } else if (value->isFontValue()) { 2374 FontValue* font = static_cast<FontValue*>(value); 2375 if (!font->style || !font->variant || !font->weight 2376 || !font->size || !font->lineHeight || !font->family) 2377 return; 2378 applyProperty(CSSPropertyFontStyle, font->style.get()); 2379 applyProperty(CSSPropertyFontVariant, font->variant.get()); 2380 applyProperty(CSSPropertyFontWeight, font->weight.get()); 2381 // The previous properties can dirty our font but they don't try to read the font's 2382 // properties back, which is safe. However if font-size is using the 'ex' unit, it will 2383 // need query the dirtied font's x-height to get the computed size. To be safe in this 2384 // case, let's just update the font now. 2385 updateFont(); 2386 applyProperty(CSSPropertyFontSize, font->size.get()); 2387 2388 state.setLineHeightValue(font->lineHeight.get()); 2389 2390 applyProperty(CSSPropertyFontFamily, font->family.get()); 2391 } 2392 return; 2393 2394 case CSSPropertyBackground: 2395 case CSSPropertyBackgroundPosition: 2396 case CSSPropertyBackgroundRepeat: 2397 case CSSPropertyBorder: 2398 case CSSPropertyBorderBottom: 2399 case CSSPropertyBorderColor: 2400 case CSSPropertyBorderImage: 2401 case CSSPropertyBorderLeft: 2402 case CSSPropertyBorderRadius: 2403 case CSSPropertyBorderRight: 2404 case CSSPropertyBorderSpacing: 2405 case CSSPropertyBorderStyle: 2406 case CSSPropertyBorderTop: 2407 case CSSPropertyBorderWidth: 2408 case CSSPropertyListStyle: 2409 case CSSPropertyMargin: 2410 case CSSPropertyOutline: 2411 case CSSPropertyOverflow: 2412 case CSSPropertyPadding: 2413 case CSSPropertyTransition: 2414 case CSSPropertyWebkitAnimation: 2415 case CSSPropertyWebkitBorderAfter: 2416 case CSSPropertyWebkitBorderBefore: 2417 case CSSPropertyWebkitBorderEnd: 2418 case CSSPropertyWebkitBorderStart: 2419 case CSSPropertyWebkitBorderRadius: 2420 case CSSPropertyWebkitColumns: 2421 case CSSPropertyWebkitColumnRule: 2422 case CSSPropertyWebkitFlex: 2423 case CSSPropertyWebkitFlexFlow: 2424 case CSSPropertyWebkitGridColumn: 2425 case CSSPropertyWebkitGridRow: 2426 case CSSPropertyWebkitMarginCollapse: 2427 case CSSPropertyWebkitMarquee: 2428 case CSSPropertyWebkitMask: 2429 case CSSPropertyWebkitMaskPosition: 2430 case CSSPropertyWebkitMaskRepeat: 2431 case CSSPropertyWebkitTextEmphasis: 2432 case CSSPropertyWebkitTextStroke: 2433 case CSSPropertyWebkitTransition: 2434 case CSSPropertyWebkitTransformOrigin: 2435 ASSERT(isExpandedShorthand(id)); 2436 ASSERT_NOT_REACHED(); 2437 break; 2438 2439 // CSS3 Properties 2440 case CSSPropertyTextShadow: 2441 case CSSPropertyBoxShadow: 2442 case CSSPropertyWebkitBoxShadow: { 2443 if (isInherit) { 2444 if (id == CSSPropertyTextShadow) 2445 return state.style()->setTextShadow(state.parentStyle()->textShadow() ? adoptPtr(new ShadowData(*state.parentStyle()->textShadow())) : nullptr); 2446 return state.style()->setBoxShadow(state.parentStyle()->boxShadow() ? adoptPtr(new ShadowData(*state.parentStyle()->boxShadow())) : nullptr); 2447 } 2448 if (isInitial || primitiveValue) // initial | none 2449 return id == CSSPropertyTextShadow ? state.style()->setTextShadow(nullptr) : state.style()->setBoxShadow(nullptr); 2450 2451 if (!value->isValueList()) 2452 return; 2453 2454 for (CSSValueListIterator i = value; i.hasMore(); i.advance()) { 2455 CSSValue* currValue = i.value(); 2456 if (!currValue->isShadowValue()) 2457 continue; 2458 ShadowValue* item = static_cast<ShadowValue*>(currValue); 2459 int x = item->x->computeLength<int>(state.style(), state.rootElementStyle(), zoomFactor); 2460 int y = item->y->computeLength<int>(state.style(), state.rootElementStyle(), zoomFactor); 2461 int blur = item->blur ? item->blur->computeLength<int>(state.style(), state.rootElementStyle(), zoomFactor) : 0; 2462 int spread = item->spread ? item->spread->computeLength<int>(state.style(), state.rootElementStyle(), zoomFactor) : 0; 2463 ShadowStyle shadowStyle = item->style && item->style->getIdent() == CSSValueInset ? Inset : Normal; 2464 Color color; 2465 if (item->color) 2466 color = colorFromPrimitiveValue(item->color.get()); 2467 else if (state.style()) 2468 color = state.style()->color(); 2469 2470 OwnPtr<ShadowData> shadowData = adoptPtr(new ShadowData(IntPoint(x, y), blur, spread, shadowStyle, id == CSSPropertyWebkitBoxShadow, color.isValid() ? color : Color::transparent)); 2471 if (id == CSSPropertyTextShadow) 2472 state.style()->setTextShadow(shadowData.release(), i.index()); // add to the list if this is not the first entry 2473 else 2474 state.style()->setBoxShadow(shadowData.release(), i.index()); // add to the list if this is not the first entry 2475 } 2476 return; 2477 } 2478 case CSSPropertyWebkitBoxReflect: { 2479 HANDLE_INHERIT_AND_INITIAL(boxReflect, BoxReflect) 2480 if (primitiveValue) { 2481 state.style()->setBoxReflect(RenderStyle::initialBoxReflect()); 2482 return; 2483 } 2484 2485 if (!value->isReflectValue()) 2486 return; 2487 2488 CSSReflectValue* reflectValue = static_cast<CSSReflectValue*>(value); 2489 RefPtr<StyleReflection> reflection = StyleReflection::create(); 2490 reflection->setDirection(*reflectValue->direction()); 2491 if (reflectValue->offset()) 2492 reflection->setOffset(reflectValue->offset()->convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion>(state.style(), state.rootElementStyle(), zoomFactor)); 2493 NinePieceImage mask; 2494 mask.setMaskDefaults(); 2495 m_styleMap.mapNinePieceImage(id, reflectValue->mask(), mask); 2496 reflection->setMask(mask); 2497 2498 state.style()->setBoxReflect(reflection.release()); 2499 return; 2500 } 2501 case CSSPropertySrc: // Only used in @font-face rules. 2502 return; 2503 case CSSPropertyUnicodeRange: // Only used in @font-face rules. 2504 return; 2505 case CSSPropertyWebkitLocale: { 2506 HANDLE_INHERIT_AND_INITIAL(locale, Locale); 2507 if (!primitiveValue) 2508 return; 2509 if (primitiveValue->getIdent() == CSSValueAuto) 2510 state.style()->setLocale(nullAtom); 2511 else 2512 state.style()->setLocale(primitiveValue->getStringValue()); 2513 FontDescription fontDescription = state.style()->fontDescription(); 2514 fontDescription.setScript(localeToScriptCodeForFontSelection(state.style()->locale())); 2515 setFontDescription(fontDescription); 2516 return; 2517 } 2518#if ENABLE(DASHBOARD_SUPPORT) 2519 case CSSPropertyWebkitDashboardRegion: 2520 { 2521 HANDLE_INHERIT_AND_INITIAL(dashboardRegions, DashboardRegions) 2522 if (!primitiveValue) 2523 return; 2524 2525 if (primitiveValue->getIdent() == CSSValueNone) { 2526 state.style()->setDashboardRegions(RenderStyle::noneDashboardRegions()); 2527 return; 2528 } 2529 2530 DashboardRegion* region = primitiveValue->getDashboardRegionValue(); 2531 if (!region) 2532 return; 2533 2534 DashboardRegion* first = region; 2535 while (region) { 2536 Length top = convertToIntLength(region->top(), state.style(), state.rootElementStyle()); 2537 Length right = convertToIntLength(region->right(), state.style(), state.rootElementStyle()); 2538 Length bottom = convertToIntLength(region->bottom(), state.style(), state.rootElementStyle()); 2539 Length left = convertToIntLength(region->left(), state.style(), state.rootElementStyle()); 2540 2541 if (top.isUndefined()) 2542 top = Length(); 2543 if (right.isUndefined()) 2544 right = Length(); 2545 if (bottom.isUndefined()) 2546 bottom = Length(); 2547 if (left.isUndefined()) 2548 left = Length(); 2549 2550 if (region->m_isCircle) 2551 state.style()->setDashboardRegion(StyleDashboardRegion::Circle, region->m_label, top, right, bottom, left, region == first ? false : true); 2552 else if (region->m_isRectangle) 2553 state.style()->setDashboardRegion(StyleDashboardRegion::Rectangle, region->m_label, top, right, bottom, left, region == first ? false : true); 2554 region = region->m_next.get(); 2555 } 2556 2557 state.document()->setHasAnnotatedRegions(true); 2558 2559 return; 2560 } 2561#endif 2562#if ENABLE(DRAGGABLE_REGION) 2563 case CSSPropertyWebkitAppRegion: { 2564 if (!primitiveValue || !primitiveValue->getIdent()) 2565 return; 2566 state.style()->setDraggableRegionMode(primitiveValue->getIdent() == CSSValueDrag ? DraggableRegionDrag : DraggableRegionNoDrag); 2567 state.document()->setHasAnnotatedRegions(true); 2568 return; 2569 } 2570#endif 2571 case CSSPropertyWebkitTextStrokeWidth: { 2572 HANDLE_INHERIT_AND_INITIAL(textStrokeWidth, TextStrokeWidth) 2573 float width = 0; 2574 switch (primitiveValue->getIdent()) { 2575 case CSSValueThin: 2576 case CSSValueMedium: 2577 case CSSValueThick: { 2578 double result = 1.0 / 48; 2579 if (primitiveValue->getIdent() == CSSValueMedium) 2580 result *= 3; 2581 else if (primitiveValue->getIdent() == CSSValueThick) 2582 result *= 5; 2583 width = CSSPrimitiveValue::create(result, CSSPrimitiveValue::CSS_EMS)->computeLength<float>(state.style(), state.rootElementStyle(), zoomFactor); 2584 break; 2585 } 2586 default: 2587 width = primitiveValue->computeLength<float>(state.style(), state.rootElementStyle(), zoomFactor); 2588 break; 2589 } 2590 state.style()->setTextStrokeWidth(width); 2591 return; 2592 } 2593 case CSSPropertyWebkitTransform: { 2594 HANDLE_INHERIT_AND_INITIAL(transform, Transform); 2595 TransformOperations operations; 2596 transformsForValue(state.style(), state.rootElementStyle(), value, operations); 2597 state.style()->setTransform(operations); 2598 return; 2599 } 2600 case CSSPropertyWebkitPerspective: { 2601 HANDLE_INHERIT_AND_INITIAL(perspective, Perspective) 2602 2603 if (!primitiveValue) 2604 return; 2605 2606 if (primitiveValue->getIdent() == CSSValueNone) { 2607 state.style()->setPerspective(0); 2608 return; 2609 } 2610 2611 float perspectiveValue; 2612 if (primitiveValue->isLength()) 2613 perspectiveValue = primitiveValue->computeLength<float>(state.style(), state.rootElementStyle(), zoomFactor); 2614 else if (primitiveValue->isNumber()) { 2615 // For backward compatibility, treat valueless numbers as px. 2616 perspectiveValue = CSSPrimitiveValue::create(primitiveValue->getDoubleValue(), CSSPrimitiveValue::CSS_PX)->computeLength<float>(state.style(), state.rootElementStyle(), zoomFactor); 2617 } else 2618 return; 2619 2620 if (perspectiveValue >= 0.0f) 2621 state.style()->setPerspective(perspectiveValue); 2622 return; 2623 } 2624#if ENABLE(TOUCH_EVENTS) 2625 case CSSPropertyWebkitTapHighlightColor: { 2626 HANDLE_INHERIT_AND_INITIAL(tapHighlightColor, TapHighlightColor); 2627 if (!primitiveValue) 2628 break; 2629 2630 Color col = colorFromPrimitiveValue(primitiveValue); 2631 state.style()->setTapHighlightColor(col); 2632 return; 2633 } 2634#endif 2635#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING) 2636 case CSSPropertyWebkitOverflowScrolling: { 2637 HANDLE_INHERIT_AND_INITIAL(useTouchOverflowScrolling, UseTouchOverflowScrolling); 2638 if (!primitiveValue) 2639 break; 2640 state.style()->setUseTouchOverflowScrolling(primitiveValue->getIdent() == CSSValueTouch); 2641 return; 2642 } 2643#endif 2644 case CSSPropertyInvalid: 2645 return; 2646 // Directional properties are resolved by resolveDirectionAwareProperty() before the switch. 2647 case CSSPropertyWebkitBorderEndColor: 2648 case CSSPropertyWebkitBorderEndStyle: 2649 case CSSPropertyWebkitBorderEndWidth: 2650 case CSSPropertyWebkitBorderStartColor: 2651 case CSSPropertyWebkitBorderStartStyle: 2652 case CSSPropertyWebkitBorderStartWidth: 2653 case CSSPropertyWebkitBorderBeforeColor: 2654 case CSSPropertyWebkitBorderBeforeStyle: 2655 case CSSPropertyWebkitBorderBeforeWidth: 2656 case CSSPropertyWebkitBorderAfterColor: 2657 case CSSPropertyWebkitBorderAfterStyle: 2658 case CSSPropertyWebkitBorderAfterWidth: 2659 case CSSPropertyWebkitMarginEnd: 2660 case CSSPropertyWebkitMarginStart: 2661 case CSSPropertyWebkitMarginBefore: 2662 case CSSPropertyWebkitMarginAfter: 2663 case CSSPropertyWebkitMarginBeforeCollapse: 2664 case CSSPropertyWebkitMarginTopCollapse: 2665 case CSSPropertyWebkitMarginAfterCollapse: 2666 case CSSPropertyWebkitMarginBottomCollapse: 2667 case CSSPropertyWebkitPaddingEnd: 2668 case CSSPropertyWebkitPaddingStart: 2669 case CSSPropertyWebkitPaddingBefore: 2670 case CSSPropertyWebkitPaddingAfter: 2671 case CSSPropertyWebkitLogicalWidth: 2672 case CSSPropertyWebkitLogicalHeight: 2673 case CSSPropertyWebkitMinLogicalWidth: 2674 case CSSPropertyWebkitMinLogicalHeight: 2675 case CSSPropertyWebkitMaxLogicalWidth: 2676 case CSSPropertyWebkitMaxLogicalHeight: 2677 { 2678 CSSPropertyID newId = CSSProperty::resolveDirectionAwareProperty(id, state.style()->direction(), state.style()->writingMode()); 2679 ASSERT(newId != id); 2680 return applyProperty(newId, value); 2681 } 2682 case CSSPropertyFontStretch: 2683 case CSSPropertyPage: 2684 case CSSPropertyTextLineThrough: 2685 case CSSPropertyTextLineThroughColor: 2686 case CSSPropertyTextLineThroughMode: 2687 case CSSPropertyTextLineThroughStyle: 2688 case CSSPropertyTextLineThroughWidth: 2689 case CSSPropertyTextOverline: 2690 case CSSPropertyTextOverlineColor: 2691 case CSSPropertyTextOverlineMode: 2692 case CSSPropertyTextOverlineStyle: 2693 case CSSPropertyTextOverlineWidth: 2694 case CSSPropertyTextUnderline: 2695 case CSSPropertyTextUnderlineColor: 2696 case CSSPropertyTextUnderlineMode: 2697 case CSSPropertyTextUnderlineStyle: 2698 case CSSPropertyTextUnderlineWidth: 2699 case CSSPropertyWebkitFontSizeDelta: 2700 case CSSPropertyWebkitTextDecorationsInEffect: 2701 return; 2702 2703 // CSS Text Layout Module Level 3: Vertical writing support 2704 case CSSPropertyWebkitWritingMode: { 2705 HANDLE_INHERIT_AND_INITIAL(writingMode, WritingMode); 2706 2707 if (primitiveValue) 2708 setWritingMode(*primitiveValue); 2709 2710 // FIXME: It is not ok to modify document state while applying style. 2711 if (state.element() && state.element() == state.document()->documentElement()) 2712 state.document()->setWritingModeSetOnDocumentElement(true); 2713 return; 2714 } 2715 2716 case CSSPropertyWebkitTextOrientation: { 2717 HANDLE_INHERIT_AND_INITIAL(textOrientation, TextOrientation); 2718 2719 if (primitiveValue) 2720 setTextOrientation(*primitiveValue); 2721 2722 return; 2723 } 2724 2725 case CSSPropertyWebkitLineBoxContain: { 2726 HANDLE_INHERIT_AND_INITIAL(lineBoxContain, LineBoxContain) 2727 if (primitiveValue && primitiveValue->getIdent() == CSSValueNone) { 2728 state.style()->setLineBoxContain(LineBoxContainNone); 2729 return; 2730 } 2731 2732 if (!value->isCSSLineBoxContainValue()) 2733 return; 2734 2735 CSSLineBoxContainValue* lineBoxContainValue = static_cast<CSSLineBoxContainValue*>(value); 2736 state.style()->setLineBoxContain(lineBoxContainValue->value()); 2737 return; 2738 } 2739 2740 // CSS Fonts Module Level 3 2741 case CSSPropertyWebkitFontFeatureSettings: { 2742 if (primitiveValue && primitiveValue->getIdent() == CSSValueNormal) { 2743 setFontDescription(state.style()->fontDescription().makeNormalFeatureSettings()); 2744 return; 2745 } 2746 2747 if (!value->isValueList()) 2748 return; 2749 2750 FontDescription fontDescription = state.style()->fontDescription(); 2751 CSSValueList* list = static_cast<CSSValueList*>(value); 2752 RefPtr<FontFeatureSettings> settings = FontFeatureSettings::create(); 2753 int len = list->length(); 2754 for (int i = 0; i < len; ++i) { 2755 CSSValue* item = list->itemWithoutBoundsCheck(i); 2756 if (!item->isFontFeatureValue()) 2757 continue; 2758 FontFeatureValue* feature = static_cast<FontFeatureValue*>(item); 2759 settings->append(FontFeature(feature->tag(), feature->value())); 2760 } 2761 fontDescription.setFeatureSettings(settings.release()); 2762 setFontDescription(fontDescription); 2763 return; 2764 } 2765 2766#if ENABLE(CSS_FILTERS) 2767 case CSSPropertyWebkitFilter: { 2768 HANDLE_INHERIT_AND_INITIAL(filter, Filter); 2769 FilterOperations operations; 2770 if (createFilterOperations(value, state.style(), state.rootElementStyle(), operations)) 2771 state.style()->setFilter(operations); 2772 return; 2773 } 2774#endif 2775 case CSSPropertyWebkitGridAutoColumns: { 2776 GridTrackSize trackSize; 2777 if (!createGridTrackSize(value, trackSize, state)) 2778 return; 2779 state.style()->setGridAutoColumns(trackSize); 2780 return; 2781 } 2782 case CSSPropertyWebkitGridAutoRows: { 2783 GridTrackSize trackSize; 2784 if (!createGridTrackSize(value, trackSize, state)) 2785 return; 2786 state.style()->setGridAutoRows(trackSize); 2787 return; 2788 } 2789 case CSSPropertyWebkitGridColumns: { 2790 Vector<GridTrackSize> trackSizes; 2791 if (!createGridTrackList(value, trackSizes, state)) 2792 return; 2793 state.style()->setGridColumns(trackSizes); 2794 return; 2795 } 2796 case CSSPropertyWebkitGridRows: { 2797 Vector<GridTrackSize> trackSizes; 2798 if (!createGridTrackList(value, trackSizes, state)) 2799 return; 2800 state.style()->setGridRows(trackSizes); 2801 return; 2802 } 2803 2804 case CSSPropertyWebkitGridStart: { 2805 GridPosition startPosition; 2806 if (!createGridPosition(value, startPosition)) 2807 return; 2808 state.style()->setGridItemStart(startPosition); 2809 return; 2810 } 2811 case CSSPropertyWebkitGridEnd: { 2812 GridPosition endPosition; 2813 if (!createGridPosition(value, endPosition)) 2814 return; 2815 state.style()->setGridItemEnd(endPosition); 2816 return; 2817 } 2818 2819 case CSSPropertyWebkitGridBefore: { 2820 GridPosition beforePosition; 2821 if (!createGridPosition(value, beforePosition)) 2822 return; 2823 state.style()->setGridItemBefore(beforePosition); 2824 return; 2825 } 2826 case CSSPropertyWebkitGridAfter: { 2827 GridPosition afterPosition; 2828 if (!createGridPosition(value, afterPosition)) 2829 return; 2830 state.style()->setGridItemAfter(afterPosition); 2831 return; 2832 } 2833 2834 // These properties are aliased and DeprecatedStyleBuilder already applied the property on the prefixed version. 2835 case CSSPropertyTransitionDelay: 2836 case CSSPropertyTransitionDuration: 2837 case CSSPropertyTransitionProperty: 2838 case CSSPropertyTransitionTimingFunction: 2839 return; 2840 // These properties are implemented in the DeprecatedStyleBuilder lookup table. 2841 case CSSPropertyBackgroundAttachment: 2842 case CSSPropertyBackgroundClip: 2843 case CSSPropertyBackgroundColor: 2844 case CSSPropertyBackgroundImage: 2845 case CSSPropertyBackgroundOrigin: 2846 case CSSPropertyBackgroundPositionX: 2847 case CSSPropertyBackgroundPositionY: 2848 case CSSPropertyBackgroundRepeatX: 2849 case CSSPropertyBackgroundRepeatY: 2850 case CSSPropertyBackgroundSize: 2851 case CSSPropertyBorderBottomColor: 2852 case CSSPropertyBorderBottomLeftRadius: 2853 case CSSPropertyBorderBottomRightRadius: 2854 case CSSPropertyBorderBottomStyle: 2855 case CSSPropertyBorderBottomWidth: 2856 case CSSPropertyBorderCollapse: 2857 case CSSPropertyBorderImageOutset: 2858 case CSSPropertyBorderImageRepeat: 2859 case CSSPropertyBorderImageSlice: 2860 case CSSPropertyBorderImageSource: 2861 case CSSPropertyBorderImageWidth: 2862 case CSSPropertyBorderLeftColor: 2863 case CSSPropertyBorderLeftStyle: 2864 case CSSPropertyBorderLeftWidth: 2865 case CSSPropertyBorderRightColor: 2866 case CSSPropertyBorderRightStyle: 2867 case CSSPropertyBorderRightWidth: 2868 case CSSPropertyBorderTopColor: 2869 case CSSPropertyBorderTopLeftRadius: 2870 case CSSPropertyBorderTopRightRadius: 2871 case CSSPropertyBorderTopStyle: 2872 case CSSPropertyBorderTopWidth: 2873 case CSSPropertyBottom: 2874 case CSSPropertyBoxSizing: 2875 case CSSPropertyCaptionSide: 2876 case CSSPropertyClear: 2877 case CSSPropertyClip: 2878 case CSSPropertyColor: 2879 case CSSPropertyCounterIncrement: 2880 case CSSPropertyCounterReset: 2881 case CSSPropertyCursor: 2882 case CSSPropertyDirection: 2883 case CSSPropertyDisplay: 2884 case CSSPropertyEmptyCells: 2885 case CSSPropertyFloat: 2886 case CSSPropertyFontSize: 2887 case CSSPropertyFontStyle: 2888 case CSSPropertyFontVariant: 2889 case CSSPropertyFontWeight: 2890 case CSSPropertyHeight: 2891#if ENABLE(CSS_IMAGE_ORIENTATION) 2892 case CSSPropertyImageOrientation: 2893#endif 2894 case CSSPropertyImageRendering: 2895#if ENABLE(CSS_IMAGE_RESOLUTION) 2896 case CSSPropertyImageResolution: 2897#endif 2898 case CSSPropertyLeft: 2899 case CSSPropertyLetterSpacing: 2900 case CSSPropertyLineHeight: 2901 case CSSPropertyListStyleImage: 2902 case CSSPropertyListStylePosition: 2903 case CSSPropertyListStyleType: 2904 case CSSPropertyMarginBottom: 2905 case CSSPropertyMarginLeft: 2906 case CSSPropertyMarginRight: 2907 case CSSPropertyMarginTop: 2908 case CSSPropertyMaxHeight: 2909 case CSSPropertyMaxWidth: 2910 case CSSPropertyMinHeight: 2911 case CSSPropertyMinWidth: 2912 case CSSPropertyOpacity: 2913 case CSSPropertyOrphans: 2914 case CSSPropertyOutlineColor: 2915 case CSSPropertyOutlineOffset: 2916 case CSSPropertyOutlineStyle: 2917 case CSSPropertyOutlineWidth: 2918 case CSSPropertyOverflowWrap: 2919 case CSSPropertyOverflowX: 2920 case CSSPropertyOverflowY: 2921 case CSSPropertyPaddingBottom: 2922 case CSSPropertyPaddingLeft: 2923 case CSSPropertyPaddingRight: 2924 case CSSPropertyPaddingTop: 2925 case CSSPropertyPageBreakAfter: 2926 case CSSPropertyPageBreakBefore: 2927 case CSSPropertyPageBreakInside: 2928 case CSSPropertyPointerEvents: 2929 case CSSPropertyPosition: 2930 case CSSPropertyResize: 2931 case CSSPropertyRight: 2932 case CSSPropertySize: 2933 case CSSPropertySpeak: 2934 case CSSPropertyTabSize: 2935 case CSSPropertyTableLayout: 2936 case CSSPropertyTextAlign: 2937 case CSSPropertyTextDecoration: 2938 case CSSPropertyTextIndent: 2939 case CSSPropertyTextOverflow: 2940 case CSSPropertyTextRendering: 2941 case CSSPropertyTextTransform: 2942 case CSSPropertyTop: 2943 case CSSPropertyUnicodeBidi: 2944#if ENABLE(CSS_VARIABLES) 2945 case CSSPropertyVariable: 2946#endif 2947 case CSSPropertyVerticalAlign: 2948 case CSSPropertyVisibility: 2949 case CSSPropertyWebkitAnimationDelay: 2950 case CSSPropertyWebkitAnimationDirection: 2951 case CSSPropertyWebkitAnimationDuration: 2952 case CSSPropertyWebkitAnimationFillMode: 2953 case CSSPropertyWebkitAnimationIterationCount: 2954 case CSSPropertyWebkitAnimationName: 2955 case CSSPropertyWebkitAnimationPlayState: 2956 case CSSPropertyWebkitAnimationTimingFunction: 2957 case CSSPropertyWebkitAppearance: 2958 case CSSPropertyWebkitAspectRatio: 2959 case CSSPropertyWebkitBackfaceVisibility: 2960 case CSSPropertyWebkitBackgroundClip: 2961 case CSSPropertyWebkitBackgroundComposite: 2962 case CSSPropertyWebkitBackgroundOrigin: 2963 case CSSPropertyWebkitBackgroundSize: 2964 case CSSPropertyWebkitBorderFit: 2965 case CSSPropertyWebkitBorderHorizontalSpacing: 2966 case CSSPropertyWebkitBorderImage: 2967 case CSSPropertyWebkitBorderVerticalSpacing: 2968 case CSSPropertyWebkitBoxAlign: 2969#if ENABLE(CSS_BOX_DECORATION_BREAK) 2970 case CSSPropertyWebkitBoxDecorationBreak: 2971#endif 2972 case CSSPropertyWebkitBoxDirection: 2973 case CSSPropertyWebkitBoxFlex: 2974 case CSSPropertyWebkitBoxFlexGroup: 2975 case CSSPropertyWebkitBoxLines: 2976 case CSSPropertyWebkitBoxOrdinalGroup: 2977 case CSSPropertyWebkitBoxOrient: 2978 case CSSPropertyWebkitBoxPack: 2979 case CSSPropertyWebkitColorCorrection: 2980 case CSSPropertyWebkitColumnAxis: 2981 case CSSPropertyWebkitColumnBreakAfter: 2982 case CSSPropertyWebkitColumnBreakBefore: 2983 case CSSPropertyWebkitColumnBreakInside: 2984 case CSSPropertyWebkitColumnCount: 2985 case CSSPropertyWebkitColumnGap: 2986 case CSSPropertyWebkitColumnProgression: 2987 case CSSPropertyWebkitColumnRuleColor: 2988 case CSSPropertyWebkitColumnRuleStyle: 2989 case CSSPropertyWebkitColumnRuleWidth: 2990 case CSSPropertyWebkitColumnSpan: 2991 case CSSPropertyWebkitColumnWidth: 2992#if ENABLE(CURSOR_VISIBILITY) 2993 case CSSPropertyWebkitCursorVisibility: 2994#endif 2995 case CSSPropertyWebkitAlignContent: 2996 case CSSPropertyWebkitAlignItems: 2997 case CSSPropertyWebkitAlignSelf: 2998 case CSSPropertyWebkitFlexBasis: 2999 case CSSPropertyWebkitFlexDirection: 3000 case CSSPropertyWebkitFlexGrow: 3001 case CSSPropertyWebkitFlexShrink: 3002 case CSSPropertyWebkitFlexWrap: 3003 case CSSPropertyWebkitJustifyContent: 3004 case CSSPropertyWebkitOrder: 3005#if ENABLE(CSS_REGIONS) 3006 case CSSPropertyWebkitFlowFrom: 3007 case CSSPropertyWebkitFlowInto: 3008#endif 3009 case CSSPropertyWebkitFontKerning: 3010 case CSSPropertyWebkitFontSmoothing: 3011 case CSSPropertyWebkitFontVariantLigatures: 3012 case CSSPropertyWebkitHighlight: 3013 case CSSPropertyWebkitHyphenateCharacter: 3014 case CSSPropertyWebkitHyphenateLimitAfter: 3015 case CSSPropertyWebkitHyphenateLimitBefore: 3016 case CSSPropertyWebkitHyphenateLimitLines: 3017 case CSSPropertyWebkitHyphens: 3018 case CSSPropertyWebkitLineAlign: 3019 case CSSPropertyWebkitLineBreak: 3020 case CSSPropertyWebkitLineClamp: 3021 case CSSPropertyWebkitLineGrid: 3022 case CSSPropertyWebkitLineSnap: 3023 case CSSPropertyWebkitMarqueeDirection: 3024 case CSSPropertyWebkitMarqueeIncrement: 3025 case CSSPropertyWebkitMarqueeRepetition: 3026 case CSSPropertyWebkitMarqueeSpeed: 3027 case CSSPropertyWebkitMarqueeStyle: 3028 case CSSPropertyWebkitMaskBoxImage: 3029 case CSSPropertyWebkitMaskBoxImageOutset: 3030 case CSSPropertyWebkitMaskBoxImageRepeat: 3031 case CSSPropertyWebkitMaskBoxImageSlice: 3032 case CSSPropertyWebkitMaskBoxImageSource: 3033 case CSSPropertyWebkitMaskBoxImageWidth: 3034 case CSSPropertyWebkitMaskClip: 3035 case CSSPropertyWebkitMaskComposite: 3036 case CSSPropertyWebkitMaskImage: 3037 case CSSPropertyWebkitMaskOrigin: 3038 case CSSPropertyWebkitMaskPositionX: 3039 case CSSPropertyWebkitMaskPositionY: 3040 case CSSPropertyWebkitMaskRepeatX: 3041 case CSSPropertyWebkitMaskRepeatY: 3042 case CSSPropertyWebkitMaskSize: 3043 case CSSPropertyWebkitNbspMode: 3044 case CSSPropertyWebkitPerspectiveOrigin: 3045 case CSSPropertyWebkitPerspectiveOriginX: 3046 case CSSPropertyWebkitPerspectiveOriginY: 3047 case CSSPropertyWebkitPrintColorAdjust: 3048#if ENABLE(CSS_REGIONS) 3049 case CSSPropertyWebkitRegionBreakAfter: 3050 case CSSPropertyWebkitRegionBreakBefore: 3051 case CSSPropertyWebkitRegionBreakInside: 3052 case CSSPropertyWebkitRegionFragment: 3053#endif 3054 case CSSPropertyWebkitRtlOrdering: 3055 case CSSPropertyWebkitRubyPosition: 3056 case CSSPropertyWebkitTextCombine: 3057#if ENABLE(CSS3_TEXT) 3058 case CSSPropertyWebkitTextDecorationLine: 3059 case CSSPropertyWebkitTextDecorationStyle: 3060 case CSSPropertyWebkitTextDecorationColor: 3061 case CSSPropertyWebkitTextAlignLast: 3062 case CSSPropertyWebkitTextJustify: 3063 case CSSPropertyWebkitTextUnderlinePosition: 3064#endif // CSS3_TEXT 3065 case CSSPropertyWebkitTextEmphasisColor: 3066 case CSSPropertyWebkitTextEmphasisPosition: 3067 case CSSPropertyWebkitTextEmphasisStyle: 3068 case CSSPropertyWebkitTextFillColor: 3069 case CSSPropertyWebkitTextSecurity: 3070 case CSSPropertyWebkitTextStrokeColor: 3071 case CSSPropertyWebkitTransformOriginX: 3072 case CSSPropertyWebkitTransformOriginY: 3073 case CSSPropertyWebkitTransformOriginZ: 3074 case CSSPropertyWebkitTransformStyle: 3075 case CSSPropertyWebkitTransitionDelay: 3076 case CSSPropertyWebkitTransitionDuration: 3077 case CSSPropertyWebkitTransitionProperty: 3078 case CSSPropertyWebkitTransitionTimingFunction: 3079 case CSSPropertyWebkitUserDrag: 3080 case CSSPropertyWebkitUserModify: 3081 case CSSPropertyWebkitUserSelect: 3082 case CSSPropertyWebkitClipPath: 3083#if ENABLE(CSS_SHAPES) 3084 case CSSPropertyWebkitShapeMargin: 3085 case CSSPropertyWebkitShapePadding: 3086 case CSSPropertyWebkitShapeInside: 3087 case CSSPropertyWebkitShapeOutside: 3088#endif 3089#if ENABLE(CSS_EXCLUSIONS) 3090 case CSSPropertyWebkitWrapFlow: 3091 case CSSPropertyWebkitWrapThrough: 3092#endif 3093#if ENABLE(CSS_SHADERS) 3094 case CSSPropertyMix: 3095 case CSSPropertyParameters: 3096#endif 3097 case CSSPropertyWhiteSpace: 3098 case CSSPropertyWidows: 3099 case CSSPropertyWidth: 3100 case CSSPropertyWordBreak: 3101 case CSSPropertyWordSpacing: 3102 case CSSPropertyWordWrap: 3103 case CSSPropertyZIndex: 3104 case CSSPropertyZoom: 3105#if ENABLE(CSS_DEVICE_ADAPTATION) 3106 case CSSPropertyMaxZoom: 3107 case CSSPropertyMinZoom: 3108 case CSSPropertyOrientation: 3109 case CSSPropertyUserZoom: 3110#endif 3111 ASSERT_NOT_REACHED(); 3112 return; 3113 default: 3114#if ENABLE(SVG) 3115 // Try the SVG properties 3116 applySVGProperty(id, value); 3117#endif 3118 return; 3119 } 3120} 3121 3122PassRefPtr<StyleImage> StyleResolver::styleImage(CSSPropertyID property, CSSValue* value) 3123{ 3124 if (value->isImageValue()) 3125 return cachedOrPendingFromValue(property, static_cast<CSSImageValue*>(value)); 3126 3127 if (value->isImageGeneratorValue()) { 3128 if (value->isGradientValue()) 3129 return generatedOrPendingFromValue(property, static_cast<CSSGradientValue*>(value)->gradientWithStylesResolved(this).get()); 3130 return generatedOrPendingFromValue(property, static_cast<CSSImageGeneratorValue*>(value)); 3131 } 3132 3133#if ENABLE(CSS_IMAGE_SET) 3134 if (value->isImageSetValue()) 3135 return setOrPendingFromValue(property, static_cast<CSSImageSetValue*>(value)); 3136#endif 3137 3138 if (value->isCursorImageValue()) 3139 return cursorOrPendingFromValue(property, static_cast<CSSCursorImageValue*>(value)); 3140 3141 return 0; 3142} 3143 3144PassRefPtr<StyleImage> StyleResolver::cachedOrPendingFromValue(CSSPropertyID property, CSSImageValue* value) 3145{ 3146 RefPtr<StyleImage> image = value->cachedOrPendingImage(); 3147 if (image && image->isPendingImage()) 3148 m_state.pendingImageProperties().set(property, value); 3149 return image.release(); 3150} 3151 3152PassRefPtr<StyleImage> StyleResolver::generatedOrPendingFromValue(CSSPropertyID property, CSSImageGeneratorValue* value) 3153{ 3154 if (value->isPending()) { 3155 m_state.pendingImageProperties().set(property, value); 3156 return StylePendingImage::create(value); 3157 } 3158 return StyleGeneratedImage::create(value); 3159} 3160 3161#if ENABLE(CSS_IMAGE_SET) 3162PassRefPtr<StyleImage> StyleResolver::setOrPendingFromValue(CSSPropertyID property, CSSImageSetValue* value) 3163{ 3164 RefPtr<StyleImage> image = value->cachedOrPendingImageSet(document()); 3165 if (image && image->isPendingImage()) 3166 m_state.pendingImageProperties().set(property, value); 3167 return image.release(); 3168} 3169#endif 3170 3171PassRefPtr<StyleImage> StyleResolver::cursorOrPendingFromValue(CSSPropertyID property, CSSCursorImageValue* value) 3172{ 3173 RefPtr<StyleImage> image = value->cachedOrPendingImage(document()); 3174 if (image && image->isPendingImage()) 3175 m_state.pendingImageProperties().set(property, value); 3176 return image.release(); 3177} 3178 3179void StyleResolver::checkForZoomChange(RenderStyle* style, RenderStyle* parentStyle) 3180{ 3181 if (style->effectiveZoom() == parentStyle->effectiveZoom()) 3182 return; 3183 3184 const FontDescription& childFont = style->fontDescription(); 3185 FontDescription newFontDescription(childFont); 3186 setFontSize(newFontDescription, childFont.specifiedSize()); 3187 style->setFontDescription(newFontDescription); 3188} 3189 3190void StyleResolver::checkForGenericFamilyChange(RenderStyle* style, RenderStyle* parentStyle) 3191{ 3192 const FontDescription& childFont = style->fontDescription(); 3193 3194 if (childFont.isAbsoluteSize() || !parentStyle) 3195 return; 3196 3197 const FontDescription& parentFont = parentStyle->fontDescription(); 3198 if (childFont.useFixedDefaultSize() == parentFont.useFixedDefaultSize()) 3199 return; 3200 3201 // For now, lump all families but monospace together. 3202 if (childFont.genericFamily() != FontDescription::MonospaceFamily 3203 && parentFont.genericFamily() != FontDescription::MonospaceFamily) 3204 return; 3205 3206 // We know the parent is monospace or the child is monospace, and that font 3207 // size was unspecified. We want to scale our font size as appropriate. 3208 // If the font uses a keyword size, then we refetch from the table rather than 3209 // multiplying by our scale factor. 3210 float size; 3211 if (childFont.keywordSize()) 3212 size = fontSizeForKeyword(document(), CSSValueXxSmall + childFont.keywordSize() - 1, childFont.useFixedDefaultSize()); 3213 else { 3214 Settings* settings = documentSettings(); 3215 float fixedScaleFactor = (settings && settings->defaultFixedFontSize() && settings->defaultFontSize()) 3216 ? static_cast<float>(settings->defaultFixedFontSize()) / settings->defaultFontSize() 3217 : 1; 3218 size = parentFont.useFixedDefaultSize() ? 3219 childFont.specifiedSize() / fixedScaleFactor : 3220 childFont.specifiedSize() * fixedScaleFactor; 3221 } 3222 3223 FontDescription newFontDescription(childFont); 3224 setFontSize(newFontDescription, size); 3225 style->setFontDescription(newFontDescription); 3226} 3227 3228void StyleResolver::initializeFontStyle(Settings* settings) 3229{ 3230 FontDescription fontDescription; 3231 fontDescription.setGenericFamily(FontDescription::StandardFamily); 3232 fontDescription.setRenderingMode(settings->fontRenderingMode()); 3233 fontDescription.setUsePrinterFont(document()->printing() || !settings->screenFontSubstitutionEnabled()); 3234 const AtomicString& standardFontFamily = documentSettings()->standardFontFamily(); 3235 if (!standardFontFamily.isEmpty()) 3236 fontDescription.setOneFamily(standardFontFamily); 3237 fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1); 3238 setFontSize(fontDescription, fontSizeForKeyword(document(), CSSValueMedium, false)); 3239 m_state.style()->setLineHeight(RenderStyle::initialLineHeight()); 3240 m_state.setLineHeightValue(0); 3241 setFontDescription(fontDescription); 3242} 3243 3244void StyleResolver::setFontSize(FontDescription& fontDescription, float size) 3245{ 3246 fontDescription.setSpecifiedSize(size); 3247 fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(document(), m_state.style(), fontDescription.isAbsoluteSize(), size, useSVGZoomRules())); 3248} 3249 3250float StyleResolver::getComputedSizeFromSpecifiedSize(Document* document, RenderStyle* style, bool isAbsoluteSize, float specifiedSize, bool useSVGZoomRules) 3251{ 3252 float zoomFactor = 1.0f; 3253 if (!useSVGZoomRules) { 3254 zoomFactor = style->effectiveZoom(); 3255 if (Frame* frame = document->frame()) 3256 zoomFactor *= frame->textZoomFactor(); 3257 } 3258 3259 return StyleResolver::getComputedSizeFromSpecifiedSize(document, zoomFactor, isAbsoluteSize, specifiedSize); 3260} 3261 3262float StyleResolver::getComputedSizeFromSpecifiedSize(Document* document, float zoomFactor, bool isAbsoluteSize, float specifiedSize, ESmartMinimumForFontSize useSmartMinimumForFontSize) 3263{ 3264 // Text with a 0px font size should not be visible and therefore needs to be 3265 // exempt from minimum font size rules. Acid3 relies on this for pixel-perfect 3266 // rendering. This is also compatible with other browsers that have minimum 3267 // font size settings (e.g. Firefox). 3268 if (fabsf(specifiedSize) < std::numeric_limits<float>::epsilon()) 3269 return 0.0f; 3270 3271 // We support two types of minimum font size. The first is a hard override that applies to 3272 // all fonts. This is "minSize." The second type of minimum font size is a "smart minimum" 3273 // that is applied only when the Web page can't know what size it really asked for, e.g., 3274 // when it uses logical sizes like "small" or expresses the font-size as a percentage of 3275 // the user's default font setting. 3276 3277 // With the smart minimum, we never want to get smaller than the minimum font size to keep fonts readable. 3278 // However we always allow the page to set an explicit pixel size that is smaller, 3279 // since sites will mis-render otherwise (e.g., http://www.gamespot.com with a 9px minimum). 3280 3281 Settings* settings = document->settings(); 3282 if (!settings) 3283 return 1.0f; 3284 3285 int minSize = settings->minimumFontSize(); 3286 int minLogicalSize = settings->minimumLogicalFontSize(); 3287 float zoomedSize = specifiedSize * zoomFactor; 3288 3289 // Apply the hard minimum first. We only apply the hard minimum if after zooming we're still too small. 3290 if (zoomedSize < minSize) 3291 zoomedSize = minSize; 3292 3293 // Now apply the "smart minimum." This minimum is also only applied if we're still too small 3294 // after zooming. The font size must either be relative to the user default or the original size 3295 // must have been acceptable. In other words, we only apply the smart minimum whenever we're positive 3296 // doing so won't disrupt the layout. 3297 if (useSmartMinimumForFontSize && zoomedSize < minLogicalSize && (specifiedSize >= minLogicalSize || !isAbsoluteSize)) 3298 zoomedSize = minLogicalSize; 3299 3300 // Also clamp to a reasonable maximum to prevent insane font sizes from causing crashes on various 3301 // platforms (I'm looking at you, Windows.) 3302 return min(maximumAllowedFontSize, zoomedSize); 3303} 3304 3305const int fontSizeTableMax = 16; 3306const int fontSizeTableMin = 9; 3307const int totalKeywords = 8; 3308 3309// WinIE/Nav4 table for font sizes. Designed to match the legacy font mapping system of HTML. 3310static const int quirksFontSizeTable[fontSizeTableMax - fontSizeTableMin + 1][totalKeywords] = 3311{ 3312 { 9, 9, 9, 9, 11, 14, 18, 28 }, 3313 { 9, 9, 9, 10, 12, 15, 20, 31 }, 3314 { 9, 9, 9, 11, 13, 17, 22, 34 }, 3315 { 9, 9, 10, 12, 14, 18, 24, 37 }, 3316 { 9, 9, 10, 13, 16, 20, 26, 40 }, // fixed font default (13) 3317 { 9, 9, 11, 14, 17, 21, 28, 42 }, 3318 { 9, 10, 12, 15, 17, 23, 30, 45 }, 3319 { 9, 10, 13, 16, 18, 24, 32, 48 } // proportional font default (16) 3320}; 3321// HTML 1 2 3 4 5 6 7 3322// CSS xxs xs s m l xl xxl 3323// | 3324// user pref 3325 3326// Strict mode table matches MacIE and Mozilla's settings exactly. 3327static const int strictFontSizeTable[fontSizeTableMax - fontSizeTableMin + 1][totalKeywords] = 3328{ 3329 { 9, 9, 9, 9, 11, 14, 18, 27 }, 3330 { 9, 9, 9, 10, 12, 15, 20, 30 }, 3331 { 9, 9, 10, 11, 13, 17, 22, 33 }, 3332 { 9, 9, 10, 12, 14, 18, 24, 36 }, 3333 { 9, 10, 12, 13, 16, 20, 26, 39 }, // fixed font default (13) 3334 { 9, 10, 12, 14, 17, 21, 28, 42 }, 3335 { 9, 10, 13, 15, 18, 23, 30, 45 }, 3336 { 9, 10, 13, 16, 18, 24, 32, 48 } // proportional font default (16) 3337}; 3338// HTML 1 2 3 4 5 6 7 3339// CSS xxs xs s m l xl xxl 3340// | 3341// user pref 3342 3343// For values outside the range of the table, we use Todd Fahrner's suggested scale 3344// factors for each keyword value. 3345static const float fontSizeFactors[totalKeywords] = { 0.60f, 0.75f, 0.89f, 1.0f, 1.2f, 1.5f, 2.0f, 3.0f }; 3346 3347float StyleResolver::fontSizeForKeyword(Document* document, int keyword, bool shouldUseFixedDefaultSize) 3348{ 3349 Settings* settings = document->settings(); 3350 if (!settings) 3351 return 1.0f; 3352 3353 bool quirksMode = document->inQuirksMode(); 3354 int mediumSize = shouldUseFixedDefaultSize ? settings->defaultFixedFontSize() : settings->defaultFontSize(); 3355 if (mediumSize >= fontSizeTableMin && mediumSize <= fontSizeTableMax) { 3356 // Look up the entry in the table. 3357 int row = mediumSize - fontSizeTableMin; 3358 int col = (keyword - CSSValueXxSmall); 3359 return quirksMode ? quirksFontSizeTable[row][col] : strictFontSizeTable[row][col]; 3360 } 3361 3362 // Value is outside the range of the table. Apply the scale factor instead. 3363 float minLogicalSize = max(settings->minimumLogicalFontSize(), 1); 3364 return max(fontSizeFactors[keyword - CSSValueXxSmall]*mediumSize, minLogicalSize); 3365} 3366 3367template<typename T> 3368static int findNearestLegacyFontSize(int pixelFontSize, const T* table, int multiplier) 3369{ 3370 // Ignore table[0] because xx-small does not correspond to any legacy font size. 3371 for (int i = 1; i < totalKeywords - 1; i++) { 3372 if (pixelFontSize * 2 < (table[i] + table[i + 1]) * multiplier) 3373 return i; 3374 } 3375 return totalKeywords - 1; 3376} 3377 3378int StyleResolver::legacyFontSize(Document* document, int pixelFontSize, bool shouldUseFixedDefaultSize) 3379{ 3380 Settings* settings = document->settings(); 3381 if (!settings) 3382 return 1; 3383 3384 bool quirksMode = document->inQuirksMode(); 3385 int mediumSize = shouldUseFixedDefaultSize ? settings->defaultFixedFontSize() : settings->defaultFontSize(); 3386 if (mediumSize >= fontSizeTableMin && mediumSize <= fontSizeTableMax) { 3387 int row = mediumSize - fontSizeTableMin; 3388 return findNearestLegacyFontSize<int>(pixelFontSize, quirksMode ? quirksFontSizeTable[row] : strictFontSizeTable[row], 1); 3389 } 3390 3391 return findNearestLegacyFontSize<float>(pixelFontSize, fontSizeFactors, mediumSize); 3392} 3393 3394static Color colorForCSSValue(int cssValueId) 3395{ 3396 struct ColorValue { 3397 int cssValueId; 3398 RGBA32 color; 3399 }; 3400 3401 static const ColorValue colorValues[] = { 3402 { CSSValueAqua, 0xFF00FFFF }, 3403 { CSSValueBlack, 0xFF000000 }, 3404 { CSSValueBlue, 0xFF0000FF }, 3405 { CSSValueFuchsia, 0xFFFF00FF }, 3406 { CSSValueGray, 0xFF808080 }, 3407 { CSSValueGreen, 0xFF008000 }, 3408 { CSSValueGrey, 0xFF808080 }, 3409 { CSSValueLime, 0xFF00FF00 }, 3410 { CSSValueMaroon, 0xFF800000 }, 3411 { CSSValueNavy, 0xFF000080 }, 3412 { CSSValueOlive, 0xFF808000 }, 3413 { CSSValueOrange, 0xFFFFA500 }, 3414 { CSSValuePurple, 0xFF800080 }, 3415 { CSSValueRed, 0xFFFF0000 }, 3416 { CSSValueSilver, 0xFFC0C0C0 }, 3417 { CSSValueTeal, 0xFF008080 }, 3418 { CSSValueTransparent, 0x00000000 }, 3419 { CSSValueWhite, 0xFFFFFFFF }, 3420 { CSSValueYellow, 0xFFFFFF00 }, 3421 { 0, 0 } 3422 }; 3423 3424 for (const ColorValue* col = colorValues; col->cssValueId; ++col) { 3425 if (col->cssValueId == cssValueId) 3426 return col->color; 3427 } 3428 return RenderTheme::defaultTheme()->systemColor(cssValueId); 3429} 3430 3431bool StyleResolver::colorFromPrimitiveValueIsDerivedFromElement(CSSPrimitiveValue* value) 3432{ 3433 int ident = value->getIdent(); 3434 switch (ident) { 3435 case CSSValueWebkitText: 3436 case CSSValueWebkitLink: 3437 case CSSValueWebkitActivelink: 3438 case CSSValueCurrentcolor: 3439 return true; 3440 default: 3441 return false; 3442 } 3443} 3444 3445Color StyleResolver::colorFromPrimitiveValue(CSSPrimitiveValue* value, bool forVisitedLink) const 3446{ 3447 if (value->isRGBColor()) 3448 return Color(value->getRGBA32Value()); 3449 3450 const State& state = m_state; 3451 int ident = value->getIdent(); 3452 switch (ident) { 3453 case 0: 3454 return Color(); 3455 case CSSValueWebkitText: 3456 return state.document()->textColor(); 3457 case CSSValueWebkitLink: 3458 return (state.element()->isLink() && forVisitedLink) ? state.document()->visitedLinkColor() : state.document()->linkColor(); 3459 case CSSValueWebkitActivelink: 3460 return state.document()->activeLinkColor(); 3461 case CSSValueWebkitFocusRingColor: 3462 return RenderTheme::focusRingColor(); 3463 case CSSValueCurrentcolor: 3464 return state.style()->color(); 3465 default: 3466 return colorForCSSValue(ident); 3467 } 3468} 3469 3470void StyleResolver::addViewportDependentMediaQueryResult(const MediaQueryExp* expr, bool result) 3471{ 3472 m_viewportDependentMediaQueryResults.append(adoptPtr(new MediaQueryResult(*expr, result))); 3473} 3474 3475bool StyleResolver::affectedByViewportChange() const 3476{ 3477 unsigned s = m_viewportDependentMediaQueryResults.size(); 3478 for (unsigned i = 0; i < s; i++) { 3479 if (m_medium->eval(&m_viewportDependentMediaQueryResults[i]->m_expression) != m_viewportDependentMediaQueryResults[i]->m_result) 3480 return true; 3481 } 3482 return false; 3483} 3484 3485#if ENABLE(CSS_FILTERS) 3486static FilterOperation::OperationType filterOperationForType(WebKitCSSFilterValue::FilterOperationType type) 3487{ 3488 switch (type) { 3489 case WebKitCSSFilterValue::ReferenceFilterOperation: 3490 return FilterOperation::REFERENCE; 3491 case WebKitCSSFilterValue::GrayscaleFilterOperation: 3492 return FilterOperation::GRAYSCALE; 3493 case WebKitCSSFilterValue::SepiaFilterOperation: 3494 return FilterOperation::SEPIA; 3495 case WebKitCSSFilterValue::SaturateFilterOperation: 3496 return FilterOperation::SATURATE; 3497 case WebKitCSSFilterValue::HueRotateFilterOperation: 3498 return FilterOperation::HUE_ROTATE; 3499 case WebKitCSSFilterValue::InvertFilterOperation: 3500 return FilterOperation::INVERT; 3501 case WebKitCSSFilterValue::OpacityFilterOperation: 3502 return FilterOperation::OPACITY; 3503 case WebKitCSSFilterValue::BrightnessFilterOperation: 3504 return FilterOperation::BRIGHTNESS; 3505 case WebKitCSSFilterValue::ContrastFilterOperation: 3506 return FilterOperation::CONTRAST; 3507 case WebKitCSSFilterValue::BlurFilterOperation: 3508 return FilterOperation::BLUR; 3509 case WebKitCSSFilterValue::DropShadowFilterOperation: 3510 return FilterOperation::DROP_SHADOW; 3511#if ENABLE(CSS_SHADERS) 3512 case WebKitCSSFilterValue::CustomFilterOperation: 3513 return FilterOperation::CUSTOM; 3514#endif 3515 case WebKitCSSFilterValue::UnknownFilterOperation: 3516 return FilterOperation::NONE; 3517 } 3518 return FilterOperation::NONE; 3519} 3520 3521#if ENABLE(CSS_FILTERS) && ENABLE(SVG) 3522void StyleResolver::loadPendingSVGDocuments() 3523{ 3524 State& state = m_state; 3525 3526 // Crash reports indicate that we've seen calls to this function when our 3527 // style is NULL. We don't know exactly why this happens. Our guess is 3528 // reentering styleForElement(). 3529 ASSERT(state.style()); 3530 if (!state.style() || !state.style()->hasFilter() || state.pendingSVGDocuments().isEmpty()) 3531 return; 3532 3533 CachedResourceLoader* cachedResourceLoader = state.document()->cachedResourceLoader(); 3534 Vector<RefPtr<FilterOperation> >& filterOperations = state.style()->mutableFilter().operations(); 3535 for (unsigned i = 0; i < filterOperations.size(); ++i) { 3536 RefPtr<FilterOperation> filterOperation = filterOperations.at(i); 3537 if (filterOperation->getOperationType() == FilterOperation::REFERENCE) { 3538 ReferenceFilterOperation* referenceFilter = static_cast<ReferenceFilterOperation*>(filterOperation.get()); 3539 3540 WebKitCSSSVGDocumentValue* value = state.pendingSVGDocuments().get(referenceFilter); 3541 if (!value) 3542 continue; 3543 CachedSVGDocument* cachedDocument = value->load(cachedResourceLoader); 3544 if (!cachedDocument) 3545 continue; 3546 3547 // Stash the CachedSVGDocument on the reference filter. 3548 referenceFilter->setCachedSVGDocumentReference(adoptPtr(new CachedSVGDocumentReference(cachedDocument))); 3549 } 3550 } 3551 state.pendingSVGDocuments().clear(); 3552} 3553#endif 3554 3555#if ENABLE(CSS_SHADERS) 3556StyleShader* StyleResolver::styleShader(CSSValue* value) 3557{ 3558 if (value->isWebKitCSSShaderValue()) 3559 return cachedOrPendingStyleShaderFromValue(static_cast<WebKitCSSShaderValue*>(value)); 3560 return 0; 3561} 3562 3563StyleShader* StyleResolver::cachedOrPendingStyleShaderFromValue(WebKitCSSShaderValue* value) 3564{ 3565 StyleShader* shader = value->cachedOrPendingShader(); 3566 if (shader && shader->isPendingShader()) 3567 m_state.setHasPendingShaders(true); 3568 return shader; 3569} 3570 3571PassRefPtr<CustomFilterProgram> StyleResolver::lookupCustomFilterProgram(WebKitCSSShaderValue* vertexShader, WebKitCSSShaderValue* fragmentShader, 3572 CustomFilterProgramType programType, const CustomFilterProgramMixSettings& mixSettings, CustomFilterMeshType meshType) 3573{ 3574 CachedResourceLoader* cachedResourceLoader = m_state.document()->cachedResourceLoader(); 3575 KURL vertexShaderURL = vertexShader ? vertexShader->completeURL(cachedResourceLoader) : KURL(); 3576 KURL fragmentShaderURL = fragmentShader ? fragmentShader->completeURL(cachedResourceLoader) : KURL(); 3577 RefPtr<StyleCustomFilterProgram> program; 3578 if (m_customFilterProgramCache) 3579 program = m_customFilterProgramCache->lookup(CustomFilterProgramInfo(vertexShaderURL, fragmentShaderURL, programType, mixSettings, meshType)); 3580 if (!program) { 3581 // Create a new StyleCustomFilterProgram that will be resolved during the loadPendingShaders and added to the cache. 3582 program = StyleCustomFilterProgram::create(vertexShaderURL, vertexShader ? styleShader(vertexShader) : 0, 3583 fragmentShaderURL, fragmentShader ? styleShader(fragmentShader) : 0, programType, mixSettings, meshType); 3584 } 3585 return program.release(); 3586} 3587 3588void StyleResolver::loadPendingShaders() 3589{ 3590 // FIXME: We shouldn't have to check that style is non-null. This is a speculative fix for: 3591 // https://bugs.webkit.org/show_bug.cgi?id=117665 3592 if (!m_state.hasPendingShaders() || !m_state.style() || !m_state.style()->hasFilter()) 3593 return; 3594 3595 CachedResourceLoader* cachedResourceLoader = m_state.document()->cachedResourceLoader(); 3596 3597 Vector<RefPtr<FilterOperation> >& filterOperations = m_state.style()->mutableFilter().operations(); 3598 for (unsigned i = 0; i < filterOperations.size(); ++i) { 3599 RefPtr<FilterOperation> filterOperation = filterOperations.at(i); 3600 if (filterOperation->getOperationType() == FilterOperation::CUSTOM) { 3601 CustomFilterOperation* customFilter = static_cast<CustomFilterOperation*>(filterOperation.get()); 3602 ASSERT(customFilter->program()); 3603 StyleCustomFilterProgram* program = static_cast<StyleCustomFilterProgram*>(customFilter->program()); 3604 // Note that the StylePendingShaders could be already resolved to StyleCachedShaders. That's because the rule was matched before. 3605 // However, the StyleCustomFilterProgram that was initially created could have been removed from the cache in the meanwhile, 3606 // meaning that we get a new StyleCustomFilterProgram here that is not yet in the cache, but already has loaded StyleShaders. 3607 if (!program->hasPendingShaders() && program->inCache()) 3608 continue; 3609 if (!m_customFilterProgramCache) 3610 m_customFilterProgramCache = adoptPtr(new StyleCustomFilterProgramCache()); 3611 RefPtr<StyleCustomFilterProgram> styleProgram = m_customFilterProgramCache->lookup(program); 3612 if (styleProgram.get()) 3613 customFilter->setProgram(styleProgram.release()); 3614 else { 3615 if (program->vertexShader() && program->vertexShader()->isPendingShader()) { 3616 WebKitCSSShaderValue* shaderValue = static_cast<StylePendingShader*>(program->vertexShader())->cssShaderValue(); 3617 program->setVertexShader(shaderValue->cachedShader(cachedResourceLoader)); 3618 } 3619 if (program->fragmentShader() && program->fragmentShader()->isPendingShader()) { 3620 WebKitCSSShaderValue* shaderValue = static_cast<StylePendingShader*>(program->fragmentShader())->cssShaderValue(); 3621 program->setFragmentShader(shaderValue->cachedShader(cachedResourceLoader)); 3622 } 3623 m_customFilterProgramCache->add(program); 3624 } 3625 } 3626 } 3627 m_state.setHasPendingShaders(false); 3628} 3629 3630static bool sortParametersByNameComparator(const RefPtr<CustomFilterParameter>& a, const RefPtr<CustomFilterParameter>& b) 3631{ 3632 return codePointCompareLessThan(a->name(), b->name()); 3633} 3634 3635PassRefPtr<CustomFilterParameter> StyleResolver::parseCustomFilterArrayParameter(const String& name, CSSValueList* values, bool isArray) 3636{ 3637 RefPtr<CustomFilterArrayParameter> arrayParameter = CustomFilterArrayParameter::create(name, isArray ? CustomFilterArrayParameter::ARRAY : CustomFilterArrayParameter::MATRIX); 3638 for (unsigned i = 0, length = values->length(); i < length; ++i) { 3639 CSSValue* value = values->itemWithoutBoundsCheck(i); 3640 if (!value->isPrimitiveValue()) 3641 return 0; 3642 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); 3643 if (primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER) 3644 return 0; 3645 arrayParameter->addValue(primitiveValue->getDoubleValue()); 3646 } 3647 return arrayParameter.release(); 3648} 3649 3650PassRefPtr<CustomFilterParameter> StyleResolver::parseCustomFilterColorParameter(const String& name, CSSValueList* values) 3651{ 3652 ASSERT(values->length()); 3653 CSSPrimitiveValue* firstPrimitiveValue = static_cast<CSSPrimitiveValue*>(values->itemWithoutBoundsCheck(0)); 3654 RefPtr<CustomFilterColorParameter> colorParameter = CustomFilterColorParameter::create(name); 3655 colorParameter->setColor(Color(firstPrimitiveValue->getRGBA32Value())); 3656 return colorParameter.release(); 3657} 3658 3659PassRefPtr<CustomFilterParameter> StyleResolver::parseCustomFilterNumberParameter(const String& name, CSSValueList* values) 3660{ 3661 RefPtr<CustomFilterNumberParameter> numberParameter = CustomFilterNumberParameter::create(name); 3662 for (unsigned i = 0; i < values->length(); ++i) { 3663 CSSValue* value = values->itemWithoutBoundsCheck(i); 3664 if (!value->isPrimitiveValue()) 3665 return 0; 3666 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); 3667 if (primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER) 3668 return 0; 3669 numberParameter->addValue(primitiveValue->getDoubleValue()); 3670 } 3671 return numberParameter.release(); 3672} 3673 3674PassRefPtr<CustomFilterParameter> StyleResolver::parseCustomFilterTransformParameter(const String& name, CSSValueList* values) 3675{ 3676 RefPtr<CustomFilterTransformParameter> transformParameter = CustomFilterTransformParameter::create(name); 3677 TransformOperations operations; 3678 transformsForValue(m_state.style(), m_state.rootElementStyle(), values, operations); 3679 transformParameter->setOperations(operations); 3680 return transformParameter.release(); 3681} 3682 3683PassRefPtr<CustomFilterParameter> StyleResolver::parseCustomFilterParameter(const String& name, CSSValue* parameterValue) 3684{ 3685 // FIXME: Implement other parameters types parsing. 3686 // textures: https://bugs.webkit.org/show_bug.cgi?id=71442 3687 // mat2, mat3, mat4: https://bugs.webkit.org/show_bug.cgi?id=71444 3688 // Number parameters are wrapped inside a CSSValueList and all 3689 // the other functions values inherit from CSSValueList. 3690 if (!parameterValue->isValueList()) 3691 return 0; 3692 3693 CSSValueList* values = static_cast<CSSValueList*>(parameterValue); 3694 if (!values->length()) 3695 return 0; 3696 3697 if (parameterValue->isWebKitCSSArrayFunctionValue()) 3698 return parseCustomFilterArrayParameter(name, values, true); 3699 3700 if (parameterValue->isWebKitCSSMatFunctionValue()) 3701 return parseCustomFilterArrayParameter(name, values, false); 3702 3703 // If the first value of the list is a transform function, 3704 // then we could safely assume that all the remaining items 3705 // are transforms. parseCustomFilterTransformParameter will 3706 // return 0 if that assumption is incorrect. 3707 if (values->itemWithoutBoundsCheck(0)->isWebKitCSSTransformValue()) 3708 return parseCustomFilterTransformParameter(name, values); 3709 3710 // We can only have arrays of colors or numbers, so use the first value to choose between those two. 3711 // We need up to 4 values (all booleans or all numbers). 3712 if (!values->itemWithoutBoundsCheck(0)->isPrimitiveValue() || values->length() > 4) 3713 return 0; 3714 3715 CSSPrimitiveValue* firstPrimitiveValue = static_cast<CSSPrimitiveValue*>(values->itemWithoutBoundsCheck(0)); 3716 if (firstPrimitiveValue->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) 3717 return parseCustomFilterNumberParameter(name, values); 3718 3719 if (firstPrimitiveValue->primitiveType() == CSSPrimitiveValue::CSS_RGBCOLOR) 3720 return parseCustomFilterColorParameter(name, values); 3721 3722 return 0; 3723} 3724 3725bool StyleResolver::parseCustomFilterParameterList(CSSValue* parametersValue, CustomFilterParameterList& parameterList) 3726{ 3727 HashSet<String> knownParameterNames; 3728 CSSValueListIterator parameterIterator(parametersValue); 3729 for (; parameterIterator.hasMore(); parameterIterator.advance()) { 3730 if (!parameterIterator.value()->isValueList()) 3731 return false; 3732 CSSValueListIterator iterator(parameterIterator.value()); 3733 if (!iterator.isPrimitiveValue()) 3734 return false; 3735 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(iterator.value()); 3736 if (primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_STRING) 3737 return false; 3738 3739 String name = primitiveValue->getStringValue(); 3740 // Do not allow duplicate parameter names. 3741 if (knownParameterNames.contains(name)) 3742 return false; 3743 knownParameterNames.add(name); 3744 3745 iterator.advance(); 3746 3747 if (!iterator.hasMore()) 3748 return false; 3749 3750 RefPtr<CustomFilterParameter> parameter = parseCustomFilterParameter(name, iterator.value()); 3751 if (!parameter) 3752 return false; 3753 parameterList.append(parameter.release()); 3754 } 3755 3756 // Make sure we sort the parameters before passing them down to the CustomFilterOperation. 3757 std::sort(parameterList.begin(), parameterList.end(), sortParametersByNameComparator); 3758 3759 return true; 3760} 3761 3762PassRefPtr<CustomFilterOperation> StyleResolver::createCustomFilterOperationWithAtRuleReferenceSyntax(WebKitCSSFilterValue* filterValue) 3763{ 3764 // FIXME: Implement style resolution for the custom filter at-rule reference syntax. 3765 UNUSED_PARAM(filterValue); 3766 return 0; 3767} 3768 3769PassRefPtr<CustomFilterOperation> StyleResolver::createCustomFilterOperationWithInlineSyntax(WebKitCSSFilterValue* filterValue) 3770{ 3771 CSSValue* shadersValue = filterValue->itemWithoutBoundsCheck(0); 3772 ASSERT_WITH_SECURITY_IMPLICATION(shadersValue->isValueList()); 3773 CSSValueList* shadersList = static_cast<CSSValueList*>(shadersValue); 3774 3775 unsigned shadersListLength = shadersList->length(); 3776 ASSERT(shadersListLength); 3777 3778 WebKitCSSShaderValue* vertexShader = toWebKitCSSShaderValue(shadersList->itemWithoutBoundsCheck(0)); 3779 WebKitCSSShaderValue* fragmentShader = 0; 3780 CustomFilterProgramType programType = PROGRAM_TYPE_BLENDS_ELEMENT_TEXTURE; 3781 CustomFilterProgramMixSettings mixSettings; 3782 3783 if (shadersListLength > 1) { 3784 CSSValue* fragmentShaderOrMixFunction = shadersList->itemWithoutBoundsCheck(1); 3785 if (fragmentShaderOrMixFunction->isWebKitCSSMixFunctionValue()) { 3786 WebKitCSSMixFunctionValue* mixFunction = static_cast<WebKitCSSMixFunctionValue*>(fragmentShaderOrMixFunction); 3787 CSSValueListIterator iterator(mixFunction); 3788 3789 ASSERT(mixFunction->length()); 3790 fragmentShader = toWebKitCSSShaderValue(iterator.value()); 3791 iterator.advance(); 3792 3793 ASSERT(mixFunction->length() <= 3); 3794 while (iterator.hasMore()) { 3795 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(iterator.value()); 3796 if (CSSParser::isBlendMode(primitiveValue->getIdent())) 3797 mixSettings.blendMode = *primitiveValue; 3798 else if (CSSParser::isCompositeOperator(primitiveValue->getIdent())) 3799 mixSettings.compositeOperator = *primitiveValue; 3800 else 3801 ASSERT_NOT_REACHED(); 3802 iterator.advance(); 3803 } 3804 } else { 3805 programType = PROGRAM_TYPE_NO_ELEMENT_TEXTURE; 3806 fragmentShader = toWebKitCSSShaderValue(fragmentShaderOrMixFunction); 3807 } 3808 } 3809 3810 if (!vertexShader && !fragmentShader) 3811 return 0; 3812 3813 unsigned meshRows = 1; 3814 unsigned meshColumns = 1; 3815 CustomFilterMeshType meshType = MeshTypeAttached; 3816 3817 CSSValue* parametersValue = 0; 3818 3819 if (filterValue->length() > 1) { 3820 CSSValueListIterator iterator(filterValue->itemWithoutBoundsCheck(1)); 3821 3822 // The second value might be the mesh box or the list of parameters: 3823 // If it starts with a number or any of the mesh-box identifiers it is 3824 // the mesh-box list, if not it means it is the parameters list. 3825 3826 if (iterator.hasMore() && iterator.isPrimitiveValue()) { 3827 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(iterator.value()); 3828 if (primitiveValue->isNumber()) { 3829 // If only one integer value is specified, it will set both 3830 // the rows and the columns. 3831 meshColumns = meshRows = primitiveValue->getIntValue(); 3832 iterator.advance(); 3833 3834 // Try to match another number for the rows. 3835 if (iterator.hasMore() && iterator.isPrimitiveValue()) { 3836 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(iterator.value()); 3837 if (primitiveValue->isNumber()) { 3838 meshRows = primitiveValue->getIntValue(); 3839 iterator.advance(); 3840 } 3841 } 3842 } 3843 } 3844 3845 if (iterator.hasMore() && iterator.isPrimitiveValue()) { 3846 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(iterator.value()); 3847 if (primitiveValue->getIdent() == CSSValueDetached) { 3848 meshType = MeshTypeDetached; 3849 iterator.advance(); 3850 } 3851 } 3852 3853 if (!iterator.index()) { 3854 // If no value was consumed from the mesh value, then it is just a parameter list, meaning that we end up 3855 // having just two CSSListValues: list of shaders and list of parameters. 3856 ASSERT(filterValue->length() == 2); 3857 parametersValue = filterValue->itemWithoutBoundsCheck(1); 3858 } 3859 } 3860 3861 if (filterValue->length() > 2 && !parametersValue) 3862 parametersValue = filterValue->itemWithoutBoundsCheck(2); 3863 3864 CustomFilterParameterList parameterList; 3865 if (parametersValue && !parseCustomFilterParameterList(parametersValue, parameterList)) 3866 return 0; 3867 3868 RefPtr<CustomFilterProgram> program = lookupCustomFilterProgram(vertexShader, fragmentShader, programType, mixSettings, meshType); 3869 return CustomFilterOperation::create(program.release(), parameterList, meshRows, meshColumns); 3870} 3871 3872PassRefPtr<CustomFilterOperation> StyleResolver::createCustomFilterOperation(WebKitCSSFilterValue* filterValue) 3873{ 3874 ASSERT(filterValue->length()); 3875 bool isAtRuleReferenceSyntax = filterValue->itemWithoutBoundsCheck(0)->isPrimitiveValue(); 3876 return isAtRuleReferenceSyntax ? createCustomFilterOperationWithAtRuleReferenceSyntax(filterValue) : createCustomFilterOperationWithInlineSyntax(filterValue); 3877} 3878 3879#endif 3880 3881bool StyleResolver::createFilterOperations(CSSValue* inValue, RenderStyle* style, RenderStyle* rootStyle, FilterOperations& outOperations) 3882{ 3883 ASSERT(outOperations.isEmpty()); 3884 3885 if (!inValue) 3886 return false; 3887 3888 if (inValue->isPrimitiveValue()) { 3889 CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(inValue); 3890 if (primitiveValue->getIdent() == CSSValueNone) 3891 return true; 3892 } 3893 3894 if (!inValue->isValueList()) 3895 return false; 3896 3897 float zoomFactor = style ? style->effectiveZoom() : 1; 3898 FilterOperations operations; 3899 for (CSSValueListIterator i = inValue; i.hasMore(); i.advance()) { 3900 CSSValue* currValue = i.value(); 3901 if (!currValue->isWebKitCSSFilterValue()) 3902 continue; 3903 3904 WebKitCSSFilterValue* filterValue = static_cast<WebKitCSSFilterValue*>(i.value()); 3905 FilterOperation::OperationType operationType = filterOperationForType(filterValue->operationType()); 3906 3907#if ENABLE(CSS_SHADERS) 3908 if (operationType == FilterOperation::VALIDATED_CUSTOM) { 3909 // ValidatedCustomFilterOperation is not supposed to end up in the RenderStyle. 3910 ASSERT_NOT_REACHED(); 3911 continue; 3912 } 3913 if (operationType == FilterOperation::CUSTOM) { 3914 RefPtr<CustomFilterOperation> operation = createCustomFilterOperation(filterValue); 3915 if (!operation) 3916 return false; 3917 3918 operations.operations().append(operation); 3919 continue; 3920 } 3921#endif 3922 if (operationType == FilterOperation::REFERENCE) { 3923#if ENABLE(SVG) 3924 if (filterValue->length() != 1) 3925 continue; 3926 CSSValue* argument = filterValue->itemWithoutBoundsCheck(0); 3927 3928 if (!argument->isWebKitCSSSVGDocumentValue()) 3929 continue; 3930 3931 WebKitCSSSVGDocumentValue* svgDocumentValue = static_cast<WebKitCSSSVGDocumentValue*>(argument); 3932 KURL url = m_state.document()->completeURL(svgDocumentValue->url()); 3933 3934 RefPtr<ReferenceFilterOperation> operation = ReferenceFilterOperation::create(svgDocumentValue->url(), url.fragmentIdentifier()); 3935 if (SVGURIReference::isExternalURIReference(svgDocumentValue->url(), m_state.document())) { 3936 if (!svgDocumentValue->loadRequested()) 3937 m_state.pendingSVGDocuments().set(operation.get(), svgDocumentValue); 3938 else if (svgDocumentValue->cachedSVGDocument()) 3939 operation->setCachedSVGDocumentReference(adoptPtr(new CachedSVGDocumentReference(svgDocumentValue->cachedSVGDocument()))); 3940 } 3941 operations.operations().append(operation); 3942#endif 3943 continue; 3944 } 3945 3946 // Check that all parameters are primitive values, with the 3947 // exception of drop shadow which has a ShadowValue parameter. 3948 if (operationType != FilterOperation::DROP_SHADOW) { 3949 bool haveNonPrimitiveValue = false; 3950 for (unsigned j = 0; j < filterValue->length(); ++j) { 3951 if (!filterValue->itemWithoutBoundsCheck(j)->isPrimitiveValue()) { 3952 haveNonPrimitiveValue = true; 3953 break; 3954 } 3955 } 3956 if (haveNonPrimitiveValue) 3957 continue; 3958 } 3959 3960 CSSPrimitiveValue* firstValue = filterValue->length() ? static_cast<CSSPrimitiveValue*>(filterValue->itemWithoutBoundsCheck(0)) : 0; 3961 switch (filterValue->operationType()) { 3962 case WebKitCSSFilterValue::GrayscaleFilterOperation: 3963 case WebKitCSSFilterValue::SepiaFilterOperation: 3964 case WebKitCSSFilterValue::SaturateFilterOperation: { 3965 double amount = 1; 3966 if (filterValue->length() == 1) { 3967 amount = firstValue->getDoubleValue(); 3968 if (firstValue->isPercentage()) 3969 amount /= 100; 3970 } 3971 3972 operations.operations().append(BasicColorMatrixFilterOperation::create(amount, operationType)); 3973 break; 3974 } 3975 case WebKitCSSFilterValue::HueRotateFilterOperation: { 3976 double angle = 0; 3977 if (filterValue->length() == 1) 3978 angle = firstValue->computeDegrees(); 3979 3980 operations.operations().append(BasicColorMatrixFilterOperation::create(angle, operationType)); 3981 break; 3982 } 3983 case WebKitCSSFilterValue::InvertFilterOperation: 3984 case WebKitCSSFilterValue::BrightnessFilterOperation: 3985 case WebKitCSSFilterValue::ContrastFilterOperation: 3986 case WebKitCSSFilterValue::OpacityFilterOperation: { 3987 double amount = (filterValue->operationType() == WebKitCSSFilterValue::BrightnessFilterOperation) ? 0 : 1; 3988 if (filterValue->length() == 1) { 3989 amount = firstValue->getDoubleValue(); 3990 if (firstValue->isPercentage()) 3991 amount /= 100; 3992 } 3993 3994 operations.operations().append(BasicComponentTransferFilterOperation::create(amount, operationType)); 3995 break; 3996 } 3997 case WebKitCSSFilterValue::BlurFilterOperation: { 3998 Length stdDeviation = Length(0, Fixed); 3999 if (filterValue->length() >= 1) 4000 stdDeviation = convertToFloatLength(firstValue, style, rootStyle, zoomFactor); 4001 if (stdDeviation.isUndefined()) 4002 return false; 4003 4004 operations.operations().append(BlurFilterOperation::create(stdDeviation)); 4005 break; 4006 } 4007 case WebKitCSSFilterValue::DropShadowFilterOperation: { 4008 if (filterValue->length() != 1) 4009 return false; 4010 4011 CSSValue* cssValue = filterValue->itemWithoutBoundsCheck(0); 4012 if (!cssValue->isShadowValue()) 4013 continue; 4014 4015 ShadowValue* item = static_cast<ShadowValue*>(cssValue); 4016 IntPoint location(item->x->computeLength<int>(style, rootStyle, zoomFactor), 4017 item->y->computeLength<int>(style, rootStyle, zoomFactor)); 4018 int blur = item->blur ? item->blur->computeLength<int>(style, rootStyle, zoomFactor) : 0; 4019 Color color; 4020 if (item->color) 4021 color = colorFromPrimitiveValue(item->color.get()); 4022 4023 operations.operations().append(DropShadowFilterOperation::create(location, blur, color.isValid() ? color : Color::transparent)); 4024 break; 4025 } 4026 case WebKitCSSFilterValue::UnknownFilterOperation: 4027 default: 4028 ASSERT_NOT_REACHED(); 4029 break; 4030 } 4031 } 4032 4033 outOperations = operations; 4034 return true; 4035} 4036 4037#endif 4038 4039PassRefPtr<StyleImage> StyleResolver::loadPendingImage(StylePendingImage* pendingImage) 4040{ 4041 CachedResourceLoader* cachedResourceLoader = m_state.document()->cachedResourceLoader(); 4042 4043 if (pendingImage->cssImageValue()) { 4044 CSSImageValue* imageValue = pendingImage->cssImageValue(); 4045 return imageValue->cachedImage(cachedResourceLoader); 4046 } 4047 4048 if (pendingImage->cssImageGeneratorValue()) { 4049 CSSImageGeneratorValue* imageGeneratorValue = pendingImage->cssImageGeneratorValue(); 4050 imageGeneratorValue->loadSubimages(cachedResourceLoader); 4051 return StyleGeneratedImage::create(imageGeneratorValue); 4052 } 4053 4054 if (pendingImage->cssCursorImageValue()) { 4055 CSSCursorImageValue* cursorImageValue = pendingImage->cssCursorImageValue(); 4056 return cursorImageValue->cachedImage(cachedResourceLoader); 4057 } 4058 4059#if ENABLE(CSS_IMAGE_SET) 4060 if (pendingImage->cssImageSetValue()) { 4061 CSSImageSetValue* imageSetValue = pendingImage->cssImageSetValue(); 4062 return imageSetValue->cachedImageSet(cachedResourceLoader); 4063 } 4064#endif 4065 4066 return 0; 4067} 4068 4069void StyleResolver::loadPendingImages() 4070{ 4071 if (m_state.pendingImageProperties().isEmpty()) 4072 return; 4073 4074 PendingImagePropertyMap::const_iterator::Keys end = m_state.pendingImageProperties().end().keys(); 4075 for (PendingImagePropertyMap::const_iterator::Keys it = m_state.pendingImageProperties().begin().keys(); it != end; ++it) { 4076 CSSPropertyID currentProperty = *it; 4077 4078 switch (currentProperty) { 4079 case CSSPropertyBackgroundImage: { 4080 for (FillLayer* backgroundLayer = m_state.style()->accessBackgroundLayers(); backgroundLayer; backgroundLayer = backgroundLayer->next()) { 4081 if (backgroundLayer->image() && backgroundLayer->image()->isPendingImage()) 4082 backgroundLayer->setImage(loadPendingImage(static_cast<StylePendingImage*>(backgroundLayer->image()))); 4083 } 4084 break; 4085 } 4086 case CSSPropertyContent: { 4087 for (ContentData* contentData = const_cast<ContentData*>(m_state.style()->contentData()); contentData; contentData = contentData->next()) { 4088 if (contentData->isImage()) { 4089 StyleImage* image = static_cast<ImageContentData*>(contentData)->image(); 4090 if (image->isPendingImage()) { 4091 RefPtr<StyleImage> loadedImage = loadPendingImage(static_cast<StylePendingImage*>(image)); 4092 if (loadedImage) 4093 static_cast<ImageContentData*>(contentData)->setImage(loadedImage.release()); 4094 } 4095 } 4096 } 4097 break; 4098 } 4099 case CSSPropertyCursor: { 4100 if (CursorList* cursorList = m_state.style()->cursors()) { 4101 for (size_t i = 0; i < cursorList->size(); ++i) { 4102 CursorData& currentCursor = cursorList->at(i); 4103 if (StyleImage* image = currentCursor.image()) { 4104 if (image->isPendingImage()) 4105 currentCursor.setImage(loadPendingImage(static_cast<StylePendingImage*>(image))); 4106 } 4107 } 4108 } 4109 break; 4110 } 4111 case CSSPropertyListStyleImage: { 4112 if (m_state.style()->listStyleImage() && m_state.style()->listStyleImage()->isPendingImage()) 4113 m_state.style()->setListStyleImage(loadPendingImage(static_cast<StylePendingImage*>(m_state.style()->listStyleImage()))); 4114 break; 4115 } 4116 case CSSPropertyBorderImageSource: { 4117 if (m_state.style()->borderImageSource() && m_state.style()->borderImageSource()->isPendingImage()) 4118 m_state.style()->setBorderImageSource(loadPendingImage(static_cast<StylePendingImage*>(m_state.style()->borderImageSource()))); 4119 break; 4120 } 4121 case CSSPropertyWebkitBoxReflect: { 4122 if (StyleReflection* reflection = m_state.style()->boxReflect()) { 4123 const NinePieceImage& maskImage = reflection->mask(); 4124 if (maskImage.image() && maskImage.image()->isPendingImage()) { 4125 RefPtr<StyleImage> loadedImage = loadPendingImage(static_cast<StylePendingImage*>(maskImage.image())); 4126 reflection->setMask(NinePieceImage(loadedImage.release(), maskImage.imageSlices(), maskImage.fill(), maskImage.borderSlices(), maskImage.outset(), maskImage.horizontalRule(), maskImage.verticalRule())); 4127 } 4128 } 4129 break; 4130 } 4131 case CSSPropertyWebkitMaskBoxImageSource: { 4132 if (m_state.style()->maskBoxImageSource() && m_state.style()->maskBoxImageSource()->isPendingImage()) 4133 m_state.style()->setMaskBoxImageSource(loadPendingImage(static_cast<StylePendingImage*>(m_state.style()->maskBoxImageSource()))); 4134 break; 4135 } 4136 case CSSPropertyWebkitMaskImage: { 4137 for (FillLayer* maskLayer = m_state.style()->accessMaskLayers(); maskLayer; maskLayer = maskLayer->next()) { 4138 if (maskLayer->image() && maskLayer->image()->isPendingImage()) 4139 maskLayer->setImage(loadPendingImage(static_cast<StylePendingImage*>(maskLayer->image()))); 4140 } 4141 break; 4142 } 4143#if ENABLE(CSS_SHAPES) 4144 case CSSPropertyWebkitShapeInside: 4145 if (m_state.style()->shapeInside() && m_state.style()->shapeInside()->image() && m_state.style()->shapeInside()->image()->isPendingImage()) 4146 m_state.style()->shapeInside()->setImage(loadPendingImage(static_cast<StylePendingImage*>(m_state.style()->shapeInside()->image()))); 4147 break; 4148 case CSSPropertyWebkitShapeOutside: 4149 if (m_state.style()->shapeOutside() && m_state.style()->shapeOutside()->image() && m_state.style()->shapeOutside()->image()->isPendingImage()) 4150 m_state.style()->shapeOutside()->setImage(loadPendingImage(static_cast<StylePendingImage*>(m_state.style()->shapeOutside()->image()))); 4151 break; 4152#endif 4153 default: 4154 ASSERT_NOT_REACHED(); 4155 } 4156 } 4157 4158 m_state.pendingImageProperties().clear(); 4159} 4160 4161#ifndef NDEBUG 4162static bool inLoadPendingResources = false; 4163#endif 4164 4165void StyleResolver::loadPendingResources() 4166{ 4167 // We've seen crashes in all three of the functions below. Some of them 4168 // indicate that style() is NULL. This NULL check will cut down on total 4169 // crashes, while the ASSERT will help us find the cause in debug builds. 4170 ASSERT(style()); 4171 if (!style()) 4172 return; 4173 4174#ifndef NDEBUG 4175 // Re-entering this function will probably mean trouble. Catch it in debug builds. 4176 ASSERT(!inLoadPendingResources); 4177 inLoadPendingResources = true; 4178#endif 4179 4180 // Start loading images referenced by this style. 4181 loadPendingImages(); 4182 4183#if ENABLE(CSS_SHADERS) 4184 // Start loading the shaders referenced by this style. 4185 loadPendingShaders(); 4186#endif 4187 4188#if ENABLE(CSS_FILTERS) && ENABLE(SVG) 4189 // Start loading the SVG Documents referenced by this style. 4190 loadPendingSVGDocuments(); 4191#endif 4192 4193#ifndef NDEBUG 4194 inLoadPendingResources = false; 4195#endif 4196} 4197 4198inline StyleResolver::MatchedProperties::MatchedProperties() 4199 : possiblyPaddedMember(0) 4200{ 4201} 4202 4203inline StyleResolver::MatchedProperties::~MatchedProperties() 4204{ 4205} 4206 4207} // namespace WebCore 4208