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