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