blob: 3aeaddb9a427d26a30613cccd01eee0d7b3ccaa1 [file] [log] [blame]
/*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2001 Dirk Mueller (mueller@kde.org)
* (C) 2006 Alexey Proskuryakov (ap@webkit.org)
* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All
* rights reserved.
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved.
* (http://www.torchmobile.com/)
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
* Copyright (C) 2011 Google 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 StyleEngine_h
#define StyleEngine_h
#include <memory>
#include <utility>
#include "core/CoreExport.h"
#include "core/css/ActiveStyleSheets.h"
#include "core/css/CSSGlobalRuleSet.h"
#include "core/css/DocumentStyleSheetCollection.h"
#include "core/css/StyleEngineContext.h"
#include "core/css/invalidation/StyleInvalidator.h"
#include "core/css/resolver/StyleResolver.h"
#include "core/css/resolver/StyleResolverStats.h"
#include "core/dom/Document.h"
#include "core/dom/TreeOrderedList.h"
#include "platform/bindings/ScriptWrappable.h"
#include "platform/bindings/TraceWrapperMember.h"
#include "platform/fonts/FontSelectorClient.h"
#include "platform/heap/Handle.h"
#include "platform/wtf/Allocator.h"
#include "platform/wtf/AutoReset.h"
#include "platform/wtf/ListHashSet.h"
#include "platform/wtf/Vector.h"
#include "platform/wtf/text/WTFString.h"
#include "public/web/WebDocument.h"
namespace blink {
class CSSFontSelector;
class CSSStyleSheet;
class FontSelector;
class MediaQueryEvaluator;
class Node;
class RuleFeatureSet;
class ShadowTreeStyleSheetCollection;
class StyleRuleFontFace;
class StyleRuleUsageTracker;
class StyleSheetContents;
class ViewportStyleResolver;
enum InvalidationScope { kInvalidateCurrentScope, kInvalidateAllScopes };
class CORE_EXPORT StyleEngine final
: public GarbageCollectedFinalized<StyleEngine>,
public FontSelectorClient,
public TraceWrapperBase {
USING_GARBAGE_COLLECTED_MIXIN(StyleEngine);
public:
class IgnoringPendingStylesheet {
DISALLOW_NEW();
public:
IgnoringPendingStylesheet(StyleEngine& engine)
: scope_(&engine.ignore_pending_stylesheets_, true) {}
private:
AutoReset<bool> scope_;
};
friend class IgnoringPendingStylesheet;
static StyleEngine* Create(Document& document) {
return new StyleEngine(document);
}
~StyleEngine();
const HeapVector<TraceWrapperMember<StyleSheet>>&
StyleSheetsForStyleSheetList(TreeScope&);
CSSStyleSheet* InspectorStyleSheet() const { return inspector_style_sheet_; }
const ActiveStyleSheetVector ActiveStyleSheetsForInspector();
bool NeedsActiveStyleUpdate() const;
void SetNeedsActiveStyleUpdate(TreeScope&);
void AddStyleSheetCandidateNode(Node&);
void RemoveStyleSheetCandidateNode(Node&, ContainerNode& insertion_point);
void ModifiedStyleSheetCandidateNode(Node&);
void MediaQueriesChangedInScope(TreeScope&);
void WatchedSelectorsChanged();
void InitialViewportChanged();
void ViewportRulesChanged();
void HtmlImportAddedOrRemoved();
WebStyleSheetId AddUserSheet(StyleSheetContents*);
void RemoveUserSheet(WebStyleSheetId);
CSSStyleSheet& EnsureInspectorStyleSheet();
RuleSet* WatchedSelectorsRuleSet() {
DCHECK(IsMaster());
DCHECK(global_rule_set_);
return global_rule_set_->WatchedSelectorsRuleSet();
}
bool HasStyleSheets() const {
return GetDocumentStyleSheetCollection().HasStyleSheets();
}
RuleSet* RuleSetForSheet(CSSStyleSheet&);
void MediaQueryAffectingValueChanged();
void UpdateActiveStyleSheetsInImport(
StyleEngine& master_engine,
DocumentStyleSheetCollector& parent_collector);
void UpdateActiveStyle();
void MarkAllTreeScopesDirty() { all_tree_scopes_dirty_ = true; }
String PreferredStylesheetSetName() const {
return preferred_stylesheet_set_name_;
}
String SelectedStylesheetSetName() const {
return selected_stylesheet_set_name_;
}
void SetPreferredStylesheetSetNameIfNotSet(const String&);
void SetSelectedStylesheetSetName(const String&);
void SetHttpDefaultStyle(const String&);
void AddPendingSheet(StyleEngineContext&);
void RemovePendingSheet(Node& style_sheet_candidate_node,
const StyleEngineContext&);
bool HasPendingScriptBlockingSheets() const {
return pending_script_blocking_stylesheets_ > 0;
}
bool HasPendingRenderBlockingSheets() const {
return pending_render_blocking_stylesheets_ > 0;
}
bool HaveScriptBlockingStylesheetsLoaded() const {
return !HasPendingScriptBlockingSheets() || ignore_pending_stylesheets_;
}
bool HaveRenderBlockingStylesheetsLoaded() const {
return !HasPendingRenderBlockingSheets() || ignore_pending_stylesheets_;
}
bool IgnoringPendingStylesheets() const {
return ignore_pending_stylesheets_;
}
unsigned MaxDirectAdjacentSelectors() const {
return GetRuleFeatureSet().MaxDirectAdjacentSelectors();
}
bool UsesFirstLineRules() const {
return GetRuleFeatureSet().UsesFirstLineRules();
}
bool UsesWindowInactiveSelector() const {
return GetRuleFeatureSet().UsesWindowInactiveSelector();
}
bool UsesRemUnits() const { return uses_rem_units_; }
void SetUsesRemUnit(bool uses_rem_units) { uses_rem_units_ = uses_rem_units; }
bool UpdateRemUnits(const ComputedStyle* old_root_style,
const ComputedStyle* new_root_style);
void ResetCSSFeatureFlags(const RuleFeatureSet&);
void ShadowRootRemovedFromDocument(ShadowRoot*);
void AddTreeBoundaryCrossingScope(const TreeScope&);
const TreeOrderedList& TreeBoundaryCrossingScopes() const {
return tree_boundary_crossing_scopes_;
}
void ResetAuthorStyle(TreeScope&);
StyleResolver* Resolver() const { return resolver_; }
void SetRuleUsageTracker(StyleRuleUsageTracker*);
StyleResolver& EnsureResolver() {
UpdateActiveStyle();
if (!resolver_)
CreateResolver();
return *resolver_;
}
bool HasResolver() const { return resolver_; }
StyleInvalidator& GetStyleInvalidator() { return style_invalidator_; }
bool MediaQueryAffectedByViewportChange();
bool MediaQueryAffectedByDeviceChange();
bool HasViewportDependentMediaQueries() const {
DCHECK(IsMaster());
DCHECK(global_rule_set_);
return !global_rule_set_->GetRuleFeatureSet()
.ViewportDependentMediaQueryResults()
.IsEmpty();
}
CSSFontSelector* GetFontSelector() { return font_selector_; }
void SetFontSelector(CSSFontSelector*);
void RemoveFontFaceRules(const HeapVector<Member<const StyleRuleFontFace>>&);
// updateGenericFontFamilySettings is used from WebSettingsImpl.
void UpdateGenericFontFamilySettings();
void DidDetach();
CSSStyleSheet* CreateSheet(Element&,
const String& text,
TextPosition start_position,
StyleEngineContext&);
void CollectScopedStyleFeaturesTo(RuleFeatureSet&) const;
void EnsureUAStyleForFullscreen();
void EnsureUAStyleForElement(const Element&);
void PlatformColorsChanged();
bool HasRulesForId(const AtomicString& id) const;
void ClassChangedForElement(const SpaceSplitString& changed_classes,
Element&);
void ClassChangedForElement(const SpaceSplitString& old_classes,
const SpaceSplitString& new_classes,
Element&);
void AttributeChangedForElement(const QualifiedName& attribute_name,
Element&);
void IdChangedForElement(const AtomicString& old_id,
const AtomicString& new_id,
Element&);
void PseudoStateChangedForElement(CSSSelector::PseudoType, Element&);
void ScheduleSiblingInvalidationsForElement(Element&,
ContainerNode& scheduling_parent,
unsigned min_direct_adjacent);
void ScheduleInvalidationsForInsertedSibling(Element* before_element,
Element& inserted_element);
void ScheduleInvalidationsForRemovedSibling(Element* before_element,
Element& removed_element,
Element& after_element);
void ScheduleNthPseudoInvalidations(ContainerNode&);
void ScheduleInvalidationsForRuleSets(TreeScope&,
const HeapHashSet<Member<RuleSet>>&,
InvalidationScope =
kInvalidateCurrentScope);
void NodeWillBeRemoved(Node&);
unsigned StyleForElementCount() const { return style_for_element_count_; }
void IncStyleForElementCount() { style_for_element_count_++; }
StyleResolverStats* Stats() { return style_resolver_stats_.get(); }
void SetStatsEnabled(bool);
void ApplyRuleSetChanges(TreeScope&,
const ActiveStyleSheetVector& old_style_sheets,
const ActiveStyleSheetVector& new_style_sheets,
InvalidationScope = kInvalidateCurrentScope);
void CollectMatchingUserRules(ElementRuleCollector&) const;
void CustomPropertyRegistered();
bool NeedsWhitespaceReattachment() const {
return !whitespace_reattach_set_.IsEmpty();
}
bool NeedsWhitespaceReattachment(Element* element) const {
return whitespace_reattach_set_.Contains(element);
}
void ClearWhitespaceReattachSet() { whitespace_reattach_set_.clear(); }
void MarkForWhitespaceReattachment();
StyleRuleKeyframes* KeyframeStylesForAnimation(
const AtomicString& animation_name);
virtual void Trace(blink::Visitor*);
void TraceWrappers(const ScriptWrappableVisitor*) const;
private:
// FontSelectorClient implementation.
void FontsNeedUpdate(FontSelector*) override;
private:
StyleEngine(Document&);
bool NeedsActiveStyleSheetUpdate() const {
return all_tree_scopes_dirty_ || tree_scopes_removed_ ||
document_scope_dirty_ || dirty_tree_scopes_.size() ||
user_style_dirty_;
}
TreeScopeStyleSheetCollection& EnsureStyleSheetCollectionFor(TreeScope&);
TreeScopeStyleSheetCollection* StyleSheetCollectionFor(TreeScope&);
bool ShouldUpdateDocumentStyleSheetCollection() const;
bool ShouldUpdateShadowTreeStyleSheetCollection() const;
void MarkDocumentDirty();
void MarkTreeScopeDirty(TreeScope&);
void MarkUserStyleDirty();
bool IsMaster() const { return is_master_; }
Document* Master();
Document& GetDocument() const { return *document_; }
typedef HeapHashSet<Member<TreeScope>> UnorderedTreeScopeSet;
void MediaQueryAffectingValueChanged(UnorderedTreeScopeSet&);
const RuleFeatureSet& GetRuleFeatureSet() const {
DCHECK(IsMaster());
DCHECK(global_rule_set_);
return global_rule_set_->GetRuleFeatureSet();
}
void CreateResolver();
void ClearResolvers();
CSSStyleSheet* ParseSheet(Element&,
const String& text,
TextPosition start_position);
const DocumentStyleSheetCollection& GetDocumentStyleSheetCollection() const {
DCHECK(document_style_sheet_collection_);
return *document_style_sheet_collection_;
}
DocumentStyleSheetCollection& GetDocumentStyleSheetCollection() {
DCHECK(document_style_sheet_collection_);
return *document_style_sheet_collection_;
}
void UpdateActiveStyleSheetsInShadow(
TreeScope*,
UnorderedTreeScopeSet& tree_scopes_removed);
bool ShouldSkipInvalidationFor(const Element&) const;
void ScheduleRuleSetInvalidationsForElement(
Element&,
const HeapHashSet<Member<RuleSet>>&);
void ScheduleTypeRuleSetInvalidations(ContainerNode&,
const HeapHashSet<Member<RuleSet>>&);
void InvalidateSlottedElements(HTMLSlotElement&);
void UpdateViewport();
void UpdateActiveUserStyleSheets();
void UpdateActiveStyleSheets();
void UpdateGlobalRuleSet() {
DCHECK(!NeedsActiveStyleSheetUpdate());
if (global_rule_set_)
global_rule_set_->Update(GetDocument());
}
const MediaQueryEvaluator& EnsureMediaQueryEvaluator();
void UpdateStyleSheetList(TreeScope&);
void ClearFontCache();
void RefreshFontCache();
void MarkFontCacheDirty() { font_cache_dirty_ = true; }
bool IsFontCacheDirty() const { return font_cache_dirty_; }
void ClearKeyframeRules() { keyframes_rule_map_.clear(); }
void AddFontFaceRules(const RuleSet&);
void AddKeyframeRules(const RuleSet&);
void AddKeyframeStyle(StyleRuleKeyframes*);
Member<Document> document_;
bool is_master_;
// Track the number of currently loading top-level stylesheets needed for
// layout. Sheets loaded using the @import directive are not included in this
// count. We use this count of pending sheets to detect when we can begin
// attaching elements and when it is safe to execute scripts.
int pending_script_blocking_stylesheets_ = 0;
int pending_render_blocking_stylesheets_ = 0;
int pending_body_stylesheets_ = 0;
Member<CSSStyleSheet> inspector_style_sheet_;
TraceWrapperMember<DocumentStyleSheetCollection>
document_style_sheet_collection_;
Member<StyleRuleUsageTracker> tracker_;
using StyleSheetCollectionMap =
HeapHashMap<WeakMember<TreeScope>,
Member<ShadowTreeStyleSheetCollection>>;
StyleSheetCollectionMap style_sheet_collection_map_;
bool document_scope_dirty_ = true;
bool all_tree_scopes_dirty_ = false;
bool tree_scopes_removed_ = false;
bool user_style_dirty_ = false;
UnorderedTreeScopeSet dirty_tree_scopes_;
UnorderedTreeScopeSet active_tree_scopes_;
TreeOrderedList tree_boundary_crossing_scopes_;
String preferred_stylesheet_set_name_;
String selected_stylesheet_set_name_;
bool uses_rem_units_ = false;
bool ignore_pending_stylesheets_ = false;
Member<StyleResolver> resolver_;
Member<ViewportStyleResolver> viewport_resolver_;
Member<MediaQueryEvaluator> media_query_evaluator_;
Member<CSSGlobalRuleSet> global_rule_set_;
StyleInvalidator style_invalidator_;
// This is a set of rendered elements which had one or more of its rendered
// children removed since the last lifecycle update. For such elements we need
// to re-attach whitespace children. Also see reattach_all_whitespace_nodes_
// in the WhitespaceAttacher class.
HeapHashSet<Member<Element>> whitespace_reattach_set_;
Member<CSSFontSelector> font_selector_;
bool font_cache_dirty_ = false;
HeapHashMap<AtomicString, WeakMember<StyleSheetContents>>
text_to_sheet_cache_;
HeapHashMap<WeakMember<StyleSheetContents>, AtomicString>
sheet_to_text_cache_;
std::unique_ptr<StyleResolverStats> style_resolver_stats_;
unsigned style_for_element_count_ = 0;
HeapVector<std::pair<WebStyleSheetId, TraceWrapperMember<CSSStyleSheet>>>
user_style_sheets_;
ActiveStyleSheetVector active_user_style_sheets_;
WebStyleSheetId user_sheets_id_count_ = 0;
using KeyframesRuleMap =
HeapHashMap<AtomicString, Member<StyleRuleKeyframes>>;
KeyframesRuleMap keyframes_rule_map_;
friend class StyleEngineTest;
};
} // namespace blink
#endif