Slot elements should support fallback contents
[WebKit-https.git] / Source / WebCore / style / StyleResolveTree.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 "StyleResolveTree.h"
28
29 #include "AXObjectCache.h"
30 #include "AnimationController.h"
31 #include "AuthorStyleSheets.h"
32 #include "CSSFontSelector.h"
33 #include "ElementIterator.h"
34 #include "ElementRareData.h"
35 #include "FlowThreadController.h"
36 #include "HTMLSlotElement.h"
37 #include "InsertionPoint.h"
38 #include "InspectorInstrumentation.h"
39 #include "LoaderStrategy.h"
40 #include "MainFrame.h"
41 #include "NodeRenderStyle.h"
42 #include "NodeRenderingTraversal.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 "ResourceLoadScheduler.h"
51 #include "Settings.h"
52 #include "ShadowRoot.h"
53 #include "StyleResolveForDocument.h"
54 #include "StyleResolver.h"
55 #include "Text.h"
56
57 #if PLATFORM(IOS)
58 #include "CSSFontSelector.h"
59 #include "WKContentObservation.h"
60 #endif
61
62 namespace WebCore {
63
64 namespace Style {
65
66 enum DetachType { NormalDetach, ReattachDetach };
67
68 static void attachRenderTree(Element&, RenderStyle& inheritedStyle, RenderTreePosition&, PassRefPtr<RenderStyle>);
69 static void attachTextRenderer(Text&, RenderTreePosition&);
70 static void detachRenderTree(Element&, DetachType);
71 static void resolveTextNode(Text&, RenderTreePosition&);
72 static void resolveTree(Element&, RenderStyle& inheritedStyle, RenderTreePosition&, Change);
73
74 Change determineChange(const RenderStyle& s1, const RenderStyle& s2)
75 {
76     if (s1.display() != s2.display())
77         return Detach;
78     if (s1.hasPseudoStyle(FIRST_LETTER) != s2.hasPseudoStyle(FIRST_LETTER))
79         return Detach;
80     // We just detach if a renderer acquires or loses a column-span, since spanning elements
81     // typically won't contain much content.
82     if (s1.columnSpan() != s2.columnSpan())
83         return Detach;
84     if (!s1.contentDataEquivalent(&s2))
85         return Detach;
86     // When text-combine property has been changed, we need to prepare a separate renderer object.
87     // When text-combine is on, we use RenderCombineText, otherwise RenderText.
88     // https://bugs.webkit.org/show_bug.cgi?id=55069
89     if (s1.hasTextCombine() != s2.hasTextCombine())
90         return Detach;
91     // We need to reattach the node, so that it is moved to the correct RenderFlowThread.
92     if (s1.flowThread() != s2.flowThread())
93         return Detach;
94     // When the region thread has changed, we need to prepare a separate render region object.
95     if (s1.regionThread() != s2.regionThread())
96         return Detach;
97     // FIXME: Multicolumn regions not yet supported (http://dev.w3.org/csswg/css-regions/#multi-column-regions)
98     // When the node has region style and changed its multicol style, we have to prepare
99     // a separate render region object.
100     if (s1.hasFlowFrom() && (s1.specifiesColumns() != s2.specifiesColumns()))
101         return Detach;
102
103     if (s1 != s2) {
104         if (s1.inheritedNotEqual(&s2))
105             return Inherit;
106         if (s1.hasExplicitlyInheritedProperties() || s2.hasExplicitlyInheritedProperties())
107             return Inherit;
108
109         return NoInherit;
110     }
111     // If the pseudoStyles have changed, we want any StyleChange that is not NoChange
112     // because setStyle will do the right thing with anything else.
113     if (s1.hasAnyPublicPseudoStyles()) {
114         for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < FIRST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) {
115             if (s1.hasPseudoStyle(pseudoId)) {
116                 RenderStyle* ps2 = s2.getCachedPseudoStyle(pseudoId);
117                 if (!ps2)
118                     return NoInherit;
119                 RenderStyle* ps1 = s1.getCachedPseudoStyle(pseudoId);
120                 if (!ps1 || *ps1 != *ps2)
121                     return NoInherit;
122             }
123         }
124     }
125
126     return NoChange;
127 }
128
129 static bool shouldCreateRenderer(const Element& element, const RenderElement& parentRenderer)
130 {
131     if (!element.document().shouldCreateRenderers())
132         return false;
133     if (!parentRenderer.canHaveChildren() && !(element.isPseudoElement() && parentRenderer.canHaveGeneratedChildren()))
134         return false;
135     if (parentRenderer.element() && !parentRenderer.element()->childShouldCreateRenderer(element))
136         return false;
137     return true;
138 }
139
140 static Ref<RenderStyle> styleForElement(Element& element, RenderStyle& inheritedStyle)
141 {
142     if (element.hasCustomStyleResolveCallbacks()) {
143         if (RefPtr<RenderStyle> style = element.customStyleForRenderer(inheritedStyle))
144             return style.releaseNonNull();
145     }
146     return element.resolveStyle(&inheritedStyle);
147 }
148
149 #if ENABLE(CSS_REGIONS)
150 static RenderNamedFlowThread* moveToFlowThreadIfNeeded(Element& element, const RenderStyle& style)
151 {
152     if (!element.shouldMoveToFlowThread(style))
153         return 0;
154
155     FlowThreadController& flowThreadController = element.document().renderView()->flowThreadController();
156     RenderNamedFlowThread& parentFlowRenderer = flowThreadController.ensureRenderFlowThreadWithName(style.flowThread());
157     flowThreadController.registerNamedFlowContentElement(element, parentFlowRenderer);
158     return &parentFlowRenderer;
159 }
160 #endif
161
162 static void createRendererIfNeeded(Element& element, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, PassRefPtr<RenderStyle> resolvedStyle)
163 {
164     ASSERT(!element.renderer());
165
166     RefPtr<RenderStyle> style = resolvedStyle;
167
168     if (!shouldCreateRenderer(element, renderTreePosition.parent()))
169         return;
170
171     if (!style)
172         style = styleForElement(element, inheritedStyle);
173
174     RenderNamedFlowThread* parentFlowRenderer = 0;
175 #if ENABLE(CSS_REGIONS)
176     parentFlowRenderer = moveToFlowThreadIfNeeded(element, *style);
177 #endif
178
179     if (!element.rendererIsNeeded(*style))
180         return;
181
182     renderTreePosition.computeNextSibling(element);
183
184     RenderTreePosition insertionPosition = parentFlowRenderer
185         ? RenderTreePosition(*parentFlowRenderer, parentFlowRenderer->nextRendererForElement(element))
186         : renderTreePosition;
187
188     RenderElement* newRenderer = element.createElementRenderer(style.releaseNonNull(), insertionPosition).leakPtr();
189     if (!newRenderer)
190         return;
191     if (!insertionPosition.canInsert(*newRenderer)) {
192         newRenderer->destroy();
193         return;
194     }
195
196     // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
197     // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
198     newRenderer->setFlowThreadState(insertionPosition.parent().flowThreadState());
199
200     // Code below updateAnimations() can depend on Element::renderer() already being set.
201     element.setRenderer(newRenderer);
202
203     // FIXME: There's probably a better way to factor this.
204     // This just does what setAnimatedStyle() does, except with setStyleInternal() instead of setStyle().
205     Ref<RenderStyle> animatedStyle = newRenderer->style();
206     newRenderer->animation().updateAnimations(*newRenderer, animatedStyle, animatedStyle);
207     newRenderer->setStyleInternal(WTF::move(animatedStyle));
208
209     newRenderer->initializeStyle();
210
211 #if ENABLE(FULLSCREEN_API)
212     Document& document = element.document();
213     if (document.webkitIsFullScreen() && document.webkitCurrentFullScreenElement() == &element) {
214         newRenderer = RenderFullScreen::wrapRenderer(newRenderer, &insertionPosition.parent(), document);
215         if (!newRenderer)
216             return;
217     }
218 #endif
219     // Note: Adding newRenderer instead of renderer(). renderer() may be a child of newRenderer.
220     insertionPosition.insert(*newRenderer);
221 }
222
223 static void invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(Node& current)
224 {
225     if (is<InsertionPoint>(current))
226         return;
227     // This function finds sibling text renderers where the results of textRendererIsNeeded may have changed as a result of
228     // the current node gaining or losing the renderer. This can only affect white space text nodes.
229     for (Node* sibling = current.nextSibling(); sibling; sibling = sibling->nextSibling()) {
230         if (sibling->needsStyleRecalc())
231             return;
232         if (is<Element>(*sibling)) {
233             // Text renderers beyond rendered elements can't be affected.
234             if (!sibling->renderer() || RenderTreePosition::isRendererReparented(*sibling->renderer()))
235                 continue;
236             return;
237         }
238         if (!is<Text>(*sibling))
239             continue;
240         Text& textSibling = downcast<Text>(*sibling);
241         if (!textSibling.containsOnlyWhitespace())
242             continue;
243         textSibling.setNeedsStyleRecalc();
244     }
245 }
246
247 static bool textRendererIsNeeded(const Text& textNode, const RenderTreePosition& renderTreePosition)
248 {
249     const RenderElement& parentRenderer = renderTreePosition.parent();
250     if (!parentRenderer.canHaveChildren())
251         return false;
252     if (parentRenderer.element() && !parentRenderer.element()->childShouldCreateRenderer(textNode))
253         return false;
254     if (textNode.isEditingText())
255         return true;
256     if (!textNode.length())
257         return false;
258     if (!textNode.containsOnlyWhitespace())
259         return true;
260     // This text node has nothing but white space. We may still need a renderer in some cases.
261     if (parentRenderer.isTable() || parentRenderer.isTableRow() || parentRenderer.isTableSection() || parentRenderer.isRenderTableCol() || parentRenderer.isFrameSet())
262         return false;
263     if (parentRenderer.style().preserveNewline()) // pre/pre-wrap/pre-line always make renderers.
264         return true;
265
266     RenderObject* previousRenderer = RenderTreePosition::previousSiblingRenderer(textNode);
267     if (previousRenderer && previousRenderer->isBR()) // <span><br/> <br/></span>
268         return false;
269         
270     if (parentRenderer.isRenderInline()) {
271         // <span><div/> <div/></span>
272         if (previousRenderer && !previousRenderer->isInline())
273             return false;
274     } else {
275         if (parentRenderer.isRenderBlock() && !parentRenderer.childrenInline() && (!previousRenderer || !previousRenderer->isInline()))
276             return false;
277         
278         RenderObject* first = parentRenderer.firstChild();
279         while (first && first->isFloatingOrOutOfFlowPositioned())
280             first = first->nextSibling();
281         RenderObject* nextRenderer = RenderTreePosition::nextSiblingRenderer(textNode, parentRenderer);
282         if (!first || nextRenderer == first) {
283             // Whitespace at the start of a block just goes away. Don't even make a render object for this text.
284             return false;
285         }
286     }
287     return true;
288 }
289
290 static void createTextRendererIfNeeded(Text& textNode, RenderTreePosition& renderTreePosition)
291 {
292     ASSERT(!textNode.renderer());
293
294     if (!textRendererIsNeeded(textNode, renderTreePosition))
295         return;
296
297     auto newRenderer = textNode.createTextRenderer(renderTreePosition.parent().style());
298     ASSERT(newRenderer);
299
300     renderTreePosition.computeNextSibling(textNode);
301
302     if (!renderTreePosition.canInsert(*newRenderer))
303         return;
304
305     // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
306     // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
307     newRenderer->setFlowThreadState(renderTreePosition.parent().flowThreadState());
308
309     textNode.setRenderer(newRenderer.get());
310     // Parent takes care of the animations, no need to call setAnimatableStyle.
311     renderTreePosition.insert(*newRenderer.leakPtr());
312 }
313
314 void attachTextRenderer(Text& textNode, RenderTreePosition& renderTreePosition)
315 {
316     createTextRendererIfNeeded(textNode, renderTreePosition);
317
318     textNode.clearNeedsStyleRecalc();
319 }
320
321 void detachTextRenderer(Text& textNode)
322 {
323     if (textNode.renderer())
324         textNode.renderer()->destroyAndCleanupAnonymousWrappers();
325     textNode.setRenderer(0);
326 }
327
328 void updateTextRendererAfterContentChange(Text& textNode, unsigned offsetOfReplacedData, unsigned lengthOfReplacedData)
329 {
330     ContainerNode* renderingParentNode = NodeRenderingTraversal::parent(&textNode);
331     if (!renderingParentNode || !renderingParentNode->renderer())
332         return;
333
334     bool hadRenderer = textNode.renderer();
335
336     RenderTreePosition renderTreePosition(*renderingParentNode->renderer());
337     resolveTextNode(textNode, renderTreePosition);
338
339     if (hadRenderer && textNode.renderer())
340         textNode.renderer()->setTextWithOffset(textNode.data(), offsetOfReplacedData, lengthOfReplacedData);
341 }
342
343 static void attachChildren(ContainerNode& current, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition)
344 {
345     for (Node* child = current.firstChild(); child; child = child->nextSibling()) {
346         ASSERT((!child->renderer() || child->isNamedFlowContentNode()) || current.shadowRoot());
347         if (child->renderer()) {
348             renderTreePosition.invalidateNextSibling(*child->renderer());
349             continue;
350         }
351         if (is<Text>(*child)) {
352             attachTextRenderer(downcast<Text>(*child), renderTreePosition);
353             continue;
354         }
355         if (is<Element>(*child))
356             attachRenderTree(downcast<Element>(*child), inheritedStyle, renderTreePosition, nullptr);
357     }
358 }
359
360 static void attachDistributedChildren(InsertionPoint& insertionPoint, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition)
361 {
362     if (ShadowRoot* shadowRoot = insertionPoint.containingShadowRoot())
363         ContentDistributor::ensureDistribution(shadowRoot);
364
365     for (Node* current = insertionPoint.firstDistributed(); current; current = insertionPoint.nextDistributedTo(current)) {
366         if (current->renderer())
367             renderTreePosition.invalidateNextSibling(*current->renderer());
368         if (is<Text>(*current)) {
369             if (current->renderer())
370                 continue;
371             attachTextRenderer(downcast<Text>(*current), renderTreePosition);
372             continue;
373         }
374         if (is<Element>(*current)) {
375             Element& currentElement = downcast<Element>(*current);
376             if (currentElement.renderer())
377                 detachRenderTree(currentElement);
378             attachRenderTree(currentElement, inheritedStyle, renderTreePosition, nullptr);
379         }
380     }
381     // Use actual children as fallback content.
382     if (!insertionPoint.hasDistribution())
383         attachChildren(insertionPoint, inheritedStyle, renderTreePosition);
384 }
385
386 static void attachShadowRoot(ShadowRoot& shadowRoot)
387 {
388     ASSERT(shadowRoot.host());
389     ASSERT(shadowRoot.host()->renderer());
390
391     auto& renderer = *shadowRoot.host()->renderer();
392     RenderTreePosition renderTreePosition(renderer);
393     attachChildren(shadowRoot, renderer.style(), renderTreePosition);
394
395     shadowRoot.clearNeedsStyleRecalc();
396     shadowRoot.clearChildNeedsStyleRecalc();
397 }
398
399 static PseudoElement* beforeOrAfterPseudoElement(Element& current, PseudoId pseudoId)
400 {
401     ASSERT(pseudoId == BEFORE || pseudoId == AFTER);
402     if (pseudoId == BEFORE)
403         return current.beforePseudoElement();
404     return current.afterPseudoElement();
405 }
406
407 static void setBeforeOrAfterPseudoElement(Element& current, Ref<PseudoElement>&& pseudoElement, PseudoId pseudoId)
408 {
409     ASSERT(pseudoId == BEFORE || pseudoId == AFTER);
410     if (pseudoId == BEFORE) {
411         current.setBeforePseudoElement(WTF::move(pseudoElement));
412         return;
413     }
414     current.setAfterPseudoElement(WTF::move(pseudoElement));
415 }
416
417 static void clearBeforeOrAfterPseudoElement(Element& current, PseudoId pseudoId)
418 {
419     ASSERT(pseudoId == BEFORE || pseudoId == AFTER);
420     if (pseudoId == BEFORE) {
421         current.clearBeforePseudoElement();
422         return;
423     }
424     current.clearAfterPseudoElement();
425 }
426
427 static void resetStyleForNonRenderedDescendants(Element& current)
428 {
429     ASSERT(!current.renderer());
430     bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle = false;
431     for (auto& child : childrenOfType<Element>(current)) {
432         ASSERT(!child.renderer());
433         if (elementNeedingStyleRecalcAffectsNextSiblingElementStyle) {
434             if (child.styleIsAffectedByPreviousSibling())
435                 child.setNeedsStyleRecalc();
436             elementNeedingStyleRecalcAffectsNextSiblingElementStyle = child.affectsNextSiblingElementStyle();
437         }
438
439         if (child.needsStyleRecalc()) {
440             child.resetComputedStyle();
441             child.clearNeedsStyleRecalc();
442             elementNeedingStyleRecalcAffectsNextSiblingElementStyle = child.affectsNextSiblingElementStyle();
443         }
444
445         if (child.childNeedsStyleRecalc()) {
446             resetStyleForNonRenderedDescendants(child);
447             child.clearChildNeedsStyleRecalc();
448         }
449     }
450 }
451
452 static bool needsPseudoElement(Element& current, PseudoId pseudoId)
453 {
454     if (!current.renderer() || !current.renderer()->canHaveGeneratedChildren())
455         return false;
456     if (current.isPseudoElement())
457         return false;
458     if (!pseudoElementRendererIsNeeded(current.renderer()->getCachedPseudoStyle(pseudoId)))
459         return false;
460     return true;
461 }
462
463 static void attachBeforeOrAfterPseudoElementIfNeeded(Element& current, PseudoId pseudoId, RenderTreePosition& renderTreePosition)
464 {
465     if (!needsPseudoElement(current, pseudoId))
466         return;
467     Ref<PseudoElement> pseudoElement = PseudoElement::create(current, pseudoId);
468     InspectorInstrumentation::pseudoElementCreated(pseudoElement->document().page(), pseudoElement.get());
469     setBeforeOrAfterPseudoElement(current, pseudoElement.copyRef(), pseudoId);
470     attachRenderTree(pseudoElement.get(), *current.renderStyle(), renderTreePosition, nullptr);
471 }
472
473 #if ENABLE(SHADOW_DOM)
474 static void attachSlotAssignees(HTMLSlotElement& slot, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition)
475 {
476     if (auto* assignedNodes = slot.assignedNodes()) {
477         for (auto* child : *assignedNodes) {
478             if (is<Text>(*child))
479                 attachTextRenderer(downcast<Text>(*child), renderTreePosition);
480             else if (is<Element>(*child))
481                 attachRenderTree(downcast<Element>(*child), inheritedStyle, renderTreePosition, nullptr);
482         }
483     } else {
484         for (Node* child = slot.firstChild(); child; child = child->nextSibling()) {
485             if (is<Text>(*child))
486                 attachTextRenderer(downcast<Text>(*child), renderTreePosition);
487             else if (is<Element>(*child))
488                 attachRenderTree(downcast<Element>(*child), inheritedStyle, renderTreePosition, nullptr);
489         }
490     }
491     slot.clearNeedsStyleRecalc();
492     slot.clearChildNeedsStyleRecalc();
493 }
494 #endif
495
496 static void attachRenderTree(Element& current, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, PassRefPtr<RenderStyle> resolvedStyle)
497 {
498     PostResolutionCallbackDisabler callbackDisabler(current.document());
499     WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
500
501 #if ENABLE(SHADOW_DOM)
502     if (is<HTMLSlotElement>(current)) {
503         attachSlotAssignees(downcast<HTMLSlotElement>(current), inheritedStyle, renderTreePosition);
504         return;
505     }
506 #endif
507     if (is<InsertionPoint>(current)) {
508         attachDistributedChildren(downcast<InsertionPoint>(current), inheritedStyle, renderTreePosition);
509         current.clearNeedsStyleRecalc();
510         current.clearChildNeedsStyleRecalc();
511         return;
512     }
513
514     if (current.hasCustomStyleResolveCallbacks())
515         current.willAttachRenderers();
516
517     createRendererIfNeeded(current, inheritedStyle, renderTreePosition, resolvedStyle);
518
519     if (auto* renderer = current.renderer()) {
520         StyleResolverParentPusher parentPusher(&current);
521
522         RenderTreePosition childRenderTreePosition(*renderer);
523         attachBeforeOrAfterPseudoElementIfNeeded(current, BEFORE, childRenderTreePosition);
524
525         auto* shadowRoot = current.shadowRoot();
526         if (shadowRoot) {
527             parentPusher.push();
528             attachShadowRoot(*shadowRoot);
529         } else if (current.firstChild())
530             parentPusher.push();
531
532         bool skipChildren = shadowRoot && shadowRoot->type() != ShadowRoot::Type::UserAgent;
533         if (!skipChildren)
534             attachChildren(current, renderer->style(), childRenderTreePosition);
535
536         if (AXObjectCache* cache = current.document().axObjectCache())
537             cache->updateCacheAfterNodeIsAttached(&current);
538
539         attachBeforeOrAfterPseudoElementIfNeeded(current, AFTER, childRenderTreePosition);
540
541         current.updateFocusAppearanceAfterAttachIfNeeded();
542     } else
543         resetStyleForNonRenderedDescendants(current);
544
545     current.clearNeedsStyleRecalc();
546     current.clearChildNeedsStyleRecalc();
547
548     if (current.hasCustomStyleResolveCallbacks())
549         current.didAttachRenderers();
550 }
551
552 static void detachDistributedChildren(InsertionPoint& insertionPoint)
553 {
554     for (Node* current = insertionPoint.firstDistributed(); current; current = insertionPoint.nextDistributedTo(current)) {
555         if (is<Text>(*current)) {
556             detachTextRenderer(downcast<Text>(*current));
557             continue;
558         }
559         if (is<Element>(*current))
560             detachRenderTree(downcast<Element>(*current));
561     }
562 }
563
564 static void detachChildren(ContainerNode& current, DetachType detachType)
565 {
566     for (Node* child = current.firstChild(); child; child = child->nextSibling()) {
567         if (is<Text>(*child))
568             detachTextRenderer(downcast<Text>(*child));
569         else if (is<Element>(*child))
570             detachRenderTree(downcast<Element>(*child), detachType);
571     }
572     current.clearChildNeedsStyleRecalc();
573 }
574
575 static void detachShadowRoot(ShadowRoot& shadowRoot, DetachType detachType)
576 {
577     detachChildren(shadowRoot, detachType);
578 }
579
580 #if ENABLE(SHADOW_DOM)
581 static void detachSlotAssignees(HTMLSlotElement& slot, DetachType detachType)
582 {
583     ASSERT(!slot.renderer());
584     if (auto* assignedNodes = slot.assignedNodes()) {
585         for (auto* child : *assignedNodes) {
586             if (is<Text>(*child))
587                 detachTextRenderer(downcast<Text>(*child));
588             else if (is<Element>(*child))
589                 detachRenderTree(downcast<Element>(*child), detachType);
590         }
591     } else {
592         for (Node* child = slot.firstChild(); child; child = child->nextSibling()) {
593             if (is<Text>(*child))
594                 detachTextRenderer(downcast<Text>(*child));
595             else if (is<Element>(*child))
596                 detachRenderTree(downcast<Element>(*child), detachType);
597         }
598     }
599     slot.clearNeedsStyleRecalc();
600     slot.clearChildNeedsStyleRecalc();
601 }
602 #endif
603
604 static void detachRenderTree(Element& current, DetachType detachType)
605 {
606     WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
607
608     if (current.hasCustomStyleResolveCallbacks())
609         current.willDetachRenderers();
610
611     current.clearStyleDerivedDataBeforeDetachingRenderer();
612
613     // Do not remove the element's hovered and active status
614     // if performing a reattach.
615     if (detachType != ReattachDetach)
616         current.clearHoverAndActiveStatusBeforeDetachingRenderer();
617
618     if (is<InsertionPoint>(current))
619         detachDistributedChildren(downcast<InsertionPoint>(current));
620 #if ENABLE(SHADOW_DOM)
621     else 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(0);
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 static Change resolveLocal(Element& current, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, Change inheritedChange)
671 {
672     Change localChange = Detach;
673     RefPtr<RenderStyle> newStyle;
674     RefPtr<RenderStyle> currentStyle = current.renderStyle();
675
676     Document& document = current.document();
677     if (currentStyle && current.styleChangeType() != ReconstructRenderTree) {
678         Ref<RenderStyle> style(styleForElement(current, inheritedStyle));
679         newStyle = style.ptr();
680         localChange = determineChange(*currentStyle, style);
681     }
682     if (localChange == Detach) {
683         if (current.renderer() || current.isNamedFlowContentNode())
684             detachRenderTree(current, ReattachDetach);
685         attachRenderTree(current, inheritedStyle, 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()) || (inheritedChange == 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 (document.authorStyleSheets().usesRemUnits() && document.documentElement() == &current && localChange != NoChange && currentStyle && newStyle && currentStyle->fontSize() != newStyle->fontSize()) {
704         // Cached RenderStyles may depend on the re units.
705         if (StyleResolver* styleResolver = document.styleResolverIfExists())
706             styleResolver->invalidateMatchedPropertiesCache();
707         return Force;
708     }
709     if (inheritedChange == Force)
710         return Force;
711     if (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 static void resolveShadowTree(ShadowRoot& shadowRoot, Element& host, Style::Change change)
737 {
738     StyleResolverParentPusher parentPusher(&host);
739
740     ASSERT(shadowRoot.host() == &host);
741     ASSERT(host.renderer());
742     if (shadowRoot.styleChangeType() >= FullStyleChange)
743         change = Force;
744     RenderTreePosition renderTreePosition(*host.renderer());
745     for (Node* child = shadowRoot.firstChild(); child; child = child->nextSibling()) {
746         if (child->renderer())
747             renderTreePosition.invalidateNextSibling(*child->renderer());
748         if (is<Text>(*child) && child->needsStyleRecalc()) {
749             resolveTextNode(downcast<Text>(*child), renderTreePosition);
750             continue;
751         }
752         if (is<Element>(*child)) {
753             parentPusher.push();
754             resolveTree(downcast<Element>(*child), host.renderer()->style(), renderTreePosition, change);
755         }
756     }
757
758     shadowRoot.clearNeedsStyleRecalc();
759     shadowRoot.clearChildNeedsStyleRecalc();
760 }
761
762 static void updateBeforeOrAfterPseudoElement(Element& current, Change change, PseudoId pseudoId, RenderTreePosition& renderTreePosition)
763 {
764     ASSERT(current.renderer());
765     if (PseudoElement* existingPseudoElement = beforeOrAfterPseudoElement(current, pseudoId)) {
766         if (existingPseudoElement->renderer())
767             renderTreePosition.invalidateNextSibling(*existingPseudoElement->renderer());
768
769         if (needsPseudoElement(current, pseudoId))
770             resolveTree(*existingPseudoElement, current.renderer()->style(), renderTreePosition, current.needsStyleRecalc() ? Force : change);
771         else
772             clearBeforeOrAfterPseudoElement(current, pseudoId);
773         return;
774     }
775     attachBeforeOrAfterPseudoElementIfNeeded(current, pseudoId, renderTreePosition);
776 }
777
778 #if PLATFORM(IOS)
779 static EVisibility elementImplicitVisibility(const Element* element)
780 {
781     RenderObject* renderer = element->renderer();
782     if (!renderer)
783         return VISIBLE;
784
785     RenderStyle& style = renderer->style();
786
787     Length width(style.width());
788     Length height(style.height());
789     if ((width.isFixed() && width.value() <= 0) || (height.isFixed() && height.value() <= 0))
790         return HIDDEN;
791
792     Length top(style.top());
793     Length left(style.left());
794     if (left.isFixed() && width.isFixed() && -left.value() >= width.value())
795         return HIDDEN;
796
797     if (top.isFixed() && height.isFixed() && -top.value() >= height.value())
798         return HIDDEN;
799     return VISIBLE;
800 }
801
802 class CheckForVisibilityChangeOnRecalcStyle {
803 public:
804     CheckForVisibilityChangeOnRecalcStyle(Element* element, RenderStyle* currentStyle)
805         : m_element(element)
806         , m_previousDisplay(currentStyle ? currentStyle->display() : NONE)
807         , m_previousVisibility(currentStyle ? currentStyle->visibility() : HIDDEN)
808         , m_previousImplicitVisibility(WKObservingContentChanges() && WKContentChange() != WKContentVisibilityChange ? elementImplicitVisibility(element) : VISIBLE)
809     {
810     }
811     ~CheckForVisibilityChangeOnRecalcStyle()
812     {
813         if (!WKObservingContentChanges())
814             return;
815         RenderStyle* style = m_element->renderStyle();
816         if (!style)
817             return;
818         if ((m_previousDisplay == NONE && style->display() != NONE) || (m_previousVisibility == HIDDEN && style->visibility() != HIDDEN)
819             || (m_previousImplicitVisibility == HIDDEN && elementImplicitVisibility(m_element.get()) == VISIBLE))
820             WKSetObservedContentChange(WKContentVisibilityChange);
821     }
822 private:
823     RefPtr<Element> m_element;
824     EDisplay m_previousDisplay;
825     EVisibility m_previousVisibility;
826     EVisibility m_previousImplicitVisibility;
827 };
828 #endif // PLATFORM(IOS)
829
830 static void resolveChildren(Element& current, RenderStyle& inheritedStyle, Change change, RenderTreePosition& childRenderTreePosition)
831 {
832     StyleResolverParentPusher parentPusher(&current);
833
834     bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle = false;
835     for (Node* child = current.firstChild(); child; child = child->nextSibling()) {
836         if (RenderObject* childRenderer = child->renderer())
837             childRenderTreePosition.invalidateNextSibling(*childRenderer);
838         if (is<Text>(*child) && child->needsStyleRecalc()) {
839             resolveTextNode(downcast<Text>(*child), childRenderTreePosition);
840             continue;
841         }
842         if (!is<Element>(*child))
843             continue;
844
845         Element& childElement = downcast<Element>(*child);
846         if (elementNeedingStyleRecalcAffectsNextSiblingElementStyle) {
847             if (childElement.styleIsAffectedByPreviousSibling())
848                 childElement.setNeedsStyleRecalc();
849             elementNeedingStyleRecalcAffectsNextSiblingElementStyle = childElement.affectsNextSiblingElementStyle();
850         } else if (childElement.needsStyleRecalc())
851             elementNeedingStyleRecalcAffectsNextSiblingElementStyle = childElement.affectsNextSiblingElementStyle();
852         if (change >= Inherit || childElement.childNeedsStyleRecalc() || childElement.needsStyleRecalc()) {
853             parentPusher.push();
854             resolveTree(childElement, inheritedStyle, childRenderTreePosition, change);
855         }
856     }
857 }
858
859 #if ENABLE(SHADOW_DOM)
860 static void resolveSlotAssignees(HTMLSlotElement& slot, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, Change change)
861 {
862     if (auto* assignedNodes = slot.assignedNodes()) {
863         for (auto* child : *assignedNodes) {
864             if (is<Text>(*child))
865                 resolveTextNode(downcast<Text>(*child), renderTreePosition);
866             else if (is<Element>(*child))
867                 resolveTree(downcast<Element>(*child), inheritedStyle, renderTreePosition, change);
868         }
869     } else {
870         for (Node* child = slot.firstChild(); child; child = child->nextSibling()) {
871             if (is<Text>(*child))
872                 resolveTextNode(downcast<Text>(*child), renderTreePosition);
873             else if (is<Element>(*child))
874                 resolveTree(downcast<Element>(*child), inheritedStyle, renderTreePosition, change);
875         }
876     }
877     slot.clearNeedsStyleRecalc();
878     slot.clearChildNeedsStyleRecalc();
879 }
880 #endif
881
882 void resolveTree(Element& current, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, Change change)
883 {
884     ASSERT(change != Detach);
885
886 #if ENABLE(SHADOW_DOM)
887     if (is<HTMLSlotElement>(current)) {
888         resolveSlotAssignees(downcast<HTMLSlotElement>(current), inheritedStyle, renderTreePosition, change);
889         return;
890     }
891 #endif
892     if (is<InsertionPoint>(current)) {
893         current.clearNeedsStyleRecalc();
894         current.clearChildNeedsStyleRecalc();
895         return;
896     }
897
898     if (current.hasCustomStyleResolveCallbacks()) {
899         if (!current.willRecalcStyle(change))
900             return;
901     }
902
903 #if PLATFORM(IOS)
904     CheckForVisibilityChangeOnRecalcStyle checkForVisibilityChange(&current, current.renderStyle());
905 #endif
906
907     if (change > NoChange || current.needsStyleRecalc())
908         current.resetComputedStyle();
909
910     if (change >= Inherit || current.needsStyleRecalc())
911         change = resolveLocal(current, inheritedStyle, renderTreePosition, change);
912
913     auto* renderer = current.renderer();
914
915     if (change != Detach && renderer) {
916         auto* shadowRoot = current.shadowRoot();
917         if (shadowRoot && (change >= Inherit || shadowRoot->childNeedsStyleRecalc() || shadowRoot->needsStyleRecalc()))
918             resolveShadowTree(*shadowRoot, current, change);
919
920         RenderTreePosition childRenderTreePosition(*renderer);
921         updateBeforeOrAfterPseudoElement(current, change, BEFORE, childRenderTreePosition);
922
923         bool skipChildren = shadowRoot && shadowRoot->type() != ShadowRoot::Type::UserAgent;
924         if (!skipChildren)
925             resolveChildren(current, renderer->style(), change, childRenderTreePosition);
926
927         updateBeforeOrAfterPseudoElement(current, change, AFTER, childRenderTreePosition);
928     }
929     if (change != Detach && !renderer)
930         resetStyleForNonRenderedDescendants(current);
931
932     current.clearNeedsStyleRecalc();
933     current.clearChildNeedsStyleRecalc();
934     
935     if (current.hasCustomStyleResolveCallbacks())
936         current.didRecalcStyle(change);
937 }
938
939 void resolveTree(Document& document, Change change)
940 {
941     auto& renderView = *document.renderView();
942
943     if (change == Force) {
944         auto documentStyle = resolveForDocument(document);
945
946         // Inserting the pictograph font at the end of the font fallback list is done by the
947         // font selector, so set a font selector if needed.
948         if (Settings* settings = document.settings()) {
949             if (settings->fontFallbackPrefersPictographs())
950                 documentStyle.get().fontCascade().update(&document.fontSelector());
951         }
952
953         Style::Change documentChange = determineChange(documentStyle.get(), renderView.style());
954         if (documentChange != NoChange)
955             renderView.setStyle(WTF::move(documentStyle));
956     }
957
958     Element* documentElement = document.documentElement();
959     if (!documentElement)
960         return;
961     if (change < Inherit && !documentElement->childNeedsStyleRecalc() && !documentElement->needsStyleRecalc())
962         return;
963
964     auto& styleResolved = document.ensureStyleResolver();
965
966     // Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc.
967     renderView.setUsesFirstLineRules(renderView.usesFirstLineRules() || styleResolved.usesFirstLineRules());
968     renderView.setUsesFirstLetterRules(renderView.usesFirstLetterRules() || styleResolved.usesFirstLetterRules());
969
970     RenderTreePosition renderTreePosition(renderView);
971     resolveTree(*documentElement, *document.renderStyle(), renderTreePosition, change);
972
973     renderView.setUsesFirstLineRules(styleResolved.usesFirstLineRules());
974     renderView.setUsesFirstLetterRules(styleResolved.usesFirstLetterRules());
975 }
976
977 void detachRenderTree(Element& element)
978 {
979     detachRenderTree(element, NormalDetach);
980 }
981
982 static Vector<std::function<void ()>>& postResolutionCallbackQueue()
983 {
984     static NeverDestroyed<Vector<std::function<void ()>>> vector;
985     return vector;
986 }
987
988 void queuePostResolutionCallback(std::function<void ()> callback)
989 {
990     postResolutionCallbackQueue().append(callback);
991 }
992
993 static void suspendMemoryCacheClientCalls(Document& document)
994 {
995     Page* page = document.page();
996     if (!page || !page->areMemoryCacheClientCallsEnabled())
997         return;
998
999     page->setMemoryCacheClientCallsEnabled(false);
1000
1001     RefPtr<MainFrame> protectedMainFrame = &page->mainFrame();
1002     postResolutionCallbackQueue().append([protectedMainFrame]{
1003         if (Page* page = protectedMainFrame->page())
1004             page->setMemoryCacheClientCallsEnabled(true);
1005     });
1006 }
1007
1008 static unsigned resolutionNestingDepth;
1009
1010 PostResolutionCallbackDisabler::PostResolutionCallbackDisabler(Document& document)
1011 {
1012     ++resolutionNestingDepth;
1013
1014     if (resolutionNestingDepth == 1)
1015         platformStrategies()->loaderStrategy()->resourceLoadScheduler()->suspendPendingRequests();
1016
1017     // FIXME: It's strange to build this into the disabler.
1018     suspendMemoryCacheClientCalls(document);
1019 }
1020
1021 PostResolutionCallbackDisabler::~PostResolutionCallbackDisabler()
1022 {
1023     if (resolutionNestingDepth == 1) {
1024         // Get size each time through the loop because a callback can add more callbacks to the end of the queue.
1025         auto& queue = postResolutionCallbackQueue();
1026         for (size_t i = 0; i < queue.size(); ++i)
1027             queue[i]();
1028         queue.clear();
1029
1030         platformStrategies()->loaderStrategy()->resourceLoadScheduler()->resumePendingRequests();
1031     }
1032
1033     --resolutionNestingDepth;
1034 }
1035
1036 bool postResolutionCallbacksAreSuspended()
1037 {
1038     return resolutionNestingDepth;
1039 }
1040
1041 }
1042 }