Remove excessive headers from WebCore/{rendering,style,svg}
[WebKit-https.git] / Source / WebCore / style / StyleTreeResolver.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Peter Kelly (pmk@post.com)
5  *           (C) 2001 Dirk Mueller (mueller@kde.org)
6  *           (C) 2007 David Smith (catfish.man@gmail.com)
7  * Copyright (C) 2004-2010, 2012-2016 Apple Inc. All rights reserved.
8  *           (C) 2007 Eric Seidel (eric@webkit.org)
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB.  If not, write to
22  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  */
25
26 #include "config.h"
27 #include "StyleTreeResolver.h"
28
29 #include "CSSAnimationController.h"
30 #include "CSSFontSelector.h"
31 #include "ComposedTreeAncestorIterator.h"
32 #include "ComposedTreeIterator.h"
33 #include "ElementIterator.h"
34 #include "HTMLBodyElement.h"
35 #include "HTMLMeterElement.h"
36 #include "HTMLNames.h"
37 #include "HTMLProgressElement.h"
38 #include "HTMLSlotElement.h"
39 #include "LoaderStrategy.h"
40 #include "MainFrame.h"
41 #include "NodeRenderStyle.h"
42 #include "Page.h"
43 #include "PlatformStrategies.h"
44 #include "RenderElement.h"
45 #include "RenderView.h"
46 #include "Settings.h"
47 #include "ShadowRoot.h"
48 #include "StyleFontSizeFunctions.h"
49 #include "StyleResolver.h"
50 #include "StyleScope.h"
51 #include "Text.h"
52
53 namespace WebCore {
54
55 namespace Style {
56
57 TreeResolver::TreeResolver(Document& document)
58     : m_document(document)
59 {
60 }
61
62 TreeResolver::~TreeResolver()
63 {
64 }
65
66 TreeResolver::Scope::Scope(Document& document)
67     : styleResolver(document.styleScope().resolver())
68     , sharingResolver(document, styleResolver.ruleSets(), selectorFilter)
69 {
70 }
71
72 TreeResolver::Scope::Scope(ShadowRoot& shadowRoot, Scope& enclosingScope)
73     : styleResolver(shadowRoot.styleScope().resolver())
74     , sharingResolver(shadowRoot.documentScope(), styleResolver.ruleSets(), selectorFilter)
75     , shadowRoot(&shadowRoot)
76     , enclosingScope(&enclosingScope)
77 {
78 }
79
80 TreeResolver::Parent::Parent(Document& document)
81     : element(nullptr)
82     , style(*document.renderStyle())
83 {
84 }
85
86 TreeResolver::Parent::Parent(Element& element, const RenderStyle& style, Change change)
87     : element(&element)
88     , style(style)
89     , change(change)
90 {
91 }
92
93 void TreeResolver::pushScope(ShadowRoot& shadowRoot)
94 {
95     m_scopeStack.append(adoptRef(*new Scope(shadowRoot, scope())));
96     scope().styleResolver.setOverrideDocumentElementStyle(m_documentElementStyle.get());
97 }
98
99 void TreeResolver::pushEnclosingScope()
100 {
101     ASSERT(scope().enclosingScope);
102     m_scopeStack.append(*scope().enclosingScope);
103     scope().styleResolver.setOverrideDocumentElementStyle(m_documentElementStyle.get());
104 }
105
106 void TreeResolver::popScope()
107 {
108     scope().styleResolver.setOverrideDocumentElementStyle(nullptr);
109     return m_scopeStack.removeLast();
110 }
111
112 std::unique_ptr<RenderStyle> TreeResolver::styleForElement(Element& element, const RenderStyle& inheritedStyle)
113 {
114     if (element.hasCustomStyleResolveCallbacks()) {
115         RenderStyle* shadowHostStyle = scope().shadowRoot ? m_update->elementStyle(*scope().shadowRoot->host()) : nullptr;
116         if (auto customStyle = element.resolveCustomStyle(inheritedStyle, shadowHostStyle)) {
117             if (customStyle->relations)
118                 commitRelations(WTFMove(customStyle->relations), *m_update);
119
120             return WTFMove(customStyle->renderStyle);
121         }
122     }
123
124     if (auto style = scope().sharingResolver.resolve(element, *m_update))
125         return style;
126
127     auto elementStyle = scope().styleResolver.styleForElement(element, &inheritedStyle, parentBoxStyle(), MatchAllRules, nullptr, &scope().selectorFilter);
128
129     if (elementStyle.relations)
130         commitRelations(WTFMove(elementStyle.relations), *m_update);
131
132     return WTFMove(elementStyle.renderStyle);
133 }
134
135 static void resetStyleForNonRenderedDescendants(Element& current)
136 {
137     // FIXME: This is not correct with shadow trees. This should be done with ComposedTreeIterator.
138     bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle = false;
139     for (auto& child : childrenOfType<Element>(current)) {
140         bool affectedByPreviousSibling = child.styleIsAffectedByPreviousSibling() && elementNeedingStyleRecalcAffectsNextSiblingElementStyle;
141         if (child.needsStyleRecalc() || elementNeedingStyleRecalcAffectsNextSiblingElementStyle)
142             elementNeedingStyleRecalcAffectsNextSiblingElementStyle = child.affectsNextSiblingElementStyle();
143
144         if (child.needsStyleRecalc() || affectedByPreviousSibling) {
145             child.resetComputedStyle();
146             child.resetStyleRelations();
147             child.setHasValidStyle();
148         }
149
150         if (child.childNeedsStyleRecalc()) {
151             resetStyleForNonRenderedDescendants(child);
152             child.clearChildNeedsStyleRecalc();
153         }
154     }
155 }
156
157 static bool affectsRenderedSubtree(Element& element, const RenderStyle& newStyle)
158 {
159     if (element.renderer())
160         return true;
161     if (newStyle.display() != NONE)
162         return true;
163     if (element.rendererIsNeeded(newStyle))
164         return true;
165 #if ENABLE(CSS_REGIONS)
166     if (element.shouldMoveToFlowThread(newStyle))
167         return true;
168 #endif
169     return false;
170 }
171
172 ElementUpdate TreeResolver::resolveElement(Element& element)
173 {
174     if (m_didSeePendingStylesheet && !element.renderer() && !m_document.isIgnoringPendingStylesheets()) {
175         m_document.setHasNodesWithMissingStyle();
176         return { };
177     }
178
179     auto newStyle = styleForElement(element, parent().style);
180
181     if (!affectsRenderedSubtree(element, *newStyle))
182         return { };
183
184     auto* existingStyle = element.renderStyle();
185
186     if (m_didSeePendingStylesheet && (!existingStyle || existingStyle->isNotFinal())) {
187         newStyle->setIsNotFinal();
188         m_document.setHasNodesWithNonFinalStyle();
189     }
190
191     auto update = createAnimatedElementUpdate(WTFMove(newStyle), element, parent().change);
192
193     if (&element == m_document.documentElement()) {
194         m_documentElementStyle = RenderStyle::clonePtr(*update.style);
195         scope().styleResolver.setOverrideDocumentElementStyle(m_documentElementStyle.get());
196
197         if (update.change != NoChange && existingStyle && existingStyle->fontSize() != update.style->fontSize()) {
198             // "rem" units are relative to the document element's font size so we need to recompute everything.
199             // In practice this is rare.
200             scope().styleResolver.invalidateMatchedPropertiesCache();
201             update.change = std::max(update.change, Force);
202         }
203     }
204
205     // This is needed for resolving color:-webkit-text for subsequent elements.
206     // FIXME: We shouldn't mutate document when resolving style.
207     if (&element == m_document.body())
208         m_document.setTextColor(update.style->visitedDependentColor(CSSPropertyColor));
209
210     // FIXME: These elements should not change renderer based on appearance property.
211     if (element.hasTagName(HTMLNames::meterTag) || is<HTMLProgressElement>(element)) {
212         if (existingStyle && update.style->appearance() != existingStyle->appearance())
213             update.change = Detach;
214     }
215
216     return update;
217 }
218
219 const RenderStyle* TreeResolver::parentBoxStyle() const
220 {
221     // 'display: contents' doesn't generate boxes.
222     for (unsigned i = m_parentStack.size(); i; --i) {
223         auto& parent = m_parentStack[i - 1];
224         if (parent.style.display() == NONE)
225             return nullptr;
226         if (parent.style.display() != CONTENTS)
227             return &parent.style;
228     }
229     ASSERT_NOT_REACHED();
230     return nullptr;
231 }
232
233 ElementUpdate TreeResolver::createAnimatedElementUpdate(std::unique_ptr<RenderStyle> newStyle, Element& element, Change parentChange)
234 {
235     auto validity = element.styleValidity();
236     bool recompositeLayer = element.styleResolutionShouldRecompositeLayer();
237
238     auto makeUpdate = [&] (std::unique_ptr<RenderStyle> style, Change change) {
239         if (validity >= Validity::SubtreeInvalid)
240             change = std::max(change, validity == Validity::SubtreeAndRenderersInvalid ? Detach : Force);
241         if (parentChange >= Force)
242             change = std::max(change, parentChange);
243         return ElementUpdate { WTFMove(style), change, recompositeLayer };
244     };
245
246     auto* renderer = element.renderer();
247
248     bool shouldReconstruct = validity >= Validity::SubtreeAndRenderersInvalid || parentChange == Detach;
249     if (shouldReconstruct)
250         return makeUpdate(WTFMove(newStyle), Detach);
251
252     if (!renderer) {
253         auto keepsDisplayContents = newStyle->display() == CONTENTS && element.hasDisplayContents();
254         // Some inherited property might have changed.
255         return makeUpdate(WTFMove(newStyle), keepsDisplayContents ? Inherit : Detach);
256     }
257
258     std::unique_ptr<RenderStyle> animatedStyle;
259     if (element.document().frame()->animation().updateAnimations(*renderer, *newStyle, animatedStyle))
260         recompositeLayer = true;
261
262     if (animatedStyle) {
263         auto change = determineChange(renderer->style(), *animatedStyle);
264         if (renderer->hasInitialAnimatedStyle()) {
265             renderer->setHasInitialAnimatedStyle(false);
266             // When we initialize a newly created renderer with initial animated style we don't inherit it to descendants.
267             // The first animation frame needs to correct this.
268             // FIXME: We should compute animated style correctly during initial style resolution when we don't have renderers yet.
269             //        https://bugs.webkit.org/show_bug.cgi?id=171926
270             change = std::max(change, Inherit);
271         }
272         // If animation forces render tree reconstruction pass the original style. The animation will be applied on renderer construction.
273         // FIXME: We should always use the animated style here.
274         auto style = change == Detach ? WTFMove(newStyle) : WTFMove(animatedStyle);
275         return makeUpdate(WTFMove(style), change);
276     }
277
278     auto change = determineChange(renderer->style(), *newStyle);
279     return makeUpdate(WTFMove(newStyle), change);
280 }
281
282 void TreeResolver::pushParent(Element& element, const RenderStyle& style, Change change)
283 {
284     scope().selectorFilter.pushParent(&element);
285
286     Parent parent(element, style, change);
287
288     if (auto* shadowRoot = element.shadowRoot()) {
289         pushScope(*shadowRoot);
290         parent.didPushScope = true;
291     }
292     else if (is<HTMLSlotElement>(element) && downcast<HTMLSlotElement>(element).assignedNodes()) {
293         pushEnclosingScope();
294         parent.didPushScope = true;
295     }
296
297     m_parentStack.append(WTFMove(parent));
298 }
299
300 void TreeResolver::popParent()
301 {
302     auto& parentElement = *parent().element;
303
304     parentElement.setHasValidStyle();
305     parentElement.clearChildNeedsStyleRecalc();
306
307     if (parent().didPushScope)
308         popScope();
309
310     scope().selectorFilter.popParent();
311
312     m_parentStack.removeLast();
313 }
314
315 void TreeResolver::popParentsToDepth(unsigned depth)
316 {
317     ASSERT(depth);
318     ASSERT(m_parentStack.size() >= depth);
319
320     while (m_parentStack.size() > depth)
321         popParent();
322 }
323
324 static bool shouldResolvePseudoElement(const PseudoElement* pseudoElement)
325 {
326     if (!pseudoElement)
327         return false;
328     return pseudoElement->needsStyleRecalc();
329 }
330
331 static bool shouldResolveElement(const Element& element, Style::Change parentChange)
332 {
333     if (parentChange >= Inherit)
334         return true;
335     if (parentChange == NoInherit) {
336         auto* existingStyle = element.renderStyle();
337         if (existingStyle && existingStyle->hasExplicitlyInheritedProperties())
338             return true;
339     }
340     if (element.needsStyleRecalc())
341         return true;
342     if (element.hasDisplayContents())
343         return true;
344     if (shouldResolvePseudoElement(element.beforePseudoElement()))
345         return true;
346     if (shouldResolvePseudoElement(element.afterPseudoElement()))
347         return true;
348
349     return false;
350 }
351
352 static void clearNeedsStyleResolution(Element& element)
353 {
354     element.setHasValidStyle();
355     if (auto* before = element.beforePseudoElement())
356         before->setHasValidStyle();
357     if (auto* after = element.afterPseudoElement())
358         after->setHasValidStyle();
359 }
360
361 static bool hasLoadingStylesheet(const Style::Scope& styleScope, const Element& element, bool checkDescendants)
362 {
363     if (!styleScope.hasPendingSheetsInBody())
364         return false;
365     if (styleScope.hasPendingSheetInBody(element))
366         return true;
367     if (!checkDescendants)
368         return false;
369     for (auto& descendant : descendantsOfType<Element>(element)) {
370         if (styleScope.hasPendingSheetInBody(descendant))
371             return true;
372     };
373     return false;
374 }
375
376 void TreeResolver::resolveComposedTree()
377 {
378     ASSERT(m_parentStack.size() == 1);
379     ASSERT(m_scopeStack.size() == 1);
380
381     auto descendants = composedTreeDescendants(m_document);
382     auto it = descendants.begin();
383     auto end = descendants.end();
384
385     // FIXME: SVG <use> element may cause tree mutations during style recalc.
386     it.dropAssertions();
387
388     while (it != end) {
389         popParentsToDepth(it.depth());
390
391         auto& node = *it;
392         auto& parent = this->parent();
393
394         ASSERT(node.isConnected());
395         ASSERT(node.containingShadowRoot() == scope().shadowRoot);
396         ASSERT(node.parentElement() == parent.element || is<ShadowRoot>(node.parentNode()) || node.parentElement()->shadowRoot());
397
398         if (is<Text>(node)) {
399             auto& text = downcast<Text>(node);
400             if (text.styleValidity() >= Validity::SubtreeAndRenderersInvalid && parent.change != Detach)
401                 m_update->addText(text, parent.element);
402
403             text.setHasValidStyle();
404             it.traverseNextSkippingChildren();
405             continue;
406         }
407
408         auto& element = downcast<Element>(node);
409
410         if (it.depth() > Settings::defaultMaximumRenderTreeDepth) {
411             resetStyleForNonRenderedDescendants(element);
412             element.clearChildNeedsStyleRecalc();
413             it.traverseNextSkippingChildren();
414             continue;
415         }
416
417         // FIXME: We should deal with this during style invalidation.
418         bool affectedByPreviousSibling = element.styleIsAffectedByPreviousSibling() && parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle;
419         if (element.needsStyleRecalc() || parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle)
420             parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle = element.affectsNextSiblingElementStyle();
421
422         auto* style = element.renderStyle();
423         auto change = NoChange;
424
425         bool shouldResolve = shouldResolveElement(element, parent.change) || affectedByPreviousSibling;
426         if (shouldResolve) {
427             if (!element.hasDisplayContents())
428                 element.resetComputedStyle();
429             element.resetStyleRelations();
430
431             if (element.hasCustomStyleResolveCallbacks())
432                 element.willRecalcStyle(parent.change);
433
434             auto elementUpdate = resolveElement(element);
435
436             if (element.hasCustomStyleResolveCallbacks())
437                 element.didRecalcStyle(elementUpdate.change);
438
439             style = elementUpdate.style.get();
440             change = elementUpdate.change;
441
442             if (affectedByPreviousSibling && change != Detach)
443                 change = Force;
444
445             if (elementUpdate.style)
446                 m_update->addElement(element, parent.element, WTFMove(elementUpdate));
447
448             clearNeedsStyleResolution(element);
449         }
450
451         if (!style) {
452             resetStyleForNonRenderedDescendants(element);
453             element.clearChildNeedsStyleRecalc();
454         }
455
456         bool shouldIterateChildren = style && (element.childNeedsStyleRecalc() || change != NoChange);
457
458         if (!m_didSeePendingStylesheet)
459             m_didSeePendingStylesheet = hasLoadingStylesheet(m_document.styleScope(), element, !shouldIterateChildren);
460
461         if (!shouldIterateChildren) {
462             it.traverseNextSkippingChildren();
463             continue;
464         }
465
466         pushParent(element, *style, change);
467
468         it.traverseNext();
469     }
470
471     popParentsToDepth(1);
472 }
473
474 std::unique_ptr<Update> TreeResolver::resolve()
475 {
476     auto& renderView = *m_document.renderView();
477
478     Element* documentElement = m_document.documentElement();
479     if (!documentElement) {
480         m_document.styleScope().resolver();
481         return nullptr;
482     }
483     if (!documentElement->childNeedsStyleRecalc() && !documentElement->needsStyleRecalc())
484         return nullptr;
485
486     m_didSeePendingStylesheet = m_document.styleScope().hasPendingSheetsBeforeBody();
487
488     m_update = std::make_unique<Update>(m_document);
489     m_scopeStack.append(adoptRef(*new Scope(m_document)));
490     m_parentStack.append(Parent(m_document));
491
492     // Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc.
493     renderView.setUsesFirstLineRules(renderView.usesFirstLineRules() || scope().styleResolver.usesFirstLineRules());
494     renderView.setUsesFirstLetterRules(renderView.usesFirstLetterRules() || scope().styleResolver.usesFirstLetterRules());
495
496     resolveComposedTree();
497
498     renderView.setUsesFirstLineRules(scope().styleResolver.usesFirstLineRules());
499     renderView.setUsesFirstLetterRules(scope().styleResolver.usesFirstLetterRules());
500
501     ASSERT(m_scopeStack.size() == 1);
502     ASSERT(m_parentStack.size() == 1);
503     m_parentStack.clear();
504     popScope();
505
506     if (m_update->roots().isEmpty())
507         return { };
508
509     return WTFMove(m_update);
510 }
511
512 static Vector<Function<void ()>>& postResolutionCallbackQueue()
513 {
514     static NeverDestroyed<Vector<Function<void ()>>> vector;
515     return vector;
516 }
517
518 void queuePostResolutionCallback(Function<void ()>&& callback)
519 {
520     postResolutionCallbackQueue().append(WTFMove(callback));
521 }
522
523 static void suspendMemoryCacheClientCalls(Document& document)
524 {
525     Page* page = document.page();
526     if (!page || !page->areMemoryCacheClientCallsEnabled())
527         return;
528
529     page->setMemoryCacheClientCallsEnabled(false);
530
531     postResolutionCallbackQueue().append([protectedMainFrame = Ref<MainFrame>(page->mainFrame())] {
532         if (Page* page = protectedMainFrame->page())
533             page->setMemoryCacheClientCallsEnabled(true);
534     });
535 }
536
537 static unsigned resolutionNestingDepth;
538
539 PostResolutionCallbackDisabler::PostResolutionCallbackDisabler(Document& document)
540 {
541     ++resolutionNestingDepth;
542
543     if (resolutionNestingDepth == 1)
544         platformStrategies()->loaderStrategy()->suspendPendingRequests();
545
546     // FIXME: It's strange to build this into the disabler.
547     suspendMemoryCacheClientCalls(document);
548 }
549
550 PostResolutionCallbackDisabler::~PostResolutionCallbackDisabler()
551 {
552     if (resolutionNestingDepth == 1) {
553         // Get size each time through the loop because a callback can add more callbacks to the end of the queue.
554         auto& queue = postResolutionCallbackQueue();
555         for (size_t i = 0; i < queue.size(); ++i)
556             queue[i]();
557         queue.clear();
558
559         platformStrategies()->loaderStrategy()->resumePendingRequests();
560     }
561
562     --resolutionNestingDepth;
563 }
564
565 bool postResolutionCallbacksAreSuspended()
566 {
567     return resolutionNestingDepth;
568 }
569
570 }
571 }