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