Use "= default" to denote default constructor or destructor
[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() = default;
63
64 TreeResolver::Scope::Scope(Document& document)
65     : styleResolver(document.styleScope().resolver())
66     , sharingResolver(document, styleResolver.ruleSets(), selectorFilter)
67 {
68 }
69
70 TreeResolver::Scope::Scope(ShadowRoot& shadowRoot, Scope& enclosingScope)
71     : styleResolver(shadowRoot.styleScope().resolver())
72     , sharingResolver(shadowRoot.documentScope(), styleResolver.ruleSets(), selectorFilter)
73     , shadowRoot(&shadowRoot)
74     , enclosingScope(&enclosingScope)
75 {
76     styleResolver.setOverrideDocumentElementStyle(enclosingScope.styleResolver.overrideDocumentElementStyle());
77 }
78
79 TreeResolver::Scope::~Scope()
80 {
81     styleResolver.setOverrideDocumentElementStyle(nullptr);
82 }
83
84 TreeResolver::Parent::Parent(Document& document)
85     : element(nullptr)
86     , style(*document.renderStyle())
87 {
88 }
89
90 TreeResolver::Parent::Parent(Element& element, const RenderStyle& style, Change change)
91     : element(&element)
92     , style(style)
93     , change(change)
94 {
95 }
96
97 void TreeResolver::pushScope(ShadowRoot& shadowRoot)
98 {
99     m_scopeStack.append(adoptRef(*new Scope(shadowRoot, scope())));
100 }
101
102 void TreeResolver::pushEnclosingScope()
103 {
104     ASSERT(scope().enclosingScope);
105     m_scopeStack.append(*scope().enclosingScope);
106 }
107
108 void TreeResolver::popScope()
109 {
110     return m_scopeStack.removeLast();
111 }
112
113 std::unique_ptr<RenderStyle> TreeResolver::styleForElement(Element& element, const RenderStyle& inheritedStyle)
114 {
115     if (element.hasCustomStyleResolveCallbacks()) {
116         RenderStyle* shadowHostStyle = scope().shadowRoot ? m_update->elementStyle(*scope().shadowRoot->host()) : nullptr;
117         if (auto customStyle = element.resolveCustomStyle(inheritedStyle, shadowHostStyle)) {
118             if (customStyle->relations)
119                 commitRelations(WTFMove(customStyle->relations), *m_update);
120
121             return WTFMove(customStyle->renderStyle);
122         }
123     }
124
125     if (auto style = scope().sharingResolver.resolve(element, *m_update))
126         return style;
127
128     auto elementStyle = scope().styleResolver.styleForElement(element, &inheritedStyle, parentBoxStyle(), MatchAllRules, &scope().selectorFilter);
129
130     if (elementStyle.relations)
131         commitRelations(WTFMove(elementStyle.relations), *m_update);
132
133     return WTFMove(elementStyle.renderStyle);
134 }
135
136 static void resetStyleForNonRenderedDescendants(Element& current)
137 {
138     // FIXME: This is not correct with shadow trees. This should be done with ComposedTreeIterator.
139     bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle = false;
140     for (auto& child : childrenOfType<Element>(current)) {
141         bool affectedByPreviousSibling = child.styleIsAffectedByPreviousSibling() && elementNeedingStyleRecalcAffectsNextSiblingElementStyle;
142         if (child.needsStyleRecalc() || elementNeedingStyleRecalcAffectsNextSiblingElementStyle)
143             elementNeedingStyleRecalcAffectsNextSiblingElementStyle = child.affectsNextSiblingElementStyle();
144
145         if (child.needsStyleRecalc() || affectedByPreviousSibling) {
146             child.resetComputedStyle();
147             child.resetStyleRelations();
148             child.setHasValidStyle();
149         }
150
151         if (child.childNeedsStyleRecalc()) {
152             resetStyleForNonRenderedDescendants(child);
153             child.clearChildNeedsStyleRecalc();
154         }
155     }
156 }
157
158 static bool affectsRenderedSubtree(Element& element, const RenderStyle& newStyle)
159 {
160     if (element.renderer())
161         return true;
162     if (newStyle.display() != NONE)
163         return true;
164     if (element.rendererIsNeeded(newStyle))
165         return true;
166     return false;
167 }
168
169 static const RenderStyle* renderOrDisplayContentsStyle(const Element& element)
170 {
171     if (auto* renderStyle = element.renderStyle())
172         return renderStyle;
173     if (element.hasDisplayContents())
174         return element.existingComputedStyle();
175     return nullptr;
176 }
177
178 ElementUpdates TreeResolver::resolveElement(Element& element)
179 {
180     if (m_didSeePendingStylesheet && !element.renderer() && !m_document.isIgnoringPendingStylesheets()) {
181         m_document.setHasNodesWithMissingStyle();
182         return { };
183     }
184
185     auto newStyle = styleForElement(element, parent().style);
186
187     if (!affectsRenderedSubtree(element, *newStyle))
188         return { };
189
190     auto* existingStyle = renderOrDisplayContentsStyle(element);
191
192     if (m_didSeePendingStylesheet && (!existingStyle || existingStyle->isNotFinal())) {
193         newStyle->setIsNotFinal();
194         m_document.setHasNodesWithNonFinalStyle();
195     }
196
197     auto update = createAnimatedElementUpdate(WTFMove(newStyle), element, parent().change);
198
199     if (&element == m_document.documentElement()) {
200         m_documentElementStyle = RenderStyle::clonePtr(*update.style);
201         scope().styleResolver.setOverrideDocumentElementStyle(m_documentElementStyle.get());
202
203         if (update.change != NoChange && existingStyle && existingStyle->computedFontPixelSize() != update.style->computedFontPixelSize()) {
204             // "rem" units are relative to the document element's font size so we need to recompute everything.
205             // In practice this is rare.
206             scope().styleResolver.invalidateMatchedPropertiesCache();
207             update.change = std::max(update.change, Force);
208         }
209     }
210
211     // This is needed for resolving color:-webkit-text for subsequent elements.
212     // FIXME: We shouldn't mutate document when resolving style.
213     if (&element == m_document.body())
214         m_document.setTextColor(update.style->visitedDependentColor(CSSPropertyColor));
215
216     // FIXME: These elements should not change renderer based on appearance property.
217     if (element.hasTagName(HTMLNames::meterTag) || is<HTMLProgressElement>(element)) {
218         if (existingStyle && update.style->appearance() != existingStyle->appearance())
219             update.change = Detach;
220     }
221
222     auto beforeUpdate = resolvePseudoStyle(element, update, BEFORE);
223     auto afterUpdate = resolvePseudoStyle(element, update, AFTER);
224
225     return { WTFMove(update), WTFMove(beforeUpdate), WTFMove(afterUpdate) };
226 }
227
228 ElementUpdate TreeResolver::resolvePseudoStyle(Element& element, const ElementUpdate& elementUpdate, PseudoId pseudoId)
229 {
230     if (!elementUpdate.style->hasPseudoStyle(pseudoId))
231         return { };
232
233     auto pseudoStyle = scope().styleResolver.pseudoStyleForElement(element, { pseudoId }, *elementUpdate.style);
234     if (!pseudoStyle)
235         return { };
236
237     PseudoElement* pseudoElement = pseudoId == BEFORE ? element.beforePseudoElement() : element.afterPseudoElement();
238     if (!pseudoElement) {
239         auto newPseudoElement = PseudoElement::create(element, pseudoId);
240         pseudoElement = newPseudoElement.ptr();
241         if (pseudoId == BEFORE)
242             element.setBeforePseudoElement(WTFMove(newPseudoElement));
243         else
244             element.setAfterPseudoElement(WTFMove(newPseudoElement));
245     }
246
247     return createAnimatedElementUpdate(WTFMove(pseudoStyle), *pseudoElement, elementUpdate.change);
248 }
249
250 const RenderStyle* TreeResolver::parentBoxStyle() const
251 {
252     // 'display: contents' doesn't generate boxes.
253     for (unsigned i = m_parentStack.size(); i; --i) {
254         auto& parent = m_parentStack[i - 1];
255         if (parent.style.display() == NONE)
256             return nullptr;
257         if (parent.style.display() != CONTENTS)
258             return &parent.style;
259     }
260     ASSERT_NOT_REACHED();
261     return nullptr;
262 }
263
264 ElementUpdate TreeResolver::createAnimatedElementUpdate(std::unique_ptr<RenderStyle> newStyle, Element& element, Change parentChange)
265 {
266     auto& animationController = m_document.frame()->animation();
267
268     auto* oldStyle = renderOrDisplayContentsStyle(element);
269     auto animationUpdate = animationController.updateAnimations(element, *newStyle, oldStyle);
270
271     if (animationUpdate.style)
272         newStyle = WTFMove(animationUpdate.style);
273
274     auto change = oldStyle ? determineChange(*oldStyle, *newStyle) : Detach;
275
276     auto validity = element.styleValidity();
277     if (validity >= Validity::SubtreeInvalid)
278         change = std::max(change, validity == Validity::SubtreeAndRenderersInvalid ? Detach : Force);
279     if (parentChange >= Force)
280         change = std::max(change, parentChange);
281
282     bool shouldRecompositeLayer = element.styleResolutionShouldRecompositeLayer() || animationUpdate.stateChanged;
283
284     return { WTFMove(newStyle), change, shouldRecompositeLayer };
285 }
286
287 void TreeResolver::pushParent(Element& element, const RenderStyle& style, Change change)
288 {
289     scope().selectorFilter.pushParent(&element);
290
291     Parent parent(element, style, change);
292
293     if (auto* shadowRoot = element.shadowRoot()) {
294         pushScope(*shadowRoot);
295         parent.didPushScope = true;
296     }
297     else if (is<HTMLSlotElement>(element) && downcast<HTMLSlotElement>(element).assignedNodes()) {
298         pushEnclosingScope();
299         parent.didPushScope = true;
300     }
301
302     m_parentStack.append(WTFMove(parent));
303 }
304
305 void TreeResolver::popParent()
306 {
307     auto& parentElement = *parent().element;
308
309     parentElement.setHasValidStyle();
310     parentElement.clearChildNeedsStyleRecalc();
311
312     if (parent().didPushScope)
313         popScope();
314
315     scope().selectorFilter.popParent();
316
317     m_parentStack.removeLast();
318 }
319
320 void TreeResolver::popParentsToDepth(unsigned depth)
321 {
322     ASSERT(depth);
323     ASSERT(m_parentStack.size() >= depth);
324
325     while (m_parentStack.size() > depth)
326         popParent();
327 }
328
329 static bool shouldResolvePseudoElement(const PseudoElement* pseudoElement)
330 {
331     if (!pseudoElement)
332         return false;
333     return pseudoElement->needsStyleRecalc();
334 }
335
336 static bool shouldResolveElement(const Element& element, Style::Change parentChange)
337 {
338     if (parentChange >= Inherit)
339         return true;
340     if (parentChange == NoInherit) {
341         auto* existingStyle = renderOrDisplayContentsStyle(element);
342         if (existingStyle && existingStyle->hasExplicitlyInheritedProperties())
343             return true;
344     }
345     if (element.needsStyleRecalc())
346         return true;
347     if (shouldResolvePseudoElement(element.beforePseudoElement()))
348         return true;
349     if (shouldResolvePseudoElement(element.afterPseudoElement()))
350         return true;
351
352     return false;
353 }
354
355 static void clearNeedsStyleResolution(Element& element)
356 {
357     element.setHasValidStyle();
358     if (auto* before = element.beforePseudoElement())
359         before->setHasValidStyle();
360     if (auto* after = element.afterPseudoElement())
361         after->setHasValidStyle();
362 }
363
364 static bool hasLoadingStylesheet(const Style::Scope& styleScope, const Element& element, bool checkDescendants)
365 {
366     if (!styleScope.hasPendingSheetsInBody())
367         return false;
368     if (styleScope.hasPendingSheetInBody(element))
369         return true;
370     if (!checkDescendants)
371         return false;
372     for (auto& descendant : descendantsOfType<Element>(element)) {
373         if (styleScope.hasPendingSheetInBody(descendant))
374             return true;
375     };
376     return false;
377 }
378
379 static std::unique_ptr<RenderStyle> createInheritedDisplayContentsStyleIfNeeded(const RenderStyle& parentElementStyle, const RenderStyle* parentBoxStyle)
380 {
381     if (parentElementStyle.display() != CONTENTS)
382         return nullptr;
383     if (parentBoxStyle && !parentBoxStyle->inheritedNotEqual(&parentElementStyle))
384         return nullptr;
385     // Compute style for imaginary unstyled <span> around the text node.
386     auto style = RenderStyle::createPtr();
387     style->inheritFrom(parentElementStyle);
388     return style;
389 }
390
391 void TreeResolver::resolveComposedTree()
392 {
393     ASSERT(m_parentStack.size() == 1);
394     ASSERT(m_scopeStack.size() == 1);
395
396     auto descendants = composedTreeDescendants(m_document);
397     auto it = descendants.begin();
398     auto end = descendants.end();
399
400     // FIXME: SVG <use> element may cause tree mutations during style recalc.
401     it.dropAssertions();
402
403     while (it != end) {
404         popParentsToDepth(it.depth());
405
406         auto& node = *it;
407         auto& parent = this->parent();
408
409         ASSERT(node.isConnected());
410         ASSERT(node.containingShadowRoot() == scope().shadowRoot);
411         ASSERT(node.parentElement() == parent.element || is<ShadowRoot>(node.parentNode()) || node.parentElement()->shadowRoot());
412
413         if (is<Text>(node)) {
414             auto& text = downcast<Text>(node);
415             
416             if ((text.styleValidity() >= Validity::SubtreeAndRenderersInvalid && parent.change != Detach) || parent.style.display() == CONTENTS) {
417                 TextUpdate textUpdate;
418                 textUpdate.inheritedDisplayContentsStyle = createInheritedDisplayContentsStyleIfNeeded(parent.style, parentBoxStyle());
419
420                 m_update->addText(text, parent.element, WTFMove(textUpdate));
421             }
422
423             text.setHasValidStyle();
424             it.traverseNextSkippingChildren();
425             continue;
426         }
427
428         auto& element = downcast<Element>(node);
429
430         if (it.depth() > Settings::defaultMaximumRenderTreeDepth) {
431             resetStyleForNonRenderedDescendants(element);
432             element.clearChildNeedsStyleRecalc();
433             it.traverseNextSkippingChildren();
434             continue;
435         }
436
437         // FIXME: We should deal with this during style invalidation.
438         bool affectedByPreviousSibling = element.styleIsAffectedByPreviousSibling() && parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle;
439         if (element.needsStyleRecalc() || parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle)
440             parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle = element.affectsNextSiblingElementStyle();
441
442         auto* style = renderOrDisplayContentsStyle(element);
443         auto change = NoChange;
444
445         bool shouldResolve = shouldResolveElement(element, parent.change) || affectedByPreviousSibling;
446         if (shouldResolve) {
447             if (!element.hasDisplayContents())
448                 element.resetComputedStyle();
449             element.resetStyleRelations();
450
451             if (element.hasCustomStyleResolveCallbacks())
452                 element.willRecalcStyle(parent.change);
453
454             auto elementUpdates = resolveElement(element);
455
456             if (element.hasCustomStyleResolveCallbacks())
457                 element.didRecalcStyle(elementUpdates.update.change);
458
459             style = elementUpdates.update.style.get();
460             change = elementUpdates.update.change;
461
462             if (affectedByPreviousSibling && change != Detach)
463                 change = Force;
464
465             if (elementUpdates.update.style)
466                 m_update->addElement(element, parent.element, WTFMove(elementUpdates));
467
468             clearNeedsStyleResolution(element);
469         }
470
471         if (!style) {
472             resetStyleForNonRenderedDescendants(element);
473             element.clearChildNeedsStyleRecalc();
474         }
475
476         bool shouldIterateChildren = style && (element.childNeedsStyleRecalc() || change != NoChange);
477
478         if (!m_didSeePendingStylesheet)
479             m_didSeePendingStylesheet = hasLoadingStylesheet(m_document.styleScope(), element, !shouldIterateChildren);
480
481         if (!shouldIterateChildren) {
482             it.traverseNextSkippingChildren();
483             continue;
484         }
485
486         pushParent(element, *style, change);
487
488         it.traverseNext();
489     }
490
491     popParentsToDepth(1);
492 }
493
494 std::unique_ptr<Update> TreeResolver::resolve()
495 {
496     auto& renderView = *m_document.renderView();
497
498     Element* documentElement = m_document.documentElement();
499     if (!documentElement) {
500         m_document.styleScope().resolver();
501         return nullptr;
502     }
503     if (!documentElement->childNeedsStyleRecalc() && !documentElement->needsStyleRecalc())
504         return nullptr;
505
506     m_didSeePendingStylesheet = m_document.styleScope().hasPendingSheetsBeforeBody();
507
508     m_update = std::make_unique<Update>(m_document);
509     m_scopeStack.append(adoptRef(*new Scope(m_document)));
510     m_parentStack.append(Parent(m_document));
511
512     // Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc.
513     renderView.setUsesFirstLineRules(renderView.usesFirstLineRules() || scope().styleResolver.usesFirstLineRules());
514     renderView.setUsesFirstLetterRules(renderView.usesFirstLetterRules() || scope().styleResolver.usesFirstLetterRules());
515
516     resolveComposedTree();
517
518     renderView.setUsesFirstLineRules(scope().styleResolver.usesFirstLineRules());
519     renderView.setUsesFirstLetterRules(scope().styleResolver.usesFirstLetterRules());
520
521     ASSERT(m_scopeStack.size() == 1);
522     ASSERT(m_parentStack.size() == 1);
523     m_parentStack.clear();
524     popScope();
525
526     if (m_update->roots().isEmpty())
527         return { };
528
529     return WTFMove(m_update);
530 }
531
532 static Vector<Function<void ()>>& postResolutionCallbackQueue()
533 {
534     static NeverDestroyed<Vector<Function<void ()>>> vector;
535     return vector;
536 }
537
538 void queuePostResolutionCallback(Function<void ()>&& callback)
539 {
540     postResolutionCallbackQueue().append(WTFMove(callback));
541 }
542
543 static void suspendMemoryCacheClientCalls(Document& document)
544 {
545     Page* page = document.page();
546     if (!page || !page->areMemoryCacheClientCallsEnabled())
547         return;
548
549     page->setMemoryCacheClientCallsEnabled(false);
550
551     postResolutionCallbackQueue().append([protectedMainFrame = Ref<MainFrame>(page->mainFrame())] {
552         if (Page* page = protectedMainFrame->page())
553             page->setMemoryCacheClientCallsEnabled(true);
554     });
555 }
556
557 static unsigned resolutionNestingDepth;
558
559 PostResolutionCallbackDisabler::PostResolutionCallbackDisabler(Document& document)
560 {
561     ++resolutionNestingDepth;
562
563     if (resolutionNestingDepth == 1)
564         platformStrategies()->loaderStrategy()->suspendPendingRequests();
565
566     // FIXME: It's strange to build this into the disabler.
567     suspendMemoryCacheClientCalls(document);
568 }
569
570 PostResolutionCallbackDisabler::~PostResolutionCallbackDisabler()
571 {
572     if (resolutionNestingDepth == 1) {
573         // Get size each time through the loop because a callback can add more callbacks to the end of the queue.
574         auto& queue = postResolutionCallbackQueue();
575         for (size_t i = 0; i < queue.size(); ++i)
576             queue[i]();
577         queue.clear();
578
579         platformStrategies()->loaderStrategy()->resumePendingRequests();
580     }
581
582     --resolutionNestingDepth;
583 }
584
585 bool postResolutionCallbacksAreSuspended()
586 {
587     return resolutionNestingDepth;
588 }
589
590 }
591 }