Eliminate styleDidChange with StyleDifferenceEqual when updates are actually necessary
[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 "CSSFontSelector.h"
32 #include "ElementIterator.h"
33 #include "ElementRareData.h"
34 #include "FlowThreadController.h"
35 #include "InsertionPoint.h"
36 #include "LoaderStrategy.h"
37 #include "MainFrame.h"
38 #include "NodeRenderStyle.h"
39 #include "NodeRenderingTraversal.h"
40 #include "NodeTraversal.h"
41 #include "PlatformStrategies.h"
42 #include "RenderFullScreen.h"
43 #include "RenderNamedFlowThread.h"
44 #include "RenderText.h"
45 #include "RenderTreePosition.h"
46 #include "RenderWidget.h"
47 #include "ResourceLoadScheduler.h"
48 #include "Settings.h"
49 #include "ShadowRoot.h"
50 #include "StyleResolveForDocument.h"
51 #include "StyleResolver.h"
52 #include "Text.h"
53
54 #if PLATFORM(IOS)
55 #include "CSSFontSelector.h"
56 #include "WKContentObservation.h"
57 #endif
58
59 namespace WebCore {
60
61 namespace Style {
62
63 enum DetachType { NormalDetach, ReattachDetach };
64
65 static void attachRenderTree(Element&, RenderStyle& inheritedStyle, RenderTreePosition&, PassRefPtr<RenderStyle>);
66 static void attachTextRenderer(Text&, RenderTreePosition&);
67 static void detachRenderTree(Element&, DetachType);
68 static void resolveTextNode(Text&, RenderTreePosition&);
69 static void resolveTree(Element&, RenderStyle& inheritedStyle, RenderTreePosition&, Change);
70
71 Change determineChange(const RenderStyle& s1, const RenderStyle& s2)
72 {
73     if (s1.display() != s2.display())
74         return Detach;
75     if (s1.hasPseudoStyle(FIRST_LETTER) != s2.hasPseudoStyle(FIRST_LETTER))
76         return Detach;
77     // We just detach if a renderer acquires or loses a column-span, since spanning elements
78     // typically won't contain much content.
79     if (s1.columnSpan() != s2.columnSpan())
80         return Detach;
81     if (!s1.contentDataEquivalent(&s2))
82         return Detach;
83     // When text-combine property has been changed, we need to prepare a separate renderer object.
84     // When text-combine is on, we use RenderCombineText, otherwise RenderText.
85     // https://bugs.webkit.org/show_bug.cgi?id=55069
86     if (s1.hasTextCombine() != s2.hasTextCombine())
87         return Detach;
88     // We need to reattach the node, so that it is moved to the correct RenderFlowThread.
89     if (s1.flowThread() != s2.flowThread())
90         return Detach;
91     // When the region thread has changed, we need to prepare a separate render region object.
92     if (s1.regionThread() != s2.regionThread())
93         return Detach;
94     // FIXME: Multicolumn regions not yet supported (http://dev.w3.org/csswg/css-regions/#multi-column-regions)
95     // When the node has region style and changed its multicol style, we have to prepare
96     // a separate render region object.
97     if (s1.hasFlowFrom() && (s1.specifiesColumns() != s2.specifiesColumns()))
98         return Detach;
99     if (s1.alignItems() != s2.alignItems())
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.document().ensureStyleResolver().styleForElement(&element, &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(WTF::move(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     if (is<InsertionPoint>(current))
225         return;
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, parentRenderer);
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     ContainerNode* renderingParentNode = NodeRenderingTraversal::parent(&textNode);
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 attachDistributedChildren(InsertionPoint& insertionPoint, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition)
360 {
361     if (ShadowRoot* shadowRoot = insertionPoint.containingShadowRoot())
362         ContentDistributor::ensureDistribution(shadowRoot);
363
364     for (Node* current = insertionPoint.firstDistributed(); current; current = insertionPoint.nextDistributedTo(current)) {
365         if (current->renderer())
366             renderTreePosition.invalidateNextSibling(*current->renderer());
367         if (is<Text>(*current)) {
368             if (current->renderer())
369                 continue;
370             attachTextRenderer(downcast<Text>(*current), renderTreePosition);
371             continue;
372         }
373         if (is<Element>(*current)) {
374             Element& currentElement = downcast<Element>(*current);
375             if (currentElement.renderer())
376                 detachRenderTree(currentElement);
377             attachRenderTree(currentElement, inheritedStyle, renderTreePosition, nullptr);
378         }
379     }
380     // Use actual children as fallback content.
381     if (!insertionPoint.hasDistribution())
382         attachChildren(insertionPoint, inheritedStyle, renderTreePosition);
383 }
384
385 static void attachShadowRoot(ShadowRoot& shadowRoot)
386 {
387     ASSERT(shadowRoot.hostElement());
388     ASSERT(shadowRoot.hostElement()->renderer());
389
390     auto& renderer = *shadowRoot.hostElement()->renderer();
391     RenderTreePosition renderTreePosition(renderer);
392     attachChildren(shadowRoot, renderer.style(), renderTreePosition);
393
394     shadowRoot.clearNeedsStyleRecalc();
395     shadowRoot.clearChildNeedsStyleRecalc();
396 }
397
398 static PseudoElement* beforeOrAfterPseudoElement(Element& current, PseudoId pseudoId)
399 {
400     ASSERT(pseudoId == BEFORE || pseudoId == AFTER);
401     if (pseudoId == BEFORE)
402         return current.beforePseudoElement();
403     return current.afterPseudoElement();
404 }
405
406 static void setBeforeOrAfterPseudoElement(Element& current, Ref<PseudoElement>&& pseudoElement, PseudoId pseudoId)
407 {
408     ASSERT(pseudoId == BEFORE || pseudoId == AFTER);
409     if (pseudoId == BEFORE) {
410         current.setBeforePseudoElement(WTF::move(pseudoElement));
411         return;
412     }
413     current.setAfterPseudoElement(WTF::move(pseudoElement));
414 }
415
416 static void clearBeforeOrAfterPseudoElement(Element& current, PseudoId pseudoId)
417 {
418     ASSERT(pseudoId == BEFORE || pseudoId == AFTER);
419     if (pseudoId == BEFORE) {
420         current.clearBeforePseudoElement();
421         return;
422     }
423     current.clearAfterPseudoElement();
424 }
425
426 static void resetStyleForNonRenderedDescendants(Element& current)
427 {
428     ASSERT(!current.renderer());
429     bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle = false;
430     for (auto& child : childrenOfType<Element>(current)) {
431         ASSERT(!child.renderer());
432         if (elementNeedingStyleRecalcAffectsNextSiblingElementStyle) {
433             if (child.styleIsAffectedByPreviousSibling())
434                 child.setNeedsStyleRecalc();
435             elementNeedingStyleRecalcAffectsNextSiblingElementStyle = child.affectsNextSiblingElementStyle();
436         }
437
438         if (child.needsStyleRecalc()) {
439             child.resetComputedStyle();
440             child.clearNeedsStyleRecalc();
441             elementNeedingStyleRecalcAffectsNextSiblingElementStyle = child.affectsNextSiblingElementStyle();
442         }
443
444         if (child.childNeedsStyleRecalc()) {
445             resetStyleForNonRenderedDescendants(child);
446             child.clearChildNeedsStyleRecalc();
447         }
448     }
449 }
450
451 static bool needsPseudoElement(Element& current, PseudoId pseudoId)
452 {
453     if (!current.renderer() || !current.renderer()->canHaveGeneratedChildren())
454         return false;
455     if (current.isPseudoElement())
456         return false;
457     if (!pseudoElementRendererIsNeeded(current.renderer()->getCachedPseudoStyle(pseudoId)))
458         return false;
459     return true;
460 }
461
462 static void attachBeforeOrAfterPseudoElementIfNeeded(Element& current, PseudoId pseudoId, RenderTreePosition& renderTreePosition)
463 {
464     if (!needsPseudoElement(current, pseudoId))
465         return;
466     Ref<PseudoElement> pseudoElement = PseudoElement::create(current, pseudoId);
467     setBeforeOrAfterPseudoElement(current, pseudoElement.copyRef(), pseudoId);
468     attachRenderTree(pseudoElement.get(), *current.renderStyle(), renderTreePosition, nullptr);
469 }
470
471 static void attachRenderTree(Element& current, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, PassRefPtr<RenderStyle> resolvedStyle)
472 {
473     PostResolutionCallbackDisabler callbackDisabler(current.document());
474     WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
475
476     if (is<InsertionPoint>(current)) {
477         attachDistributedChildren(downcast<InsertionPoint>(current), inheritedStyle, renderTreePosition);
478         current.clearNeedsStyleRecalc();
479         current.clearChildNeedsStyleRecalc();
480         return;
481     }
482
483     if (current.hasCustomStyleResolveCallbacks())
484         current.willAttachRenderers();
485
486     createRendererIfNeeded(current, inheritedStyle, renderTreePosition, resolvedStyle);
487
488     if (auto* renderer = current.renderer()) {
489         StyleResolverParentPusher parentPusher(&current);
490
491         RenderTreePosition childRenderTreePosition(*renderer);
492         attachBeforeOrAfterPseudoElementIfNeeded(current, BEFORE, childRenderTreePosition);
493
494         if (ShadowRoot* shadowRoot = current.shadowRoot()) {
495             parentPusher.push();
496             attachShadowRoot(*shadowRoot);
497         } else if (current.firstChild())
498             parentPusher.push();
499
500         attachChildren(current, renderer->style(), childRenderTreePosition);
501
502         if (AXObjectCache* cache = current.document().axObjectCache())
503             cache->updateCacheAfterNodeIsAttached(&current);
504
505         attachBeforeOrAfterPseudoElementIfNeeded(current, AFTER, childRenderTreePosition);
506
507         current.updateFocusAppearanceAfterAttachIfNeeded();
508     } else
509         resetStyleForNonRenderedDescendants(current);
510
511     current.clearNeedsStyleRecalc();
512     current.clearChildNeedsStyleRecalc();
513
514     if (current.hasCustomStyleResolveCallbacks())
515         current.didAttachRenderers();
516 }
517
518 static void detachDistributedChildren(InsertionPoint& insertionPoint)
519 {
520     for (Node* current = insertionPoint.firstDistributed(); current; current = insertionPoint.nextDistributedTo(current)) {
521         if (is<Text>(*current)) {
522             detachTextRenderer(downcast<Text>(*current));
523             continue;
524         }
525         if (is<Element>(*current))
526             detachRenderTree(downcast<Element>(*current));
527     }
528 }
529
530 static void detachChildren(ContainerNode& current, DetachType detachType)
531 {
532     if (is<InsertionPoint>(current))
533         detachDistributedChildren(downcast<InsertionPoint>(current));
534
535     for (Node* child = current.firstChild(); child; child = child->nextSibling()) {
536         if (is<Text>(*child)) {
537             Style::detachTextRenderer(downcast<Text>(*child));
538             continue;
539         }
540         if (is<Element>(*child))
541             detachRenderTree(downcast<Element>(*child), detachType);
542     }
543     current.clearChildNeedsStyleRecalc();
544 }
545
546 static void detachShadowRoot(ShadowRoot& shadowRoot, DetachType detachType)
547 {
548     detachChildren(shadowRoot, detachType);
549 }
550
551 static void detachRenderTree(Element& current, DetachType detachType)
552 {
553     WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
554
555     if (current.hasCustomStyleResolveCallbacks())
556         current.willDetachRenderers();
557
558     current.clearStyleDerivedDataBeforeDetachingRenderer();
559
560     // Do not remove the element's hovered and active status
561     // if performing a reattach.
562     if (detachType != ReattachDetach)
563         current.clearHoverAndActiveStatusBeforeDetachingRenderer();
564
565     if (ShadowRoot* shadowRoot = current.shadowRoot())
566         detachShadowRoot(*shadowRoot, detachType);
567
568     detachChildren(current, detachType);
569
570     if (current.renderer())
571         current.renderer()->destroyAndCleanupAnonymousWrappers();
572     current.setRenderer(0);
573
574     if (current.hasCustomStyleResolveCallbacks())
575         current.didDetachRenderers();
576 }
577
578 static bool pseudoStyleCacheIsInvalid(RenderElement* renderer, RenderStyle* newStyle)
579 {
580     const RenderStyle& currentStyle = renderer->style();
581
582     const PseudoStyleCache* pseudoStyleCache = currentStyle.cachedPseudoStyles();
583     if (!pseudoStyleCache)
584         return false;
585
586     size_t cacheSize = pseudoStyleCache->size();
587     for (size_t i = 0; i < cacheSize; ++i) {
588         RefPtr<RenderStyle> newPseudoStyle;
589         PseudoId pseudoId = pseudoStyleCache->at(i)->styleType();
590         if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
591             newPseudoStyle = renderer->uncachedFirstLineStyle(newStyle);
592         else
593             newPseudoStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle);
594         if (!newPseudoStyle)
595             return true;
596         if (*newPseudoStyle != *pseudoStyleCache->at(i)) {
597             if (pseudoId < FIRST_INTERNAL_PSEUDOID)
598                 newStyle->setHasPseudoStyle(pseudoId);
599             newStyle->addCachedPseudoStyle(newPseudoStyle);
600             if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
601                 // FIXME: We should do an actual diff to determine whether a repaint vs. layout
602                 // is needed, but for now just assume a layout will be required. The diff code
603                 // in RenderObject::setStyle would need to be factored out so that it could be reused.
604                 renderer->setNeedsLayoutAndPrefWidthsRecalc();
605             }
606             return true;
607         }
608     }
609     return false;
610 }
611
612 static Change resolveLocal(Element& current, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, Change inheritedChange)
613 {
614     Change localChange = Detach;
615     RefPtr<RenderStyle> newStyle;
616     RefPtr<RenderStyle> currentStyle = current.renderStyle();
617
618     Document& document = current.document();
619     if (currentStyle && current.styleChangeType() != ReconstructRenderTree) {
620         Ref<RenderStyle> style(styleForElement(current, inheritedStyle));
621         newStyle = style.ptr();
622         localChange = determineChange(*currentStyle, style);
623     }
624     if (localChange == Detach) {
625         if (current.renderer() || current.isNamedFlowContentNode())
626             detachRenderTree(current, ReattachDetach);
627         attachRenderTree(current, inheritedStyle, renderTreePosition, newStyle.release());
628         invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(current);
629
630         return Detach;
631     }
632
633     if (RenderElement* renderer = current.renderer()) {
634         if (localChange != NoChange || pseudoStyleCacheIsInvalid(renderer, newStyle.get()) || (inheritedChange == Force && renderer->requiresForcedStyleRecalcPropagation()) || current.styleChangeType() == SyntheticStyleChange)
635             renderer->setAnimatableStyle(*newStyle, current.styleChangeType() == SyntheticStyleChange ? StyleDifferenceRecompositeLayer : StyleDifferenceEqual);
636         else if (current.needsStyleRecalc()) {
637             // Although no change occurred, we use the new style so that the cousin style sharing code won't get
638             // fooled into believing this style is the same.
639             renderer->setStyleInternal(*newStyle);
640         }
641     }
642
643     // If "rem" units are used anywhere in the document, and if the document element's font size changes, then force font updating
644     // 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).
645     if (document.styleSheetCollection().usesRemUnits() && document.documentElement() == &current && localChange != NoChange && currentStyle && newStyle && currentStyle->fontSize() != newStyle->fontSize()) {
646         // Cached RenderStyles may depend on the re units.
647         if (StyleResolver* styleResolver = document.styleResolverIfExists())
648             styleResolver->invalidateMatchedPropertiesCache();
649         return Force;
650     }
651     if (inheritedChange == Force)
652         return Force;
653     if (current.styleChangeType() >= FullStyleChange)
654         return Force;
655
656     return localChange;
657 }
658
659 void resolveTextNode(Text& text, RenderTreePosition& renderTreePosition)
660 {
661     text.clearNeedsStyleRecalc();
662
663     bool hasRenderer = text.renderer();
664     bool needsRenderer = textRendererIsNeeded(text, renderTreePosition);
665     if (hasRenderer) {
666         if (needsRenderer)
667             return;
668         detachTextRenderer(text);
669         invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(text);
670         return;
671     }
672     if (!needsRenderer)
673         return;
674     attachTextRenderer(text, renderTreePosition);
675     invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(text);
676 }
677
678 static void resolveShadowTree(ShadowRoot& shadowRoot, Element& host, Style::Change change)
679 {
680     ASSERT(shadowRoot.hostElement() == &host);
681     ASSERT(host.renderer());
682     RenderTreePosition renderTreePosition(*host.renderer());
683     for (Node* child = shadowRoot.firstChild(); child; child = child->nextSibling()) {
684         if (child->renderer())
685             renderTreePosition.invalidateNextSibling(*child->renderer());
686         if (is<Text>(*child) && child->needsStyleRecalc()) {
687             resolveTextNode(downcast<Text>(*child), renderTreePosition);
688             continue;
689         }
690         if (is<Element>(*child))
691             resolveTree(downcast<Element>(*child), host.renderer()->style(), renderTreePosition, change);
692     }
693
694     shadowRoot.clearNeedsStyleRecalc();
695     shadowRoot.clearChildNeedsStyleRecalc();
696 }
697
698 static void updateBeforeOrAfterPseudoElement(Element& current, Change change, PseudoId pseudoId, RenderTreePosition& renderTreePosition)
699 {
700     ASSERT(current.renderer());
701     if (PseudoElement* existingPseudoElement = beforeOrAfterPseudoElement(current, pseudoId)) {
702         if (existingPseudoElement->renderer())
703             renderTreePosition.invalidateNextSibling(*existingPseudoElement->renderer());
704
705         if (needsPseudoElement(current, pseudoId))
706             resolveTree(*existingPseudoElement, current.renderer()->style(), renderTreePosition, current.needsStyleRecalc() ? Force : change);
707         else
708             clearBeforeOrAfterPseudoElement(current, pseudoId);
709         return;
710     }
711     attachBeforeOrAfterPseudoElementIfNeeded(current, pseudoId, renderTreePosition);
712 }
713
714 #if PLATFORM(IOS)
715 static EVisibility elementImplicitVisibility(const Element* element)
716 {
717     RenderObject* renderer = element->renderer();
718     if (!renderer)
719         return VISIBLE;
720
721     RenderStyle& style = renderer->style();
722
723     Length width(style.width());
724     Length height(style.height());
725     if ((width.isFixed() && width.value() <= 0) || (height.isFixed() && height.value() <= 0))
726         return HIDDEN;
727
728     Length top(style.top());
729     Length left(style.left());
730     if (left.isFixed() && width.isFixed() && -left.value() >= width.value())
731         return HIDDEN;
732
733     if (top.isFixed() && height.isFixed() && -top.value() >= height.value())
734         return HIDDEN;
735     return VISIBLE;
736 }
737
738 class CheckForVisibilityChangeOnRecalcStyle {
739 public:
740     CheckForVisibilityChangeOnRecalcStyle(Element* element, RenderStyle* currentStyle)
741         : m_element(element)
742         , m_previousDisplay(currentStyle ? currentStyle->display() : NONE)
743         , m_previousVisibility(currentStyle ? currentStyle->visibility() : HIDDEN)
744         , m_previousImplicitVisibility(WKObservingContentChanges() && WKContentChange() != WKContentVisibilityChange ? elementImplicitVisibility(element) : VISIBLE)
745     {
746     }
747     ~CheckForVisibilityChangeOnRecalcStyle()
748     {
749         if (!WKObservingContentChanges())
750             return;
751         RenderStyle* style = m_element->renderStyle();
752         if (!style)
753             return;
754         if ((m_previousDisplay == NONE && style->display() != NONE) || (m_previousVisibility == HIDDEN && style->visibility() != HIDDEN)
755             || (m_previousImplicitVisibility == HIDDEN && elementImplicitVisibility(m_element.get()) == VISIBLE))
756             WKSetObservedContentChange(WKContentVisibilityChange);
757     }
758 private:
759     RefPtr<Element> m_element;
760     EDisplay m_previousDisplay;
761     EVisibility m_previousVisibility;
762     EVisibility m_previousImplicitVisibility;
763 };
764 #endif // PLATFORM(IOS)
765
766 void resolveTree(Element& current, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, Change change)
767 {
768     ASSERT(change != Detach);
769
770     if (is<InsertionPoint>(current)) {
771         current.clearNeedsStyleRecalc();
772         current.clearChildNeedsStyleRecalc();
773         return;
774     }
775
776     if (current.hasCustomStyleResolveCallbacks()) {
777         if (!current.willRecalcStyle(change))
778             return;
779     }
780
781 #if PLATFORM(IOS)
782     CheckForVisibilityChangeOnRecalcStyle checkForVisibilityChange(&current, current.renderStyle());
783 #endif
784
785     if (change > NoChange || current.needsStyleRecalc())
786         current.resetComputedStyle();
787
788     if (change >= Inherit || current.needsStyleRecalc())
789         change = resolveLocal(current, inheritedStyle, renderTreePosition, change);
790
791     auto* renderer = current.renderer();
792
793     if (change != Detach && renderer) {
794         StyleResolverParentPusher parentPusher(&current);
795
796         if (ShadowRoot* shadowRoot = current.shadowRoot()) {
797             if (change >= Inherit || shadowRoot->childNeedsStyleRecalc() || shadowRoot->needsStyleRecalc()) {
798                 parentPusher.push();
799                 resolveShadowTree(*shadowRoot, current, change);
800             }
801         }
802
803         RenderTreePosition childRenderTreePosition(*renderer);
804         updateBeforeOrAfterPseudoElement(current, change, BEFORE, childRenderTreePosition);
805
806         bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle = false;
807         for (Node* child = current.firstChild(); child; child = child->nextSibling()) {
808             if (RenderObject* childRenderer = child->renderer())
809                 childRenderTreePosition.invalidateNextSibling(*childRenderer);
810             if (is<Text>(*child) && child->needsStyleRecalc()) {
811                 resolveTextNode(downcast<Text>(*child), childRenderTreePosition);
812                 continue;
813             }
814             if (!is<Element>(*child))
815                 continue;
816
817             Element& childElement = downcast<Element>(*child);
818             if (elementNeedingStyleRecalcAffectsNextSiblingElementStyle) {
819                 if (childElement.styleIsAffectedByPreviousSibling())
820                     childElement.setNeedsStyleRecalc();
821                 elementNeedingStyleRecalcAffectsNextSiblingElementStyle = childElement.affectsNextSiblingElementStyle();
822             } else if (childElement.styleChangeType() >= FullStyleChange)
823                 elementNeedingStyleRecalcAffectsNextSiblingElementStyle = childElement.affectsNextSiblingElementStyle();
824             if (change >= Inherit || childElement.childNeedsStyleRecalc() || childElement.needsStyleRecalc()) {
825                 parentPusher.push();
826                 resolveTree(childElement, renderer->style(), childRenderTreePosition, change);
827             }
828         }
829
830         updateBeforeOrAfterPseudoElement(current, change, AFTER, childRenderTreePosition);
831     }
832     if (change != Detach && !renderer)
833         resetStyleForNonRenderedDescendants(current);
834
835     current.clearNeedsStyleRecalc();
836     current.clearChildNeedsStyleRecalc();
837     
838     if (current.hasCustomStyleResolveCallbacks())
839         current.didRecalcStyle(change);
840 }
841
842 void resolveTree(Document& document, Change change)
843 {
844     if (change == Force) {
845         auto documentStyle = resolveForDocument(document);
846
847         // Inserting the pictograph font at the end of the font fallback list is done by the
848         // font selector, so set a font selector if needed.
849         if (Settings* settings = document.settings()) {
850             if (settings->fontFallbackPrefersPictographs())
851                 documentStyle.get().fontCascade().update(&document.fontSelector());
852         }
853
854         Style::Change documentChange = determineChange(documentStyle.get(), document.renderView()->style());
855         if (documentChange != NoChange)
856             document.renderView()->setStyle(WTF::move(documentStyle));
857     }
858
859     Element* documentElement = document.documentElement();
860     if (!documentElement)
861         return;
862     if (change < Inherit && !documentElement->childNeedsStyleRecalc() && !documentElement->needsStyleRecalc())
863         return;
864     RenderTreePosition renderTreePosition(*document.renderView());
865     resolveTree(*documentElement, *document.renderStyle(), renderTreePosition, change);
866 }
867
868 void detachRenderTree(Element& element)
869 {
870     detachRenderTree(element, NormalDetach);
871 }
872
873 static Vector<std::function<void ()>>& postResolutionCallbackQueue()
874 {
875     static NeverDestroyed<Vector<std::function<void ()>>> vector;
876     return vector;
877 }
878
879 void queuePostResolutionCallback(std::function<void ()> callback)
880 {
881     postResolutionCallbackQueue().append(callback);
882 }
883
884 static void suspendMemoryCacheClientCalls(Document& document)
885 {
886     Page* page = document.page();
887     if (!page || !page->areMemoryCacheClientCallsEnabled())
888         return;
889
890     page->setMemoryCacheClientCallsEnabled(false);
891
892     RefPtr<MainFrame> protectedMainFrame = &page->mainFrame();
893     postResolutionCallbackQueue().append([protectedMainFrame]{
894         if (Page* page = protectedMainFrame->page())
895             page->setMemoryCacheClientCallsEnabled(true);
896     });
897 }
898
899 static unsigned resolutionNestingDepth;
900
901 PostResolutionCallbackDisabler::PostResolutionCallbackDisabler(Document& document)
902 {
903     ++resolutionNestingDepth;
904
905     if (resolutionNestingDepth == 1)
906         platformStrategies()->loaderStrategy()->resourceLoadScheduler()->suspendPendingRequests();
907
908     // FIXME: It's strange to build this into the disabler.
909     suspendMemoryCacheClientCalls(document);
910 }
911
912 PostResolutionCallbackDisabler::~PostResolutionCallbackDisabler()
913 {
914     if (resolutionNestingDepth == 1) {
915         // Get size each time through the loop because a callback can add more callbacks to the end of the queue.
916         auto& queue = postResolutionCallbackQueue();
917         for (size_t i = 0; i < queue.size(); ++i)
918             queue[i]();
919         queue.clear();
920
921         platformStrategies()->loaderStrategy()->resourceLoadScheduler()->resumePendingRequests();
922     }
923
924     --resolutionNestingDepth;
925 }
926
927 bool postResolutionCallbacksAreSuspended()
928 {
929     return resolutionNestingDepth;
930 }
931
932 }
933 }