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