Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / dom / TreeScopeStyleSheetCollection.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Dirk Mueller (mueller@kde.org)
5  *           (C) 2006 Alexey Proskuryakov (ap@webkit.org)
6  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All rights reserved.
7  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
8  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
9  * Copyright (C) 2013 Google Inc. All rights reserved.
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Library General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Library General Public License for more details.
20  *
21  * You should have received a copy of the GNU Library General Public License
22  * along with this library; see the file COPYING.LIB.  If not, write to
23  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  * Boston, MA 02110-1301, USA.
25  */
26
27 #include "config.h"
28 #include "core/dom/TreeScopeStyleSheetCollection.h"
29
30 #include "core/css/CSSStyleSheet.h"
31 #include "core/css/StyleRuleImport.h"
32 #include "core/css/StyleSheetContents.h"
33 #include "core/css/invalidation/StyleSheetInvalidationAnalysis.h"
34 #include "core/css/resolver/StyleResolver.h"
35 #include "core/dom/Element.h"
36 #include "core/dom/StyleEngine.h"
37 #include "core/html/HTMLLinkElement.h"
38 #include "core/html/HTMLStyleElement.h"
39
40 namespace blink {
41
42 TreeScopeStyleSheetCollection::TreeScopeStyleSheetCollection(TreeScope& treeScope)
43     : m_treeScope(treeScope)
44     , m_hadActiveLoadingStylesheet(false)
45     , m_usesRemUnits(false)
46 {
47 }
48
49 void TreeScopeStyleSheetCollection::addStyleSheetCandidateNode(Node* node, bool createdByParser)
50 {
51     if (!node->inDocument())
52         return;
53
54     // Until the <body> exists, we have no choice but to compare document positions,
55     // since styles outside of the body and head continue to be shunted into the head
56     // (and thus can shift to end up before dynamically added DOM content that is also
57     // outside the body).
58     if (createdByParser && document().body())
59         m_styleSheetCandidateNodes.parserAdd(node);
60     else
61         m_styleSheetCandidateNodes.add(node);
62 }
63
64 TreeScopeStyleSheetCollection::StyleResolverUpdateType TreeScopeStyleSheetCollection::compareStyleSheets(const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& oldStyleSheets, const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& newStylesheets, WillBeHeapVector<RawPtrWillBeMember<StyleSheetContents> >& addedSheets)
65 {
66     unsigned newStyleSheetCount = newStylesheets.size();
67     unsigned oldStyleSheetCount = oldStyleSheets.size();
68     ASSERT(newStyleSheetCount >= oldStyleSheetCount);
69
70     if (!newStyleSheetCount)
71         return Reconstruct;
72
73     unsigned newIndex = 0;
74     for (unsigned oldIndex = 0; oldIndex < oldStyleSheetCount; ++oldIndex) {
75         while (oldStyleSheets[oldIndex] != newStylesheets[newIndex]) {
76             addedSheets.append(newStylesheets[newIndex]->contents());
77             if (++newIndex == newStyleSheetCount)
78                 return Reconstruct;
79         }
80         if (++newIndex == newStyleSheetCount)
81             return Reconstruct;
82     }
83     bool hasInsertions = !addedSheets.isEmpty();
84     while (newIndex < newStyleSheetCount) {
85         addedSheets.append(newStylesheets[newIndex]->contents());
86         ++newIndex;
87     }
88     // If all new sheets were added at the end of the list we can just add them to existing StyleResolver.
89     // If there were insertions we need to re-add all the stylesheets so rules are ordered correctly.
90     return hasInsertions ? Reset : Additive;
91 }
92
93 bool TreeScopeStyleSheetCollection::activeLoadingStyleSheetLoaded(const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& newStyleSheets)
94 {
95     // StyleSheets of <style> elements that @import stylesheets are active but loading. We need to trigger a full recalc when such loads are done.
96     bool hasActiveLoadingStylesheet = false;
97     unsigned newStylesheetCount = newStyleSheets.size();
98     for (unsigned i = 0; i < newStylesheetCount; ++i) {
99         if (newStyleSheets[i]->isLoading())
100             hasActiveLoadingStylesheet = true;
101     }
102     if (m_hadActiveLoadingStylesheet && !hasActiveLoadingStylesheet) {
103         m_hadActiveLoadingStylesheet = false;
104         return true;
105     }
106     m_hadActiveLoadingStylesheet = hasActiveLoadingStylesheet;
107     return false;
108 }
109
110 static bool findFontFaceRulesFromStyleSheetContents(const WillBeHeapVector<RawPtrWillBeMember<StyleSheetContents> >& sheets, WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace> >& fontFaceRules)
111 {
112     bool hasFontFaceRule = false;
113
114     for (unsigned i = 0; i < sheets.size(); ++i) {
115         ASSERT(sheets[i]);
116         if (sheets[i]->hasFontFaceRule()) {
117             // FIXME: We don't need this for styles in shadow tree.
118             sheets[i]->findFontFaceRules(fontFaceRules);
119             hasFontFaceRule = true;
120         }
121     }
122     return hasFontFaceRule;
123 }
124
125 void TreeScopeStyleSheetCollection::analyzeStyleSheetChange(StyleResolverUpdateMode updateMode, const StyleSheetCollection& newCollection, StyleSheetChange& change)
126 {
127     if (activeLoadingStyleSheetLoaded(newCollection.activeAuthorStyleSheets()))
128         return;
129
130     if (updateMode != AnalyzedStyleUpdate)
131         return;
132
133     // Find out which stylesheets are new.
134     WillBeHeapVector<RawPtrWillBeMember<StyleSheetContents> > addedSheets;
135     if (m_activeAuthorStyleSheets.size() <= newCollection.activeAuthorStyleSheets().size()) {
136         change.styleResolverUpdateType = compareStyleSheets(m_activeAuthorStyleSheets, newCollection.activeAuthorStyleSheets(), addedSheets);
137     } else {
138         StyleResolverUpdateType updateType = compareStyleSheets(newCollection.activeAuthorStyleSheets(), m_activeAuthorStyleSheets, addedSheets);
139         if (updateType != Additive) {
140             change.styleResolverUpdateType = updateType;
141         } else {
142             change.styleResolverUpdateType = Reset;
143             // If @font-face is removed, needs full style recalc.
144             if (findFontFaceRulesFromStyleSheetContents(addedSheets, change.fontFaceRulesToRemove))
145                 return;
146         }
147     }
148
149     // FIXME: If styleResolverUpdateType is Reconstruct, we should return early here since
150     // we need to recalc the whole document. It's wrong to use StyleSheetInvalidationAnalysis since
151     // it only looks at the addedSheets.
152
153     // No point in doing the analysis work if we're just going to recalc the whole document anyways.
154     // This needs to be done after the compareStyleSheets calls above to ensure we don't throw away
155     // the StyleResolver if we don't need to.
156     if (document().hasPendingForcedStyleRecalc())
157         return;
158
159     // If we are already parsing the body and so may have significant amount of elements, put some effort into trying to avoid style recalcs.
160     if (!document().body() || document().hasNodesWithPlaceholderStyle())
161         return;
162     StyleSheetInvalidationAnalysis invalidationAnalysis(addedSheets);
163     if (invalidationAnalysis.dirtiesAllStyle())
164         return;
165     invalidationAnalysis.invalidateStyle(document());
166     change.requiresFullStyleRecalc = false;
167     return;
168 }
169
170 void TreeScopeStyleSheetCollection::clearMediaQueryRuleSetStyleSheets()
171 {
172     for (size_t i = 0; i < m_activeAuthorStyleSheets.size(); ++i) {
173         StyleSheetContents* contents = m_activeAuthorStyleSheets[i]->contents();
174         if (contents->hasMediaQueries())
175             contents->clearRuleSet();
176     }
177 }
178
179 void TreeScopeStyleSheetCollection::enableExitTransitionStylesheets()
180 {
181     DocumentOrderedList::iterator begin = m_styleSheetCandidateNodes.begin();
182     DocumentOrderedList::iterator end = m_styleSheetCandidateNodes.end();
183     for (DocumentOrderedList::iterator it = begin; it != end; ++it) {
184         Node* node = *it;
185         if (isHTMLLinkElement(*node))
186             toHTMLLinkElement(node)->enableIfExitTransitionStyle();
187     }
188 }
189
190 static bool styleSheetsUseRemUnits(const WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> >& sheets)
191 {
192     for (unsigned i = 0; i < sheets.size(); ++i) {
193         if (sheets[i]->contents()->usesRemUnits())
194             return true;
195     }
196     return false;
197 }
198
199 void TreeScopeStyleSheetCollection::updateUsesRemUnits()
200 {
201     m_usesRemUnits = styleSheetsUseRemUnits(m_activeAuthorStyleSheets);
202 }
203
204 void TreeScopeStyleSheetCollection::trace(Visitor* visitor)
205 {
206     visitor->trace(m_treeScope);
207     visitor->trace(m_styleSheetCandidateNodes);
208     StyleSheetCollection::trace(visitor);
209 }
210
211 }