Resolve style iteratively
[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-2014 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 "AXObjectCache.h"
30 #include "AnimationController.h"
31 #include "AuthorStyleSheets.h"
32 #include "CSSFontSelector.h"
33 #include "ComposedTreeAncestorIterator.h"
34 #include "ComposedTreeIterator.h"
35 #include "ElementIterator.h"
36 #include "ElementRareData.h"
37 #include "FlowThreadController.h"
38 #include "HTMLSlotElement.h"
39 #include "InspectorInstrumentation.h"
40 #include "LoaderStrategy.h"
41 #include "MainFrame.h"
42 #include "NodeRenderStyle.h"
43 #include "NodeTraversal.h"
44 #include "PlatformStrategies.h"
45 #include "RenderFullScreen.h"
46 #include "RenderNamedFlowThread.h"
47 #include "RenderText.h"
48 #include "RenderTreePosition.h"
49 #include "RenderWidget.h"
50 #include "Settings.h"
51 #include "ShadowRoot.h"
52 #include "StyleResolver.h"
53 #include "Text.h"
54
55 #if PLATFORM(IOS)
56 #include "WKContentObservation.h"
57 #endif
58
59 namespace WebCore {
60
61 namespace Style {
62
63 enum DetachType { NormalDetach, ReattachDetach };
64
65 static void attachTextRenderer(Text&, RenderTreePosition&);
66 static void detachRenderTree(Element&, DetachType);
67 static void resolveTextNode(Text&, RenderTreePosition&);
68
69 class SelectorFilterPusher {
70 public:
71     enum PushMode { Push, NoPush };
72     SelectorFilterPusher(SelectorFilter& selectorFilter, Element& parent, PushMode pushMode = Push)
73         : m_selectorFilter(selectorFilter)
74         , m_parent(parent)
75     {
76         if (pushMode == Push)
77             push();
78     }
79     void push()
80     {
81         if (m_didPush)
82             return;
83         m_didPush = true;
84         m_selectorFilter.pushParent(&m_parent);
85     }
86     ~SelectorFilterPusher()
87     {
88         if (!m_didPush)
89             return;
90         m_selectorFilter.popParent();
91     }
92     
93 private:
94     SelectorFilter& m_selectorFilter;
95     Element& m_parent;
96     bool m_didPush { false };
97 };
98
99
100 static RenderStyle* placeholderStyle;
101
102 static void ensurePlaceholderStyle(Document& document)
103 {
104     if (placeholderStyle)
105         return;
106     placeholderStyle = &RenderStyle::create().leakRef();
107     placeholderStyle->setDisplay(NONE);
108     placeholderStyle->fontCascade().update(&document.fontSelector());
109 }
110
111 TreeResolver::TreeResolver(Document& document)
112     : m_document(document)
113 {
114     ensurePlaceholderStyle(document);
115 }
116
117 TreeResolver::Scope::Scope(Document& document)
118     : styleResolver(document.ensureStyleResolver())
119     , sharingResolver(document, styleResolver.ruleSets(), selectorFilter)
120 {
121 }
122
123 TreeResolver::Scope::Scope(ShadowRoot& shadowRoot, Scope& enclosingScope)
124     : styleResolver(shadowRoot.styleResolver())
125     , sharingResolver(shadowRoot.documentScope(), styleResolver.ruleSets(), selectorFilter)
126     , shadowRoot(&shadowRoot)
127     , enclosingScope(&enclosingScope)
128 {
129 }
130
131 TreeResolver::Parent::Parent(Document& document, Change change)
132     : element(nullptr)
133     , style(*document.renderStyle())
134     , renderTreePosition(*document.renderView())
135     , change(change)
136 {
137 }
138
139 TreeResolver::Parent::Parent(Element& element, RenderStyle& style, RenderTreePosition renderTreePosition, Change change)
140     : element(&element)
141     , style(style)
142     , renderTreePosition(renderTreePosition)
143     , change(change)
144 {
145 }
146
147 void TreeResolver::pushScope(ShadowRoot& shadowRoot)
148 {
149     m_scopeStack.append(adoptRef(*new Scope(shadowRoot, scope())));
150 }
151
152 void TreeResolver::pushEnclosingScope()
153 {
154     ASSERT(scope().enclosingScope);
155     m_scopeStack.append(*scope().enclosingScope);
156 }
157
158 void TreeResolver::popScope()
159 {
160     return m_scopeStack.removeLast();
161 }
162
163 static bool shouldCreateRenderer(const Element& element, const RenderElement& parentRenderer)
164 {
165     if (!element.document().shouldCreateRenderers())
166         return false;
167     if (!parentRenderer.canHaveChildren() && !(element.isPseudoElement() && parentRenderer.canHaveGeneratedChildren()))
168         return false;
169     if (parentRenderer.element() && !parentRenderer.element()->childShouldCreateRenderer(element))
170         return false;
171     return true;
172 }
173
174 Ref<RenderStyle> TreeResolver::styleForElement(Element& element, RenderStyle& inheritedStyle)
175 {
176     if (!m_document.haveStylesheetsLoaded() && !element.renderer()) {
177         m_document.setHasNodesWithPlaceholderStyle();
178         return *placeholderStyle;
179     }
180
181     if (element.hasCustomStyleResolveCallbacks()) {
182         if (RefPtr<RenderStyle> style = element.customStyleForRenderer(inheritedStyle))
183             return style.releaseNonNull();
184     }
185
186     if (auto* sharingElement = scope().sharingResolver.resolve(element))
187         return *sharingElement->renderStyle();
188
189     return scope().styleResolver.styleForElement(element, &inheritedStyle, MatchAllRules, nullptr, &scope().selectorFilter);
190 }
191
192 #if ENABLE(CSS_REGIONS)
193 static RenderNamedFlowThread* moveToFlowThreadIfNeeded(Element& element, const RenderStyle& style)
194 {
195     if (!element.shouldMoveToFlowThread(style))
196         return 0;
197
198     FlowThreadController& flowThreadController = element.document().renderView()->flowThreadController();
199     RenderNamedFlowThread& parentFlowRenderer = flowThreadController.ensureRenderFlowThreadWithName(style.flowThread());
200     flowThreadController.registerNamedFlowContentElement(element, parentFlowRenderer);
201     return &parentFlowRenderer;
202 }
203 #endif
204
205 void TreeResolver::createRenderer(Element& element, RenderTreePosition& renderTreePosition, RefPtr<RenderStyle>&& resolvedStyle)
206 {
207     ASSERT(shouldCreateRenderer(element, renderTreePosition.parent()));
208     ASSERT(resolvedStyle);
209
210     RenderNamedFlowThread* parentFlowRenderer = 0;
211 #if ENABLE(CSS_REGIONS)
212     parentFlowRenderer = moveToFlowThreadIfNeeded(element, *resolvedStyle);
213 #endif
214
215     if (!element.rendererIsNeeded(*resolvedStyle))
216         return;
217
218     renderTreePosition.computeNextSibling(element);
219
220     RenderTreePosition insertionPosition = parentFlowRenderer
221         ? RenderTreePosition(*parentFlowRenderer, parentFlowRenderer->nextRendererForElement(element))
222         : renderTreePosition;
223
224     RenderElement* newRenderer = element.createElementRenderer(resolvedStyle.releaseNonNull(), insertionPosition).leakPtr();
225     if (!newRenderer)
226         return;
227     if (!insertionPosition.canInsert(*newRenderer)) {
228         newRenderer->destroy();
229         return;
230     }
231
232     // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
233     // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
234     newRenderer->setFlowThreadState(insertionPosition.parent().flowThreadState());
235
236     // Code below updateAnimations() can depend on Element::renderer() already being set.
237     element.setRenderer(newRenderer);
238
239     // FIXME: There's probably a better way to factor this.
240     // This just does what setAnimatedStyle() does, except with setStyleInternal() instead of setStyle().
241     Ref<RenderStyle> animatedStyle = newRenderer->style();
242     newRenderer->animation().updateAnimations(*newRenderer, animatedStyle, animatedStyle);
243     newRenderer->setStyleInternal(WTFMove(animatedStyle));
244
245     newRenderer->initializeStyle();
246
247 #if ENABLE(FULLSCREEN_API)
248     if (m_document.webkitIsFullScreen() && m_document.webkitCurrentFullScreenElement() == &element) {
249         newRenderer = RenderFullScreen::wrapRenderer(newRenderer, &insertionPosition.parent(), m_document);
250         if (!newRenderer)
251             return;
252     }
253 #endif
254     // Note: Adding newRenderer instead of renderer(). renderer() may be a child of newRenderer.
255     insertionPosition.insert(*newRenderer);
256 }
257
258 static void invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(Node& current)
259 {
260     // FIXME: This needs to traverse in composed tree order.
261
262     // This function finds sibling text renderers where the results of textRendererIsNeeded may have changed as a result of
263     // the current node gaining or losing the renderer. This can only affect white space text nodes.
264     for (Node* sibling = current.nextSibling(); sibling; sibling = sibling->nextSibling()) {
265         if (sibling->needsStyleRecalc())
266             return;
267         if (is<Element>(*sibling)) {
268             // Text renderers beyond rendered elements can't be affected.
269             if (!sibling->renderer() || RenderTreePosition::isRendererReparented(*sibling->renderer()))
270                 continue;
271             return;
272         }
273         if (!is<Text>(*sibling))
274             continue;
275         Text& textSibling = downcast<Text>(*sibling);
276         if (!textSibling.containsOnlyWhitespace())
277             continue;
278         textSibling.setNeedsStyleRecalc();
279     }
280 }
281
282 static bool textRendererIsNeeded(const Text& textNode, const RenderTreePosition& renderTreePosition)
283 {
284     const RenderElement& parentRenderer = renderTreePosition.parent();
285     if (!parentRenderer.canHaveChildren())
286         return false;
287     if (parentRenderer.element() && !parentRenderer.element()->childShouldCreateRenderer(textNode))
288         return false;
289     if (textNode.isEditingText())
290         return true;
291     if (!textNode.length())
292         return false;
293     if (!textNode.containsOnlyWhitespace())
294         return true;
295     // This text node has nothing but white space. We may still need a renderer in some cases.
296     if (parentRenderer.isTable() || parentRenderer.isTableRow() || parentRenderer.isTableSection() || parentRenderer.isRenderTableCol() || parentRenderer.isFrameSet())
297         return false;
298     if (parentRenderer.style().preserveNewline()) // pre/pre-wrap/pre-line always make renderers.
299         return true;
300
301     RenderObject* previousRenderer = renderTreePosition.previousSiblingRenderer(textNode);
302     if (previousRenderer && previousRenderer->isBR()) // <span><br/> <br/></span>
303         return false;
304
305     if (parentRenderer.isRenderInline()) {
306         // <span><div/> <div/></span>
307         if (previousRenderer && !previousRenderer->isInline())
308             return false;
309     } else {
310         if (parentRenderer.isRenderBlock() && !parentRenderer.childrenInline() && (!previousRenderer || !previousRenderer->isInline()))
311             return false;
312         
313         RenderObject* first = parentRenderer.firstChild();
314         while (first && first->isFloatingOrOutOfFlowPositioned())
315             first = first->nextSibling();
316         RenderObject* nextRenderer = renderTreePosition.nextSiblingRenderer(textNode);
317         if (!first || nextRenderer == first) {
318             // Whitespace at the start of a block just goes away. Don't even make a render object for this text.
319             return false;
320         }
321     }
322     return true;
323 }
324
325 static void createTextRendererIfNeeded(Text& textNode, RenderTreePosition& renderTreePosition)
326 {
327     ASSERT(!textNode.renderer());
328
329     if (!textRendererIsNeeded(textNode, renderTreePosition))
330         return;
331
332     auto newRenderer = textNode.createTextRenderer(renderTreePosition.parent().style());
333     ASSERT(newRenderer);
334
335     renderTreePosition.computeNextSibling(textNode);
336
337     if (!renderTreePosition.canInsert(*newRenderer))
338         return;
339
340     // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
341     // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
342     newRenderer->setFlowThreadState(renderTreePosition.parent().flowThreadState());
343
344     textNode.setRenderer(newRenderer.get());
345     // Parent takes care of the animations, no need to call setAnimatableStyle.
346     renderTreePosition.insert(*newRenderer.leakPtr());
347 }
348
349 void attachTextRenderer(Text& textNode, RenderTreePosition& renderTreePosition)
350 {
351     createTextRendererIfNeeded(textNode, renderTreePosition);
352
353     textNode.clearNeedsStyleRecalc();
354 }
355
356 void detachTextRenderer(Text& textNode)
357 {
358     if (textNode.renderer())
359         textNode.renderer()->destroyAndCleanupAnonymousWrappers();
360     textNode.setRenderer(0);
361 }
362
363 void updateTextRendererAfterContentChange(Text& textNode, unsigned offsetOfReplacedData, unsigned lengthOfReplacedData)
364 {
365     auto* renderingParentNode = composedTreeAncestors(textNode).first();
366     if (!renderingParentNode || !renderingParentNode->renderer())
367         return;
368
369     bool hadRenderer = textNode.renderer();
370
371     RenderTreePosition renderTreePosition(*renderingParentNode->renderer());
372     resolveTextNode(textNode, renderTreePosition);
373
374     if (hadRenderer && textNode.renderer())
375         textNode.renderer()->setTextWithOffset(textNode.data(), offsetOfReplacedData, lengthOfReplacedData);
376 }
377
378 void TreeResolver::createRenderTreeForChildren(ContainerNode& current, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition)
379 {
380     for (Node* child = current.firstChild(); child; child = child->nextSibling()) {
381         ASSERT((!child->renderer() || child->isNamedFlowContentNode()) || current.shadowRoot());
382         if (child->renderer()) {
383             renderTreePosition.invalidateNextSibling(*child->renderer());
384             continue;
385         }
386         if (is<Text>(*child)) {
387             attachTextRenderer(downcast<Text>(*child), renderTreePosition);
388             continue;
389         }
390         if (is<Element>(*child))
391             createRenderTreeRecursively(downcast<Element>(*child), inheritedStyle, renderTreePosition, nullptr);
392     }
393 }
394
395 void TreeResolver::createRenderTreeForShadowRoot(ShadowRoot& shadowRoot)
396 {
397     ASSERT(shadowRoot.host());
398     ASSERT(shadowRoot.host()->renderer());
399
400     pushScope(shadowRoot);
401
402     auto& renderer = *shadowRoot.host()->renderer();
403     RenderTreePosition renderTreePosition(renderer);
404     createRenderTreeForChildren(shadowRoot, renderer.style(), renderTreePosition);
405
406     popScope();
407
408     shadowRoot.clearNeedsStyleRecalc();
409     shadowRoot.clearChildNeedsStyleRecalc();
410 }
411
412 static PseudoElement* beforeOrAfterPseudoElement(Element& current, PseudoId pseudoId)
413 {
414     ASSERT(pseudoId == BEFORE || pseudoId == AFTER);
415     if (pseudoId == BEFORE)
416         return current.beforePseudoElement();
417     return current.afterPseudoElement();
418 }
419
420 static void setBeforeOrAfterPseudoElement(Element& current, Ref<PseudoElement>&& pseudoElement, PseudoId pseudoId)
421 {
422     ASSERT(pseudoId == BEFORE || pseudoId == AFTER);
423     if (pseudoId == BEFORE) {
424         current.setBeforePseudoElement(WTFMove(pseudoElement));
425         return;
426     }
427     current.setAfterPseudoElement(WTFMove(pseudoElement));
428 }
429
430 static void clearBeforeOrAfterPseudoElement(Element& current, PseudoId pseudoId)
431 {
432     ASSERT(pseudoId == BEFORE || pseudoId == AFTER);
433     if (pseudoId == BEFORE) {
434         current.clearBeforePseudoElement();
435         return;
436     }
437     current.clearAfterPseudoElement();
438 }
439
440 static void resetStyleForNonRenderedDescendants(Element& current)
441 {
442     // FIXME: This is not correct with shadow trees. This should be done with ComposedTreeIterator.
443     ASSERT(!current.renderer());
444     bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle = false;
445     for (auto& child : childrenOfType<Element>(current)) {
446         ASSERT(!child.renderer());
447         bool affectedByPreviousSibling = child.styleIsAffectedByPreviousSibling() && elementNeedingStyleRecalcAffectsNextSiblingElementStyle;
448         if (child.needsStyleRecalc() || elementNeedingStyleRecalcAffectsNextSiblingElementStyle)
449             elementNeedingStyleRecalcAffectsNextSiblingElementStyle = child.affectsNextSiblingElementStyle();
450
451         if (child.needsStyleRecalc() || affectedByPreviousSibling) {
452             child.resetComputedStyle();
453             child.clearNeedsStyleRecalc();
454         }
455
456         if (child.childNeedsStyleRecalc()) {
457             resetStyleForNonRenderedDescendants(child);
458             child.clearChildNeedsStyleRecalc();
459         }
460     }
461 }
462
463 static bool needsPseudoElement(Element& current, PseudoId pseudoId)
464 {
465     if (!current.renderer() || !current.renderer()->canHaveGeneratedChildren())
466         return false;
467     if (current.isPseudoElement())
468         return false;
469     if (!pseudoElementRendererIsNeeded(current.renderer()->getCachedPseudoStyle(pseudoId)))
470         return false;
471     return true;
472 }
473
474 void TreeResolver::createRenderTreeForBeforeOrAfterPseudoElement(Element& current, PseudoId pseudoId, RenderTreePosition& renderTreePosition)
475 {
476     if (!needsPseudoElement(current, pseudoId))
477         return;
478     Ref<PseudoElement> pseudoElement = PseudoElement::create(current, pseudoId);
479     InspectorInstrumentation::pseudoElementCreated(m_document.page(), pseudoElement.get());
480     setBeforeOrAfterPseudoElement(current, pseudoElement.copyRef(), pseudoId);
481     createRenderTreeRecursively(pseudoElement.get(), *current.renderStyle(), renderTreePosition, nullptr);
482 }
483
484 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
485 void TreeResolver::createRenderTreeForSlotAssignees(HTMLSlotElement& slot, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition)
486 {
487     ASSERT(shouldCreateRenderer(slot, renderTreePosition.parent()));
488
489     if (auto* assignedNodes = slot.assignedNodes()) {
490         pushEnclosingScope();
491         for (auto* child : *assignedNodes) {
492             if (is<Text>(*child))
493                 attachTextRenderer(downcast<Text>(*child), renderTreePosition);
494             else if (is<Element>(*child))
495                 createRenderTreeRecursively(downcast<Element>(*child), inheritedStyle, renderTreePosition, nullptr);
496         }
497         popScope();
498     } else {
499         SelectorFilterPusher selectorFilterPusher(scope().selectorFilter, slot);
500         createRenderTreeForChildren(slot, inheritedStyle, renderTreePosition);
501     }
502
503     slot.clearNeedsStyleRecalc();
504     slot.clearChildNeedsStyleRecalc();
505 }
506 #endif
507
508 void TreeResolver::createRenderTreeRecursively(Element& current, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, RefPtr<RenderStyle>&& resolvedStyle)
509 {
510     ASSERT(!current.renderer());
511
512     PostResolutionCallbackDisabler callbackDisabler(m_document);
513     WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
514
515     bool shouldCallCreateRenderer = shouldCreateRenderer(current, renderTreePosition.parent());
516
517     RefPtr<RenderStyle> style = resolvedStyle;
518     if (!style)
519         style = styleForElement(current, inheritedStyle);
520
521 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
522     if (is<HTMLSlotElement>(current)) {
523         if (shouldCallCreateRenderer && current.rendererIsNeeded(*style))
524             createRenderTreeForSlotAssignees(downcast<HTMLSlotElement>(current), inheritedStyle, renderTreePosition);
525         return;
526     }
527 #endif
528
529     if (current.hasCustomStyleResolveCallbacks())
530         current.willAttachRenderers();
531
532     if (shouldCallCreateRenderer)
533         createRenderer(current, renderTreePosition, style.releaseNonNull());
534
535     if (auto* renderer = current.renderer()) {
536         SelectorFilterPusher selectorFilterPusher(scope().selectorFilter, current, SelectorFilterPusher::NoPush);
537
538         RenderTreePosition childRenderTreePosition(*renderer);
539         createRenderTreeForBeforeOrAfterPseudoElement(current, BEFORE, childRenderTreePosition);
540
541         auto* shadowRoot = current.shadowRoot();
542         if (shadowRoot) {
543             selectorFilterPusher.push();
544             createRenderTreeForShadowRoot(*shadowRoot);
545         } else if (current.firstChild())
546             selectorFilterPusher.push();
547
548         bool skipChildren = shadowRoot;
549         if (!skipChildren)
550             createRenderTreeForChildren(current, renderer->style(), childRenderTreePosition);
551
552         if (AXObjectCache* cache = m_document.axObjectCache())
553             cache->updateCacheAfterNodeIsAttached(&current);
554
555         createRenderTreeForBeforeOrAfterPseudoElement(current, AFTER, childRenderTreePosition);
556
557         current.updateFocusAppearanceAfterAttachIfNeeded();
558     } else
559         resetStyleForNonRenderedDescendants(current);
560
561     current.clearNeedsStyleRecalc();
562     current.clearChildNeedsStyleRecalc();
563
564     if (current.hasCustomStyleResolveCallbacks())
565         current.didAttachRenderers();
566 }
567
568 static void detachChildren(ContainerNode& current, DetachType detachType)
569 {
570     for (Node* child = current.firstChild(); child; child = child->nextSibling()) {
571         if (is<Text>(*child))
572             detachTextRenderer(downcast<Text>(*child));
573         else if (is<Element>(*child))
574             detachRenderTree(downcast<Element>(*child), detachType);
575     }
576     current.clearChildNeedsStyleRecalc();
577 }
578
579 static void detachShadowRoot(ShadowRoot& shadowRoot, DetachType detachType)
580 {
581     detachChildren(shadowRoot, detachType);
582 }
583
584 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
585 static void detachSlotAssignees(HTMLSlotElement& slot, DetachType detachType)
586 {
587     ASSERT(!slot.renderer());
588     if (auto* assignedNodes = slot.assignedNodes()) {
589         for (auto* child : *assignedNodes) {
590             if (is<Text>(*child))
591                 detachTextRenderer(downcast<Text>(*child));
592             else if (is<Element>(*child))
593                 detachRenderTree(downcast<Element>(*child), detachType);
594         }
595     } else
596         detachChildren(slot, detachType);
597
598     slot.clearNeedsStyleRecalc();
599     slot.clearChildNeedsStyleRecalc();
600 }
601 #endif
602
603 static void detachRenderTree(Element& current, DetachType detachType)
604 {
605     WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
606
607     if (current.hasCustomStyleResolveCallbacks())
608         current.willDetachRenderers();
609
610     current.clearStyleDerivedDataBeforeDetachingRenderer();
611
612     // Do not remove the element's hovered and active status
613     // if performing a reattach.
614     if (detachType != ReattachDetach)
615         current.clearHoverAndActiveStatusBeforeDetachingRenderer();
616
617 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
618     if (is<HTMLSlotElement>(current))
619         detachSlotAssignees(downcast<HTMLSlotElement>(current), detachType);
620 #endif
621     else if (ShadowRoot* shadowRoot = current.shadowRoot())
622         detachShadowRoot(*shadowRoot, detachType);
623
624     detachChildren(current, detachType);
625
626     if (current.renderer())
627         current.renderer()->destroyAndCleanupAnonymousWrappers();
628     current.setRenderer(nullptr);
629
630     if (current.hasCustomStyleResolveCallbacks())
631         current.didDetachRenderers();
632 }
633
634 static bool pseudoStyleCacheIsInvalid(RenderElement* renderer, RenderStyle* newStyle)
635 {
636     const RenderStyle& currentStyle = renderer->style();
637
638     const PseudoStyleCache* pseudoStyleCache = currentStyle.cachedPseudoStyles();
639     if (!pseudoStyleCache)
640         return false;
641
642     for (auto& cache : *pseudoStyleCache) {
643         RefPtr<RenderStyle> newPseudoStyle;
644         PseudoId pseudoId = cache->styleType();
645         if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
646             newPseudoStyle = renderer->uncachedFirstLineStyle(newStyle);
647         else
648             newPseudoStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle);
649         if (!newPseudoStyle)
650             return true;
651         if (*newPseudoStyle != *cache) {
652             if (pseudoId < FIRST_INTERNAL_PSEUDOID)
653                 newStyle->setHasPseudoStyle(pseudoId);
654             newStyle->addCachedPseudoStyle(newPseudoStyle);
655             if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
656                 // FIXME: We should do an actual diff to determine whether a repaint vs. layout
657                 // is needed, but for now just assume a layout will be required. The diff code
658                 // in RenderObject::setStyle would need to be factored out so that it could be reused.
659                 renderer->setNeedsLayoutAndPrefWidthsRecalc();
660             }
661             return true;
662         }
663     }
664     return false;
665 }
666
667 Change TreeResolver::resolveElement(Element& current)
668 {
669     Change localChange = Detach;
670     RefPtr<RenderStyle> newStyle;
671     RefPtr<RenderStyle> currentStyle = current.renderStyle();
672
673     if (currentStyle && current.styleChangeType() != ReconstructRenderTree) {
674         Ref<RenderStyle> style(styleForElement(current, parent().style));
675         newStyle = style.ptr();
676         localChange = determineChange(*currentStyle, style);
677     }
678     if (localChange == Detach) {
679         if (current.renderer() || current.isNamedFlowContentNode())
680             detachRenderTree(current, ReattachDetach);
681 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
682         else if (is<HTMLSlotElement>(current))
683             detachRenderTree(current, ReattachDetach);
684 #endif
685         createRenderTreeRecursively(current, parent().style, parent().renderTreePosition, newStyle.release());
686         invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(current);
687
688         return Detach;
689     }
690
691     if (RenderElement* renderer = current.renderer()) {
692         if (localChange != NoChange || pseudoStyleCacheIsInvalid(renderer, newStyle.get()) || (parent().change == Force && renderer->requiresForcedStyleRecalcPropagation()) || current.styleChangeType() == SyntheticStyleChange)
693             renderer->setAnimatableStyle(*newStyle, current.styleChangeType() == SyntheticStyleChange ? StyleDifferenceRecompositeLayer : StyleDifferenceEqual);
694         else if (current.needsStyleRecalc()) {
695             // Although no change occurred, we use the new style so that the cousin style sharing code won't get
696             // fooled into believing this style is the same.
697             renderer->setStyleInternal(*newStyle);
698         }
699     }
700
701     // If "rem" units are used anywhere in the document, and if the document element's font size changes, then force font updating
702     // all the way down the tree. This is simpler than having to maintain a cache of objects (and such font size changes should be rare anyway).
703     if (m_document.authorStyleSheets().usesRemUnits() && m_document.documentElement() == &current && localChange != NoChange && currentStyle && newStyle && currentStyle->fontSize() != newStyle->fontSize()) {
704         // Cached RenderStyles may depend on the re units.
705         scope().styleResolver.invalidateMatchedPropertiesCache();
706         return Force;
707     }
708     if (parent().change == Force || current.styleChangeType() >= FullStyleChange)
709         return Force;
710
711     return localChange;
712 }
713
714 void resolveTextNode(Text& text, RenderTreePosition& renderTreePosition)
715 {
716     text.clearNeedsStyleRecalc();
717
718     bool hasRenderer = text.renderer();
719     bool needsRenderer = textRendererIsNeeded(text, renderTreePosition);
720     if (hasRenderer) {
721         if (needsRenderer)
722             return;
723         detachTextRenderer(text);
724         invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(text);
725         return;
726     }
727     if (!needsRenderer)
728         return;
729     attachTextRenderer(text, renderTreePosition);
730     invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(text);
731 }
732
733 void TreeResolver::resolveBeforeOrAfterPseudoElement(Element& current, Change change, PseudoId pseudoId, RenderTreePosition& renderTreePosition)
734 {
735     if (!current.renderer())
736         return;
737     PseudoElement* existingPseudoElement = beforeOrAfterPseudoElement(current, pseudoId);
738     if (!existingPseudoElement) {
739         createRenderTreeForBeforeOrAfterPseudoElement(current, pseudoId, renderTreePosition);
740         return;
741     }
742
743     if (existingPseudoElement->renderer())
744         renderTreePosition.invalidateNextSibling(*existingPseudoElement->renderer());
745
746     if (change == NoChange && !existingPseudoElement->needsStyleRecalc())
747         return;
748
749     if (needsPseudoElement(current, pseudoId)) {
750         auto change = resolveElement(*existingPseudoElement);
751         existingPseudoElement->didRecalcStyle(change);
752         existingPseudoElement->clearNeedsStyleRecalc();
753     } else
754         clearBeforeOrAfterPseudoElement(current, pseudoId);
755 }
756
757 #if PLATFORM(IOS)
758 static EVisibility elementImplicitVisibility(const Element* element)
759 {
760     RenderObject* renderer = element->renderer();
761     if (!renderer)
762         return VISIBLE;
763
764     RenderStyle& style = renderer->style();
765
766     Length width(style.width());
767     Length height(style.height());
768     if ((width.isFixed() && width.value() <= 0) || (height.isFixed() && height.value() <= 0))
769         return HIDDEN;
770
771     Length top(style.top());
772     Length left(style.left());
773     if (left.isFixed() && width.isFixed() && -left.value() >= width.value())
774         return HIDDEN;
775
776     if (top.isFixed() && height.isFixed() && -top.value() >= height.value())
777         return HIDDEN;
778     return VISIBLE;
779 }
780
781 class CheckForVisibilityChangeOnRecalcStyle {
782 public:
783     CheckForVisibilityChangeOnRecalcStyle(Element* element, RenderStyle* currentStyle)
784         : m_element(element)
785         , m_previousDisplay(currentStyle ? currentStyle->display() : NONE)
786         , m_previousVisibility(currentStyle ? currentStyle->visibility() : HIDDEN)
787         , m_previousImplicitVisibility(WKObservingContentChanges() && WKContentChange() != WKContentVisibilityChange ? elementImplicitVisibility(element) : VISIBLE)
788     {
789     }
790     ~CheckForVisibilityChangeOnRecalcStyle()
791     {
792         if (!WKObservingContentChanges())
793             return;
794         if (m_element->isInUserAgentShadowTree())
795             return;
796         RenderStyle* style = m_element->renderStyle();
797         if (!style)
798             return;
799         if ((m_previousDisplay == NONE && style->display() != NONE) || (m_previousVisibility == HIDDEN && style->visibility() != HIDDEN)
800             || (m_previousImplicitVisibility == HIDDEN && elementImplicitVisibility(m_element.get()) == VISIBLE))
801             WKSetObservedContentChange(WKContentVisibilityChange);
802     }
803 private:
804     RefPtr<Element> m_element;
805     EDisplay m_previousDisplay;
806     EVisibility m_previousVisibility;
807     EVisibility m_previousImplicitVisibility;
808 };
809 #endif // PLATFORM(IOS)
810
811 void TreeResolver::pushParent(Element& element, RenderStyle& style, RenderTreePosition renderTreePosition, Change change)
812 {
813     scope().selectorFilter.pushParent(&element);
814
815     Parent parent(element, style, renderTreePosition, change);
816
817     if (auto* shadowRoot = element.shadowRoot()) {
818         pushScope(*shadowRoot);
819         parent.didPushScope = true;
820     }
821 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
822     else if (is<HTMLSlotElement>(element) && downcast<HTMLSlotElement>(element).assignedNodes()) {
823         pushEnclosingScope();
824         parent.didPushScope = true;
825     }
826 #endif
827
828     m_parentStack.append(WTFMove(parent));
829
830     resolveBeforeOrAfterPseudoElement(element, change, BEFORE, renderTreePosition);
831 }
832
833 void TreeResolver::popParent()
834 {
835     auto& parentElement = *parent().element;
836
837     resolveBeforeOrAfterPseudoElement(parentElement, parent().change, AFTER, parent().renderTreePosition);
838
839     parentElement.clearNeedsStyleRecalc();
840     parentElement.clearChildNeedsStyleRecalc();
841
842     if (parent().didPushScope)
843         popScope();
844
845     scope().selectorFilter.popParent();
846
847     m_parentStack.removeLast();
848 }
849
850 void TreeResolver::popParentsToDepth(unsigned depth)
851 {
852     ASSERT(depth);
853     ASSERT(m_parentStack.size() >= depth);
854
855     while (m_parentStack.size() > depth)
856         popParent();
857 }
858
859 void TreeResolver::resolveComposedTree()
860 {
861     ASSERT(m_parentStack.size() == 1);
862     ASSERT(m_scopeStack.size() == 1);
863
864     auto descendants = composedTreeDescendants(m_document);
865     auto it = descendants.begin();
866     auto end = descendants.end();
867
868     // FIXME: SVG <use> element may cause tree mutations during style recalc.
869     it.dropAssertions();
870
871     while (it != end) {
872         popParentsToDepth(it.depth());
873
874         auto& node = *it;
875         auto& parent = this->parent();
876
877         ASSERT(node.containingShadowRoot() == scope().shadowRoot);
878         ASSERT(node.parentElement() == parent.element || is<ShadowRoot>(node.parentNode()) || node.parentElement()->shadowRoot());
879
880         if (auto* existingRenderer = node.renderer())
881             parent.renderTreePosition.invalidateNextSibling(*existingRenderer);
882
883         if (is<Text>(node)) {
884             if (node.needsStyleRecalc())
885                 resolveTextNode(downcast<Text>(node), parent.renderTreePosition);
886             it.traverseNextSkippingChildren();
887             continue;
888         }
889
890         auto& element = downcast<Element>(node);
891
892         // FIXME: We should deal with this during style invalidation.
893         bool affectedByPreviousSibling = element.styleIsAffectedByPreviousSibling() && parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle;
894         if (element.needsStyleRecalc() || parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle)
895             parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle = element.affectsNextSiblingElementStyle();
896
897         Change change = NoChange;
898
899         bool shouldResolve = parent.change >= Inherit || element.needsStyleRecalc() || affectedByPreviousSibling;
900         if (shouldResolve) {
901 #if PLATFORM(IOS)
902             CheckForVisibilityChangeOnRecalcStyle checkForVisibilityChange(&element, element.renderStyle());
903 #endif
904             element.resetComputedStyle();
905
906             if (element.hasCustomStyleResolveCallbacks()) {
907                 if (!element.willRecalcStyle(parent.change)) {
908                     it.traverseNextSkippingChildren();
909                     continue;
910                 }
911             }
912             change = resolveElement(element);
913
914             element.clearNeedsStyleRecalc();
915
916             if (element.hasCustomStyleResolveCallbacks())
917                 element.didRecalcStyle(change);
918
919             if (change == Detach) {
920                 it.traverseNextSkippingChildren();
921                 continue;
922             }
923
924             if (affectedByPreviousSibling)
925                 change = Force;
926         }
927
928 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
929         if (is<HTMLSlotElement>(element)) {
930             // FIXME: We should compute style for the slot and use it as parent style.
931             // FIXME: This should be display:contents check.
932             // Duplicate the style and render tree position from the current context.
933             pushParent(element, parent.style.get(), parent.renderTreePosition, change);
934             it.traverseNext();
935             continue;
936         }
937 #endif
938         auto* renderer = element.renderer();
939         if (!renderer) {
940             resetStyleForNonRenderedDescendants(element);
941             element.clearChildNeedsStyleRecalc();
942         }
943
944         bool shouldIterateChildren = renderer && (element.childNeedsStyleRecalc() || change != NoChange);
945         if (!shouldIterateChildren) {
946             it.traverseNextSkippingChildren();
947             continue;
948         }
949
950         pushParent(element, renderer->style(), RenderTreePosition(*renderer), change);
951
952         it.traverseNext();
953     }
954
955     popParentsToDepth(1);
956 }
957
958 void TreeResolver::resolve(Change change)
959 {
960     auto& renderView = *m_document.renderView();
961
962     Element* documentElement = m_document.documentElement();
963     if (!documentElement)
964         return;
965     if (change != Force && !documentElement->childNeedsStyleRecalc() && !documentElement->needsStyleRecalc())
966         return;
967
968     m_scopeStack.append(adoptRef(*new Scope(m_document)));
969
970     // Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc.
971     renderView.setUsesFirstLineRules(renderView.usesFirstLineRules() || scope().styleResolver.usesFirstLineRules());
972     renderView.setUsesFirstLetterRules(renderView.usesFirstLetterRules() || scope().styleResolver.usesFirstLetterRules());
973
974     m_parentStack.append(Parent(m_document, change));
975
976     resolveComposedTree();
977
978     renderView.setUsesFirstLineRules(scope().styleResolver.usesFirstLineRules());
979     renderView.setUsesFirstLetterRules(scope().styleResolver.usesFirstLetterRules());
980
981     m_parentStack.clear();
982     m_scopeStack.clear();
983 }
984
985 void detachRenderTree(Element& element)
986 {
987     detachRenderTree(element, NormalDetach);
988 }
989
990 static Vector<std::function<void ()>>& postResolutionCallbackQueue()
991 {
992     static NeverDestroyed<Vector<std::function<void ()>>> vector;
993     return vector;
994 }
995
996 void queuePostResolutionCallback(std::function<void ()> callback)
997 {
998     postResolutionCallbackQueue().append(callback);
999 }
1000
1001 static void suspendMemoryCacheClientCalls(Document& document)
1002 {
1003     Page* page = document.page();
1004     if (!page || !page->areMemoryCacheClientCallsEnabled())
1005         return;
1006
1007     page->setMemoryCacheClientCallsEnabled(false);
1008
1009     RefPtr<MainFrame> protectedMainFrame = &page->mainFrame();
1010     postResolutionCallbackQueue().append([protectedMainFrame]{
1011         if (Page* page = protectedMainFrame->page())
1012             page->setMemoryCacheClientCallsEnabled(true);
1013     });
1014 }
1015
1016 static unsigned resolutionNestingDepth;
1017
1018 PostResolutionCallbackDisabler::PostResolutionCallbackDisabler(Document& document)
1019 {
1020     ++resolutionNestingDepth;
1021
1022     if (resolutionNestingDepth == 1)
1023         platformStrategies()->loaderStrategy()->suspendPendingRequests();
1024
1025     // FIXME: It's strange to build this into the disabler.
1026     suspendMemoryCacheClientCalls(document);
1027 }
1028
1029 PostResolutionCallbackDisabler::~PostResolutionCallbackDisabler()
1030 {
1031     if (resolutionNestingDepth == 1) {
1032         // Get size each time through the loop because a callback can add more callbacks to the end of the queue.
1033         auto& queue = postResolutionCallbackQueue();
1034         for (size_t i = 0; i < queue.size(); ++i)
1035             queue[i]();
1036         queue.clear();
1037
1038         platformStrategies()->loaderStrategy()->resumePendingRequests();
1039     }
1040
1041     --resolutionNestingDepth;
1042 }
1043
1044 bool postResolutionCallbacksAreSuspended()
1045 {
1046     return resolutionNestingDepth;
1047 }
1048
1049 bool isPlaceholderStyle(const RenderStyle& style)
1050 {
1051     return &style == placeholderStyle;
1052 }
1053
1054 }
1055 }