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