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