[Web Animations] Expose Web Animations CSS integration as an experimental feature
[WebKit-https.git] / Source / WebCore / rendering / updating / RenderTreeUpdater.cpp
1 /*
2  * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "RenderTreeUpdater.h"
28
29 #include "AXObjectCache.h"
30 #include "CSSAnimationController.h"
31 #include "ComposedTreeAncestorIterator.h"
32 #include "ComposedTreeIterator.h"
33 #include "Document.h"
34 #include "DocumentTimeline.h"
35 #include "Element.h"
36 #include "HTMLParserIdioms.h"
37 #include "HTMLSlotElement.h"
38 #include "InspectorInstrumentation.h"
39 #include "NodeRenderStyle.h"
40 #include "PseudoElement.h"
41 #include "RenderDescendantIterator.h"
42 #include "RenderFullScreen.h"
43 #include "RenderInline.h"
44 #include "RenderTreeUpdaterGeneratedContent.h"
45 #include "RuntimeEnabledFeatures.h"
46 #include "StyleResolver.h"
47 #include "StyleTreeResolver.h"
48 #include <wtf/SystemTracing.h>
49
50 #if PLATFORM(IOS)
51 #include "WKContentObservation.h"
52 #include "WKContentObservationInternal.h"
53 #endif
54
55 namespace WebCore {
56
57 #if PLATFORM(IOS)
58 class CheckForVisibilityChange {
59 public:
60     CheckForVisibilityChange(const Element&);
61     ~CheckForVisibilityChange();
62
63 private:
64     const Element& m_element;
65     EDisplay m_previousDisplay;
66     EVisibility m_previousVisibility;
67     EVisibility m_previousImplicitVisibility;
68 };
69 #endif // PLATFORM(IOS)
70
71 RenderTreeUpdater::Parent::Parent(ContainerNode& root)
72     : element(is<Document>(root) ? nullptr : downcast<Element>(&root))
73     , renderTreePosition(RenderTreePosition(*root.renderer()))
74 {
75 }
76
77 RenderTreeUpdater::Parent::Parent(Element& element, const Style::ElementUpdates* updates)
78     : element(&element)
79     , updates(updates)
80     , renderTreePosition(element.renderer() ? std::make_optional(RenderTreePosition(*element.renderer())) : std::nullopt)
81 {
82 }
83
84 RenderTreeUpdater::RenderTreeUpdater(Document& document)
85     : m_document(document)
86     , m_generatedContent(std::make_unique<GeneratedContent>(*this))
87     , m_builder(renderView())
88 {
89 }
90
91 RenderTreeUpdater::~RenderTreeUpdater() = default;
92
93 static ContainerNode* findRenderingRoot(ContainerNode& node)
94 {
95     if (node.renderer())
96         return &node;
97     for (auto& ancestor : composedTreeAncestors(node)) {
98         if (ancestor.renderer())
99             return &ancestor;
100         if (!ancestor.hasDisplayContents())
101             return nullptr;
102     }
103     return &node.document();
104 }
105
106 static ListHashSet<ContainerNode*> findRenderingRoots(const Style::Update& update)
107 {
108     ListHashSet<ContainerNode*> renderingRoots;
109     for (auto* root : update.roots()) {
110         auto* renderingRoot = findRenderingRoot(*root);
111         if (!renderingRoot)
112             continue;
113         renderingRoots.add(renderingRoot);
114     }
115     return renderingRoots;
116 }
117
118 void RenderTreeUpdater::commit(std::unique_ptr<const Style::Update> styleUpdate)
119 {
120     ASSERT(&m_document == &styleUpdate->document());
121
122     if (!m_document.shouldCreateRenderers() || !m_document.renderView())
123         return;
124     
125     TraceScope scope(RenderTreeBuildStart, RenderTreeBuildEnd);
126
127     Style::PostResolutionCallbackDisabler callbackDisabler(m_document);
128
129     m_styleUpdate = WTFMove(styleUpdate);
130
131     for (auto* root : findRenderingRoots(*m_styleUpdate))
132         updateRenderTree(*root);
133
134     generatedContent().updateRemainingQuotes();
135
136     m_builder.updateAfterDescendants(renderView());
137
138     m_styleUpdate = nullptr;
139 }
140
141 static bool shouldCreateRenderer(const Element& element, const RenderElement& parentRenderer)
142 {
143     if (!parentRenderer.canHaveChildren() && !(element.isPseudoElement() && parentRenderer.canHaveGeneratedChildren()))
144         return false;
145     if (parentRenderer.element() && !parentRenderer.element()->childShouldCreateRenderer(element))
146         return false;
147     return true;
148 }
149
150 void RenderTreeUpdater::updateRenderTree(ContainerNode& root)
151 {
152     ASSERT(root.renderer());
153     ASSERT(m_parentStack.isEmpty());
154
155     m_parentStack.append(Parent(root));
156
157     auto descendants = composedTreeDescendants(root);
158     auto it = descendants.begin();
159     auto end = descendants.end();
160
161     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=156172
162     it.dropAssertions();
163
164     while (it != end) {
165         popParentsToDepth(it.depth());
166
167         auto& node = *it;
168
169         if (auto* renderer = node.renderer())
170             renderTreePosition().invalidateNextSibling(*renderer);
171         else if (is<Element>(node) && downcast<Element>(node).hasDisplayContents())
172             renderTreePosition().invalidateNextSibling();
173
174         if (is<Text>(node)) {
175             auto& text = downcast<Text>(node);
176             auto* textUpdate = m_styleUpdate->textUpdate(text);
177             bool didCreateParent = parent().updates && parent().updates->update.change == Style::Detach;
178             bool mayNeedUpdateWhitespaceOnlyRenderer = renderingParent().didCreateOrDestroyChildRenderer && text.data().isAllSpecialCharacters<isHTMLSpace>();
179             if (didCreateParent || textUpdate || mayNeedUpdateWhitespaceOnlyRenderer)
180                 updateTextRenderer(text, textUpdate);
181
182             storePreviousRenderer(text);
183             it.traverseNextSkippingChildren();
184             continue;
185         }
186
187         auto& element = downcast<Element>(node);
188
189         auto* elementUpdates = m_styleUpdate->elementUpdates(element);
190
191         // We hop through display: contents elements in findRenderingRoot, so
192         // there may be other updates down the tree.
193         if (!elementUpdates && !element.hasDisplayContents()) {
194             storePreviousRenderer(element);
195             it.traverseNextSkippingChildren();
196             continue;
197         }
198
199         if (elementUpdates)
200             updateElementRenderer(element, elementUpdates->update);
201
202         storePreviousRenderer(element);
203
204         bool mayHaveRenderedDescendants = element.renderer() || (element.hasDisplayContents() && shouldCreateRenderer(element, renderTreePosition().parent()));
205         if (!mayHaveRenderedDescendants) {
206             it.traverseNextSkippingChildren();
207             continue;
208         }
209
210         pushParent(element, elementUpdates);
211
212         it.traverseNext();
213     }
214
215     popParentsToDepth(0);
216 }
217
218 auto RenderTreeUpdater::renderingParent() -> Parent&
219 {
220     for (unsigned i = m_parentStack.size(); i--;) {
221         if (m_parentStack[i].renderTreePosition)
222             return m_parentStack[i];
223     }
224     ASSERT_NOT_REACHED();
225     return m_parentStack.last();
226 }
227
228 RenderTreePosition& RenderTreeUpdater::renderTreePosition()
229 {
230     return *renderingParent().renderTreePosition;
231 }
232
233 void RenderTreeUpdater::pushParent(Element& element, const Style::ElementUpdates* updates)
234 {
235     m_parentStack.append(Parent(element, updates));
236
237     updateBeforeDescendants(element, updates);
238 }
239
240 void RenderTreeUpdater::popParent()
241 {
242     auto& parent = m_parentStack.last();
243     if (parent.element)
244         updateAfterDescendants(*parent.element, parent.updates);
245
246     m_parentStack.removeLast();
247 }
248
249 void RenderTreeUpdater::popParentsToDepth(unsigned depth)
250 {
251     ASSERT(m_parentStack.size() >= depth);
252
253     while (m_parentStack.size() > depth)
254         popParent();
255 }
256
257 void RenderTreeUpdater::updateBeforeDescendants(Element& element, const Style::ElementUpdates* updates)
258 {
259     if (updates)
260         generatedContent().updatePseudoElement(element, updates->beforePseudoElementUpdate, BEFORE);
261 }
262
263 void RenderTreeUpdater::updateAfterDescendants(Element& element, const Style::ElementUpdates* updates)
264 {
265     if (updates)
266         generatedContent().updatePseudoElement(element, updates->afterPseudoElementUpdate, AFTER);
267
268     auto* renderer = element.renderer();
269     if (!renderer)
270         return;
271
272     m_builder.updateAfterDescendants(*renderer);
273
274     if (element.hasCustomStyleResolveCallbacks() && updates && updates->update.change == Style::Detach)
275         element.didAttachRenderers();
276 }
277
278 static bool pseudoStyleCacheIsInvalid(RenderElement* renderer, RenderStyle* newStyle)
279 {
280     const RenderStyle& currentStyle = renderer->style();
281
282     const PseudoStyleCache* pseudoStyleCache = currentStyle.cachedPseudoStyles();
283     if (!pseudoStyleCache)
284         return false;
285
286     for (auto& cache : *pseudoStyleCache) {
287         PseudoId pseudoId = cache->styleType();
288         std::unique_ptr<RenderStyle> newPseudoStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle);
289         if (!newPseudoStyle)
290             return true;
291         if (*newPseudoStyle != *cache) {
292             newStyle->addCachedPseudoStyle(WTFMove(newPseudoStyle));
293             return true;
294         }
295     }
296     return false;
297 }
298
299 void RenderTreeUpdater::updateRendererStyle(RenderElement& renderer, RenderStyle&& newStyle, StyleDifference minimalStyleDifference)
300 {
301     auto oldStyle = RenderStyle::clone(renderer.style());
302     renderer.setStyle(WTFMove(newStyle), minimalStyleDifference);
303     m_builder.normalizeTreeAfterStyleChange(renderer, oldStyle);
304 }
305
306 void RenderTreeUpdater::updateElementRenderer(Element& element, const Style::ElementUpdate& update)
307 {
308 #if PLATFORM(IOS)
309     CheckForVisibilityChange checkForVisibilityChange(element);
310 #endif
311
312     bool shouldTearDownRenderers = update.change == Style::Detach && (element.renderer() || element.hasDisplayContents());
313     if (shouldTearDownRenderers) {
314         if (!element.renderer()) {
315             // We may be tearing down a descendant renderer cached in renderTreePosition.
316             renderTreePosition().invalidateNextSibling();
317         }
318
319         // display:none cancels animations.
320         auto teardownType = update.style->display() == NONE ? TeardownType::RendererUpdateCancelingAnimations : TeardownType::RendererUpdate;
321         tearDownRenderers(element, teardownType, m_builder);
322
323         renderingParent().didCreateOrDestroyChildRenderer = true;
324     }
325
326     bool hasDisplayContents = update.style->display() == CONTENTS;
327     if (hasDisplayContents)
328         element.storeDisplayContentsStyle(RenderStyle::clonePtr(*update.style));
329     else
330         element.resetComputedStyle();
331
332     bool shouldCreateNewRenderer = !element.renderer() && !hasDisplayContents;
333     if (shouldCreateNewRenderer) {
334         if (element.hasCustomStyleResolveCallbacks())
335             element.willAttachRenderers();
336         createRenderer(element, RenderStyle::clone(*update.style));
337
338         renderingParent().didCreateOrDestroyChildRenderer = true;
339         return;
340     }
341
342     if (!element.renderer())
343         return;
344     auto& renderer = *element.renderer();
345
346     if (update.recompositeLayer) {
347         updateRendererStyle(renderer, RenderStyle::clone(*update.style), StyleDifferenceRecompositeLayer);
348         return;
349     }
350
351     if (update.change == Style::NoChange) {
352         if (pseudoStyleCacheIsInvalid(&renderer, update.style.get())) {
353             updateRendererStyle(renderer, RenderStyle::clone(*update.style), StyleDifferenceEqual);
354             return;
355         }
356         return;
357     }
358
359     updateRendererStyle(renderer, RenderStyle::clone(*update.style), StyleDifferenceEqual);
360 }
361
362 void RenderTreeUpdater::createRenderer(Element& element, RenderStyle&& style)
363 {
364     auto computeInsertionPosition = [this, &element] () {
365         renderTreePosition().computeNextSibling(element);
366         return renderTreePosition();
367     };
368     
369     if (!shouldCreateRenderer(element, renderTreePosition().parent()))
370         return;
371
372     if (!element.rendererIsNeeded(style))
373         return;
374
375     RenderTreePosition insertionPosition = computeInsertionPosition();
376     auto newRenderer = element.createElementRenderer(WTFMove(style), insertionPosition);
377     if (!newRenderer)
378         return;
379
380     if (!insertionPosition.parent().isChildAllowed(*newRenderer, newRenderer->style()))
381         return;
382
383     element.setRenderer(newRenderer.get());
384
385     newRenderer->initializeStyle();
386
387 #if ENABLE(FULLSCREEN_API)
388     if (m_document.webkitIsFullScreen() && m_document.webkitCurrentFullScreenElement() == &element) {
389         newRenderer = RenderFullScreen::wrapNewRenderer(m_builder, WTFMove(newRenderer), insertionPosition.parent(), m_document);
390         if (!newRenderer)
391             return;
392     }
393 #endif
394
395     m_builder.attach(insertionPosition, WTFMove(newRenderer));
396
397     if (AXObjectCache* cache = m_document.axObjectCache())
398         cache->updateCacheAfterNodeIsAttached(&element);
399 }
400
401 bool RenderTreeUpdater::textRendererIsNeeded(const Text& textNode)
402 {
403     auto& renderingParent = this->renderingParent();
404     auto& parentRenderer = renderingParent.renderTreePosition->parent();
405     if (!parentRenderer.canHaveChildren())
406         return false;
407     if (parentRenderer.element() && !parentRenderer.element()->childShouldCreateRenderer(textNode))
408         return false;
409     if (textNode.isEditingText())
410         return true;
411     if (!textNode.length())
412         return false;
413     if (!textNode.data().isAllSpecialCharacters<isHTMLSpace>())
414         return true;
415     if (is<RenderText>(renderingParent.previousChildRenderer))
416         return true;
417     // This text node has nothing but white space. We may still need a renderer in some cases.
418     if (parentRenderer.isTable() || parentRenderer.isTableRow() || parentRenderer.isTableSection() || parentRenderer.isRenderTableCol() || parentRenderer.isFrameSet())
419         return false;
420     if (parentRenderer.isFlexibleBox() && !parentRenderer.isRenderButton())
421         return false;
422     if (parentRenderer.style().preserveNewline()) // pre/pre-wrap/pre-line always make renderers.
423         return true;
424
425     auto* previousRenderer = renderingParent.previousChildRenderer;
426     if (previousRenderer && previousRenderer->isBR()) // <span><br/> <br/></span>
427         return false;
428
429     if (parentRenderer.isRenderInline()) {
430         // <span><div/> <div/></span>
431         if (previousRenderer && !previousRenderer->isInline())
432             return false;
433     } else {
434         if (parentRenderer.isRenderBlock() && !parentRenderer.childrenInline() && (!previousRenderer || !previousRenderer->isInline()))
435             return false;
436         
437         RenderObject* first = parentRenderer.firstChild();
438         while (first && first->isFloatingOrOutOfFlowPositioned())
439             first = first->nextSibling();
440         RenderObject* nextRenderer = textNode.renderer() ? textNode.renderer() :  renderTreePosition().nextSiblingRenderer(textNode);
441         if (!first || nextRenderer == first) {
442             // Whitespace at the start of a block just goes away. Don't even make a render object for this text.
443             return false;
444         }
445     }
446     return true;
447 }
448
449 void RenderTreeUpdater::createTextRenderer(Text& textNode, const Style::TextUpdate* textUpdate)
450 {
451     ASSERT(!textNode.renderer());
452
453     auto& renderTreePosition = this->renderTreePosition();
454     auto textRenderer = textNode.createTextRenderer(renderTreePosition.parent().style());
455
456     renderTreePosition.computeNextSibling(textNode);
457
458     if (!renderTreePosition.parent().isChildAllowed(*textRenderer, renderTreePosition.parent().style()))
459         return;
460
461     textNode.setRenderer(textRenderer.get());
462
463     if (textUpdate && textUpdate->inheritedDisplayContentsStyle && *textUpdate->inheritedDisplayContentsStyle) {
464         // Wrap text renderer into anonymous inline so we can give it a style.
465         // This is to support "<div style='display:contents;color:green'>text</div>" type cases
466         auto newDisplayContentsAnonymousWrapper = WebCore::createRenderer<RenderInline>(textNode.document(), RenderStyle::clone(**textUpdate->inheritedDisplayContentsStyle));
467         newDisplayContentsAnonymousWrapper->initializeStyle();
468         auto& displayContentsAnonymousWrapper = *newDisplayContentsAnonymousWrapper;
469         m_builder.attach(renderTreePosition, WTFMove(newDisplayContentsAnonymousWrapper));
470
471         textRenderer->setInlineWrapperForDisplayContents(&displayContentsAnonymousWrapper);
472         m_builder.attach(displayContentsAnonymousWrapper, WTFMove(textRenderer));
473         return;
474     }
475
476     m_builder.attach(renderTreePosition, WTFMove(textRenderer));
477 }
478
479 void RenderTreeUpdater::updateTextRenderer(Text& text, const Style::TextUpdate* textUpdate)
480 {
481     auto* existingRenderer = text.renderer();
482     bool needsRenderer = textRendererIsNeeded(text);
483
484     if (existingRenderer && textUpdate && textUpdate->inheritedDisplayContentsStyle) {
485         if (existingRenderer->inlineWrapperForDisplayContents() || *textUpdate->inheritedDisplayContentsStyle) {
486             // FIXME: We could update without teardown.
487             tearDownTextRenderer(text, m_builder);
488             existingRenderer = nullptr;
489         }
490     }
491
492     if (existingRenderer) {
493         if (needsRenderer) {
494             if (textUpdate)
495                 existingRenderer->setTextWithOffset(text.data(), textUpdate->offset, textUpdate->length);
496             return;
497         }
498         tearDownTextRenderer(text, m_builder);
499         renderingParent().didCreateOrDestroyChildRenderer = true;
500         return;
501     }
502     if (!needsRenderer)
503         return;
504     createTextRenderer(text, textUpdate);
505     renderingParent().didCreateOrDestroyChildRenderer = true;
506 }
507
508 void RenderTreeUpdater::storePreviousRenderer(Node& node)
509 {
510     auto* renderer = node.renderer();
511     if (!renderer)
512         return;
513     ASSERT(renderingParent().previousChildRenderer != renderer);
514     renderingParent().previousChildRenderer = renderer;
515 }
516
517 void RenderTreeUpdater::tearDownRenderers(Element& root)
518 {
519     auto* view = root.document().renderView();
520     if (!view)
521         return;
522     RenderTreeBuilder builder(*view);
523     tearDownRenderers(root, TeardownType::Full, builder);
524 }
525
526 void RenderTreeUpdater::tearDownRenderer(Text& text)
527 {
528     auto* view = text.document().renderView();
529     if (!view)
530         return;
531     RenderTreeBuilder builder(*view);
532     tearDownTextRenderer(text, builder);
533 }
534
535 void RenderTreeUpdater::tearDownRenderers(Element& root, TeardownType teardownType, RenderTreeBuilder& builder)
536 {
537     WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
538
539     Vector<Element*, 30> teardownStack;
540
541     auto push = [&] (Element& element) {
542         if (element.hasCustomStyleResolveCallbacks())
543             element.willDetachRenderers();
544         teardownStack.append(&element);
545     };
546
547     auto& document = root.document();
548     auto* timeline = document.existingTimeline();
549     auto& animationController = document.frame()->animation();    
550
551     auto pop = [&] (unsigned depth) {
552         while (teardownStack.size() > depth) {
553             auto& element = *teardownStack.takeLast();
554
555             if (teardownType == TeardownType::Full || teardownType == TeardownType::RendererUpdateCancelingAnimations) {
556                 if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled()) {
557                     if (timeline)
558                         timeline->cancelDeclarativeAnimationsForElement(element);
559                 } else
560                     animationController.cancelAnimations(element);
561             }
562
563             if (teardownType == TeardownType::Full)
564                 element.clearHoverAndActiveStatusBeforeDetachingRenderer();
565
566             GeneratedContent::removeBeforePseudoElement(element, builder);
567             GeneratedContent::removeAfterPseudoElement(element, builder);
568
569             if (auto* renderer = element.renderer()) {
570                 builder.destroyAndCleanUpAnonymousWrappers(*renderer);
571                 element.setRenderer(nullptr);
572             }
573
574             // Make sure we don't leave any renderers behind in nodes outside the composed tree.
575             if (element.shadowRoot())
576                 tearDownLeftoverShadowHostChildren(element, builder);
577
578             if (element.hasCustomStyleResolveCallbacks())
579                 element.didDetachRenderers();
580         }
581     };
582
583     push(root);
584
585     auto descendants = composedTreeDescendants(root);
586     for (auto it = descendants.begin(), end = descendants.end(); it != end; ++it) {
587         pop(it.depth());
588
589         if (is<Text>(*it)) {
590             tearDownTextRenderer(downcast<Text>(*it), builder);
591             continue;
592         }
593
594         push(downcast<Element>(*it));
595     }
596
597     pop(0);
598
599     tearDownLeftoverPaginationRenderersIfNeeded(root, builder);
600 }
601
602 void RenderTreeUpdater::tearDownTextRenderer(Text& text, RenderTreeBuilder& builder)
603 {
604     auto* renderer = text.renderer();
605     if (!renderer)
606         return;
607     builder.destroyAndCleanUpAnonymousWrappers(*renderer);
608     text.setRenderer(nullptr);
609 }
610
611 void RenderTreeUpdater::tearDownLeftoverPaginationRenderersIfNeeded(Element& root, RenderTreeBuilder& builder)
612 {
613     if (&root != root.document().documentElement())
614         return;
615     for (auto* child = root.document().renderView()->firstChild(); child;) {
616         auto* nextSibling = child->nextSibling();
617         if (is<RenderMultiColumnFlow>(*child) || is<RenderMultiColumnSet>(*child))
618             builder.destroyAndCleanUpAnonymousWrappers(*child);
619         child = nextSibling;
620     }
621 }
622
623 void RenderTreeUpdater::tearDownLeftoverShadowHostChildren(Element& host, RenderTreeBuilder& builder)
624 {
625     for (auto* hostChild = host.firstChild(); hostChild; hostChild = hostChild->nextSibling()) {
626         if (!hostChild->renderer())
627             continue;
628         if (is<Text>(*hostChild)) {
629             tearDownTextRenderer(downcast<Text>(*hostChild), builder);
630             continue;
631         }
632         if (is<Element>(*hostChild))
633             tearDownRenderers(downcast<Element>(*hostChild), TeardownType::Full, builder);
634     }
635 }
636
637 RenderView& RenderTreeUpdater::renderView()
638 {
639     return *m_document.renderView();
640 }
641
642 #if PLATFORM(IOS)
643 static EVisibility elementImplicitVisibility(const Element& element)
644 {
645     auto* renderer = element.renderer();
646     if (!renderer)
647         return VISIBLE;
648
649     auto& style = renderer->style();
650
651     auto width = style.width();
652     auto height = style.height();
653     if ((width.isFixed() && width.value() <= 0) || (height.isFixed() && height.value() <= 0))
654         return HIDDEN;
655
656     auto top = style.top();
657     auto left = style.left();
658     if (left.isFixed() && width.isFixed() && -left.value() >= width.value())
659         return HIDDEN;
660
661     if (top.isFixed() && height.isFixed() && -top.value() >= height.value())
662         return HIDDEN;
663     return VISIBLE;
664 }
665
666 CheckForVisibilityChange::CheckForVisibilityChange(const Element& element)
667     : m_element(element)
668     , m_previousDisplay(element.renderStyle() ? element.renderStyle()->display() : NONE)
669     , m_previousVisibility(element.renderStyle() ? element.renderStyle()->visibility() : HIDDEN)
670     , m_previousImplicitVisibility(WKObservingContentChanges() && WKObservedContentChange() != WKContentVisibilityChange ? elementImplicitVisibility(element) : VISIBLE)
671 {
672 }
673
674 CheckForVisibilityChange::~CheckForVisibilityChange()
675 {
676     if (!WKObservingContentChanges())
677         return;
678     if (m_element.isInUserAgentShadowTree())
679         return;
680     auto* style = m_element.renderStyle();
681     if (!style)
682         return;
683     if ((m_previousDisplay == NONE && style->display() != NONE) || (m_previousVisibility == HIDDEN && style->visibility() != HIDDEN)
684         || (m_previousImplicitVisibility == HIDDEN && elementImplicitVisibility(m_element) == VISIBLE))
685         WKSetObservedContentChange(WKContentVisibilityChange);
686 }
687 #endif
688
689 }