blob: fa652147281c3f24b4aec423d777372904a18e4d [file] [log] [blame]
/*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc.
* All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef StyleResolver_h
#define StyleResolver_h
#include "core/CoreExport.h"
#include "core/animation/PropertyHandle.h"
#include "core/css/ElementRuleCollector.h"
#include "core/css/PseudoStyleRequest.h"
#include "core/css/RuleFeature.h"
#include "core/css/RuleSet.h"
#include "core/css/SelectorChecker.h"
#include "core/css/SelectorFilter.h"
#include "core/css/resolver/CSSPropertyPriority.h"
#include "core/css/resolver/MatchedPropertiesCache.h"
#include "core/css/resolver/StyleBuilder.h"
#include "core/style/CachedUAStyle.h"
#include "platform/heap/Handle.h"
#include "wtf/Deque.h"
#include "wtf/HashMap.h"
#include "wtf/HashSet.h"
#include "wtf/ListHashSet.h"
#include "wtf/RefPtr.h"
#include "wtf/Vector.h"
namespace blink {
class AnimatableValue;
class CSSRuleList;
class CSSStyleSheet;
class CSSValue;
class Document;
class Element;
class Interpolation;
class MatchResult;
class MediaQueryEvaluator;
class StylePropertySet;
class StyleRule;
class StyleRuleUsageTracker;
enum StyleSharingBehavior {
AllowStyleSharing,
DisallowStyleSharing,
};
enum RuleMatchingBehavior { MatchAllRules, MatchAllRulesExcludingSMIL };
const unsigned styleSharingListSize = 15;
const unsigned styleSharingMaxDepth = 32;
using StyleSharingList = HeapDeque<Member<Element>, styleSharingListSize>;
using ActiveInterpolationsMap =
HashMap<PropertyHandle, Vector<RefPtr<Interpolation>, 1>>;
// This class selects a ComputedStyle for a given element based on a collection
// of stylesheets.
class CORE_EXPORT StyleResolver final
: public GarbageCollectedFinalized<StyleResolver> {
WTF_MAKE_NONCOPYABLE(StyleResolver);
public:
static StyleResolver* create(Document& document) {
return new StyleResolver(document);
}
~StyleResolver();
void dispose();
PassRefPtr<ComputedStyle> styleForElement(
Element*,
const ComputedStyle* parentStyle = 0,
StyleSharingBehavior = AllowStyleSharing,
RuleMatchingBehavior = MatchAllRules);
static PassRefPtr<AnimatableValue> createAnimatableValueSnapshot(
Element&,
const ComputedStyle& baseStyle,
const ComputedStyle* parentStyle,
CSSPropertyID,
const CSSValue*);
PassRefPtr<ComputedStyle> pseudoStyleForElement(
Element*,
const PseudoStyleRequest&,
const ComputedStyle* parentStyle);
PassRefPtr<ComputedStyle> styleForPage(int pageIndex);
PassRefPtr<ComputedStyle> styleForText(Text*);
static PassRefPtr<ComputedStyle> styleForDocument(Document&);
// FIXME: It could be better to call appendAuthorStyleSheets() directly after
// we factor StyleResolver further.
// https://bugs.webkit.org/show_bug.cgi?id=108890
void appendAuthorStyleSheets(const HeapVector<Member<CSSStyleSheet>>&);
void lazyAppendAuthorStyleSheets(unsigned firstNew,
const HeapVector<Member<CSSStyleSheet>>&);
void removePendingAuthorStyleSheets(const HeapVector<Member<CSSStyleSheet>>&);
void appendPendingAuthorStyleSheets();
bool hasPendingAuthorStyleSheets() const {
return m_pendingStyleSheets.size() > 0;
}
// TODO(esprehn): StyleResolver should probably not contain tree walking
// state, instead we should pass a context object during recalcStyle.
SelectorFilter& selectorFilter() { return m_selectorFilter; }
StyleRuleKeyframes* findKeyframesRule(const Element*,
const AtomicString& animationName);
// These methods will give back the set of rules that matched for a given
// element (or a pseudo-element).
enum CSSRuleFilter {
UAAndUserCSSRules = 1 << 1,
AuthorCSSRules = 1 << 2,
EmptyCSSRules = 1 << 3,
CrossOriginCSSRules = 1 << 4,
AllButEmptyCSSRules =
UAAndUserCSSRules | AuthorCSSRules | CrossOriginCSSRules,
AllCSSRules = AllButEmptyCSSRules | EmptyCSSRules,
};
CSSRuleList* cssRulesForElement(
Element*,
unsigned rulesToInclude = AllButEmptyCSSRules);
CSSRuleList* pseudoCSSRulesForElement(
Element*,
PseudoId,
unsigned rulesToInclude = AllButEmptyCSSRules);
StyleRuleList* styleRulesForElement(Element*, unsigned rulesToInclude);
void computeFont(ComputedStyle*, const StylePropertySet&);
void addViewportDependentMediaQueries(const MediaQueryResultList&);
bool hasViewportDependentMediaQueries() const {
return !m_viewportDependentMediaQueryResults.isEmpty();
}
bool mediaQueryAffectedByViewportChange() const;
void addDeviceDependentMediaQueries(const MediaQueryResultList&);
bool mediaQueryAffectedByDeviceChange() const;
// FIXME: Rename to reflect the purpose, like didChangeFontSize or something.
void invalidateMatchedPropertiesCache();
void notifyResizeForViewportUnits();
// Exposed for ComputedStyle::isStyleAvilable().
static ComputedStyle* styleNotYetAvailable() {
return s_styleNotYetAvailable;
}
StyleSharingList& styleSharingList();
void addToStyleSharingList(Element&);
void clearStyleSharingList();
void increaseStyleSharingDepth() { ++m_styleSharingDepth; }
void decreaseStyleSharingDepth() { --m_styleSharingDepth; }
PseudoElement* createPseudoElementIfNeeded(Element& parent, PseudoId);
void setRuleUsageTracker(StyleRuleUsageTracker*);
void updateMediaType();
DECLARE_TRACE();
private:
explicit StyleResolver(Document&);
PassRefPtr<ComputedStyle> initialStyleForElement();
// FIXME: This should probably go away, folded into FontBuilder.
void updateFont(StyleResolverState&);
void addMatchedRulesToTracker(const ElementRuleCollector&);
void loadPendingResources(StyleResolverState&);
void adjustComputedStyle(StyleResolverState&, Element*);
void appendCSSStyleSheet(CSSStyleSheet&);
void collectPseudoRulesForElement(const Element&,
ElementRuleCollector&,
PseudoId,
unsigned rulesToInclude);
void matchRuleSet(ElementRuleCollector&, RuleSet*);
void matchUARules(ElementRuleCollector&);
void matchScopedRules(const Element&, ElementRuleCollector&);
void matchAuthorRules(const Element&, ElementRuleCollector&);
void matchAuthorRulesV0(const Element&, ElementRuleCollector&);
void matchAllRules(StyleResolverState&,
ElementRuleCollector&,
bool includeSMILProperties);
void collectTreeBoundaryCrossingRulesV0CascadeOrder(const Element&,
ElementRuleCollector&);
void applyMatchedProperties(StyleResolverState&, const MatchResult&);
bool applyAnimatedProperties(StyleResolverState&,
const Element* animatingElement);
void applyCallbackSelectors(StyleResolverState&);
// These flags indicate whether an apply pass for a given CSSPropertyPriority
// and isImportant is required.
class NeedsApplyPass {
public:
bool get(CSSPropertyPriority priority, bool isImportant) const {
return m_flags[getIndex(priority, isImportant)];
}
void set(CSSPropertyPriority priority, bool isImportant) {
m_flags[getIndex(priority, isImportant)] = true;
}
private:
static size_t getIndex(CSSPropertyPriority priority, bool isImportant) {
DCHECK(priority >= 0 && priority < PropertyPriorityCount);
return priority * 2 + isImportant;
}
bool m_flags[PropertyPriorityCount * 2] = {0};
};
enum ShouldUpdateNeedsApplyPass {
CheckNeedsApplyPass = false,
UpdateNeedsApplyPass = true,
};
template <CSSPropertyPriority priority, ShouldUpdateNeedsApplyPass>
void applyMatchedProperties(StyleResolverState&,
const MatchedPropertiesRange&,
bool important,
bool inheritedOnly,
NeedsApplyPass&);
template <CSSPropertyPriority priority, ShouldUpdateNeedsApplyPass>
void applyProperties(StyleResolverState&,
const StylePropertySet* properties,
bool isImportant,
bool inheritedOnly,
NeedsApplyPass&,
PropertyWhitelistType = PropertyWhitelistNone);
template <CSSPropertyPriority priority>
void applyAnimatedProperties(StyleResolverState&,
const ActiveInterpolationsMap&);
template <CSSPropertyPriority priority>
void applyAllProperty(StyleResolverState&,
const CSSValue&,
bool inheritedOnly,
PropertyWhitelistType);
template <CSSPropertyPriority priority, ShouldUpdateNeedsApplyPass>
void applyPropertiesForApplyAtRule(StyleResolverState&,
const CSSValue&,
bool isImportant,
NeedsApplyPass&,
PropertyWhitelistType);
bool pseudoStyleForElementInternal(Element&,
const PseudoStyleRequest&,
const ComputedStyle* parentStyle,
StyleResolverState&);
bool hasAuthorBackground(const StyleResolverState&);
bool hasAuthorBorder(const StyleResolverState&);
PseudoElement* createPseudoElement(Element* parent, PseudoId);
Document& document() const { return *m_document; }
static ComputedStyle* s_styleNotYetAvailable;
MatchedPropertiesCache m_matchedPropertiesCache;
MediaQueryResultList m_viewportDependentMediaQueryResults;
MediaQueryResultList m_deviceDependentMediaQueryResults;
Member<Document> m_document;
SelectorFilter m_selectorFilter;
HeapListHashSet<Member<CSSStyleSheet>, 16> m_pendingStyleSheets;
Member<StyleRuleUsageTracker> m_tracker;
bool m_printMediaType = false;
unsigned m_styleSharingDepth = 0;
HeapVector<Member<StyleSharingList>, styleSharingMaxDepth>
m_styleSharingLists;
};
} // namespace blink
#endif // StyleResolver_h