b9d207f7dfd3246fe03086c84ca201bcb7b919c9
[WebKit.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 "FullscreenManager.h"
37 #include "HTMLParserIdioms.h"
38 #include "HTMLSlotElement.h"
39 #include "InspectorInstrumentation.h"
40 #include "NodeRenderStyle.h"
41 #include "PseudoElement.h"
42 #include "RenderDescendantIterator.h"
43 #include "RenderFullScreen.h"
44 #include "RenderInline.h"
45 #include "RenderMultiColumnFlow.h"
46 #include "RenderMultiColumnSet.h"
47 #include "RenderTreeUpdaterGeneratedContent.h"
48 #include "RuntimeEnabledFeatures.h"
49 #include "StyleResolver.h"
50 #include "StyleTreeResolver.h"
51 #include <wtf/SystemTracing.h>
52
53 #if PLATFORM(IOS_FAMILY)
54 #include "ContentChangeObserver.h"
55 #endif
56
57 namespace WebCore {
58
59 RenderTreeUpdater::Parent::Parent(ContainerNode& root)
60     : element(is<Document>(root) ? nullptr : downcast<Element>(&root))
61     , renderTreePosition(RenderTreePosition(*root.renderer()))
62 {
63 }
64
65 RenderTreeUpdater::Parent::Parent(Element& element, const Style::ElementUpdates* updates)
66     : element(&element)
67     , updates(updates)
68     , renderTreePosition(element.renderer() ? makeOptional(RenderTreePosition(*element.renderer())) : WTF::nullopt)
69 {
70 }
71
72 RenderTreeUpdater::RenderTreeUpdater(Document& document)
73     : m_document(document)
74     , m_generatedContent(makeUnique<GeneratedContent>(*this))
75     , m_builder(renderView())
76 {
77 }
78
79 RenderTreeUpdater::~RenderTreeUpdater() = default;
80
81 static ContainerNode* findRenderingRoot(ContainerNode& node)
82 {
83     if (node.renderer())
84         return &node;
85     for (auto& ancestor : composedTreeAncestors(node)) {
86         if (ancestor.renderer())
87             return &ancestor;
88         if (!ancestor.hasDisplayContents())
89             return nullptr;
90     }
91     return &node.document();
92 }
93
94 static ListHashSet<ContainerNode*> findRenderingRoots(const Style::Update& update)
95 {
96     ListHashSet<ContainerNode*> renderingRoots;
97     for (auto* root : update.roots()) {
98         auto* renderingRoot = findRenderingRoot(*root);
99         if (!renderingRoot)
100             continue;
101         renderingRoots.add(renderingRoot);
102     }
103     return renderingRoots;
104 }
105
106 void RenderTreeUpdater::commit(std::unique_ptr<const Style::Update> styleUpdate)
107 {
108     ASSERT(&m_document == &styleUpdate->document());
109
110     if (!m_document.shouldCreateRenderers() || !m_document.renderView())
111         return;
112     
113     TraceScope scope(RenderTreeBuildStart, RenderTreeBuildEnd);
114
115     Style::PostResolutionCallbackDisabler callbackDisabler(m_document);
116
117     m_styleUpdate = WTFMove(styleUpdate);
118
119     for (auto* root : findRenderingRoots(*m_styleUpdate))
120         updateRenderTree(*root);
121
122     generatedContent().updateRemainingQuotes();
123
124     m_builder.updateAfterDescendants(renderView());
125
126     m_styleUpdate = nullptr;
127 }
128
129 static bool shouldCreateRenderer(const Element& element, const RenderElement& parentRenderer)
130 {
131     if (!parentRenderer.canHaveChildren() && !(element.isPseudoElement() && parentRenderer.canHaveGeneratedChildren()))
132         return false;
133     if (parentRenderer.element() && !parentRenderer.element()->childShouldCreateRenderer(element))
134         return false;
135     return true;
136 }
137
138 void RenderTreeUpdater::updateRenderTree(ContainerNode& root)
139 {
140     ASSERT(root.renderer());
141     ASSERT(m_parentStack.isEmpty());
142
143     m_parentStack.append(Parent(root));
144
145     auto descendants = composedTreeDescendants(root);
146     auto it = descendants.begin();
147     auto end = descendants.end();
148
149     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=156172
150     it.dropAssertions();
151
152     while (it != end) {
153         popParentsToDepth(it.depth());
154
155         auto& node = *it;
156
157         if (auto* renderer = node.renderer())
158             renderTreePosition().invalidateNextSibling(*renderer);
159         else if (is<Element>(node) && downcast<Element>(node).hasDisplayContents())
160             renderTreePosition().invalidateNextSibling();
161
162         if (is<Text>(node)) {
163             auto& text = downcast<Text>(node);
164             auto* textUpdate = m_styleUpdate->textUpdate(text);
165             bool didCreateParent = parent().updates && parent().updates->update.change == Style::Detach;
166             bool mayNeedUpdateWhitespaceOnlyRenderer = renderingParent().didCreateOrDestroyChildRenderer && text.data().isAllSpecialCharacters<isHTMLSpace>();
167             if (didCreateParent || textUpdate || mayNeedUpdateWhitespaceOnlyRenderer)
168                 updateTextRenderer(text, textUpdate);
169
170             storePreviousRenderer(text);
171             it.traverseNextSkippingChildren();
172             continue;
173         }
174
175         auto& element = downcast<Element>(node);
176
177         auto* elementUpdates = m_styleUpdate->elementUpdates(element);
178
179         // We hop through display: contents elements in findRenderingRoot, so
180         // there may be other updates down the tree.
181         if (!elementUpdates && !element.hasDisplayContents()) {
182             storePreviousRenderer(element);
183             it.traverseNextSkippingChildren();
184             continue;
185         }
186
187         if (elementUpdates)
188             updateElementRenderer(element, elementUpdates->update);
189
190         storePreviousRenderer(element);
191
192         bool mayHaveRenderedDescendants = element.renderer() || (element.hasDisplayContents() && shouldCreateRenderer(element, renderTreePosition().parent()));
193         if (!mayHaveRenderedDescendants) {
194             it.traverseNextSkippingChildren();
195             continue;
196         }
197
198         pushParent(element, elementUpdates);
199
200         it.traverseNext();
201     }
202
203     popParentsToDepth(0);
204 }
205
206 auto RenderTreeUpdater::renderingParent() -> Parent&
207 {
208     for (unsigned i = m_parentStack.size(); i--;) {
209         if (m_parentStack[i].renderTreePosition)
210             return m_parentStack[i];
211     }
212     ASSERT_NOT_REACHED();
213     return m_parentStack.last();
214 }
215
216 RenderTreePosition& RenderTreeUpdater::renderTreePosition()
217 {
218     return *renderingParent().renderTreePosition;
219 }
220
221 void RenderTreeUpdater::pushParent(Element& element, const Style::ElementUpdates* updates)
222 {
223     m_parentStack.append(Parent(element, updates));
224
225     updateBeforeDescendants(element, updates);
226 }
227
228 void RenderTreeUpdater::popParent()
229 {
230     auto& parent = m_parentStack.last();
231     if (parent.element)
232         updateAfterDescendants(*parent.element, parent.updates);
233
234     m_parentStack.removeLast();
235 }
236
237 void RenderTreeUpdater::popParentsToDepth(unsigned depth)
238 {
239     ASSERT(m_parentStack.size() >= depth);
240
241     while (m_parentStack.size() > depth)
242         popParent();
243 }
244
245 void RenderTreeUpdater::updateBeforeDescendants(Element& element, const Style::ElementUpdates* updates)
246 {
247     if (updates)
248         generatedContent().updatePseudoElement(element, updates->beforePseudoElementUpdate, PseudoId::Before);
249 }
250
251 void RenderTreeUpdater::updateAfterDescendants(Element& element, const Style::ElementUpdates* updates)
252 {
253     if (updates)
254         generatedContent().updatePseudoElement(element, updates->afterPseudoElementUpdate, PseudoId::After);
255
256     auto* renderer = element.renderer();
257     if (!renderer)
258         return;
259
260     m_builder.updateAfterDescendants(*renderer);
261
262     if (element.hasCustomStyleResolveCallbacks() && updates && updates->update.change == Style::Detach)
263         element.didAttachRenderers();
264 }
265
266 static bool pseudoStyleCacheIsInvalid(RenderElement* renderer, RenderStyle* newStyle)
267 {
268     const RenderStyle& currentStyle = renderer->style();
269
270     const PseudoStyleCache* pseudoStyleCache = currentStyle.cachedPseudoStyles();
271     if (!pseudoStyleCache)
272         return false;
273
274     for (auto& cache : *pseudoStyleCache) {
275         PseudoId pseudoId = cache->styleType();
276         std::unique_ptr<RenderStyle> newPseudoStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle);
277         if (!newPseudoStyle)
278             return true;
279         if (*newPseudoStyle != *cache) {
280             newStyle->addCachedPseudoStyle(WTFMove(newPseudoStyle));
281             return true;
282         }
283     }
284     return false;
285 }
286
287 void RenderTreeUpdater::updateRendererStyle(RenderElement& renderer, RenderStyle&& newStyle, StyleDifference minimalStyleDifference)
288 {
289     auto oldStyle = RenderStyle::clone(renderer.style());
290     renderer.setStyle(WTFMove(newStyle), minimalStyleDifference);
291     m_builder.normalizeTreeAfterStyleChange(renderer, oldStyle);
292 }
293
294 void RenderTreeUpdater::updateElementRenderer(Element& element, const Style::ElementUpdate& update)
295 {
296 #if PLATFORM(IOS_FAMILY)
297     ContentChangeObserver::StyleChangeScope observingScope(m_document, element);
298 #endif
299
300     bool shouldTearDownRenderers = update.change == Style::Detach && (element.renderer() || element.hasDisplayContents());
301     if (shouldTearDownRenderers) {
302         if (!element.renderer()) {
303             // We may be tearing down a descendant renderer cached in renderTreePosition.
304             renderTreePosition().invalidateNextSibling();
305         }
306
307         // display:none cancels animations.
308         auto teardownType = update.style->display() == DisplayType::None ? TeardownType::RendererUpdateCancelingAnimations : TeardownType::RendererUpdate;
309         tearDownRenderers(element, teardownType, m_builder);
310
311         renderingParent().didCreateOrDestroyChildRenderer = true;
312     }
313
314     bool hasDisplayContents = update.style->display() == DisplayType::Contents;
315     if (hasDisplayContents)
316         element.storeDisplayContentsStyle(RenderStyle::clonePtr(*update.style));
317     else
318         element.resetComputedStyle();
319
320     bool shouldCreateNewRenderer = !element.renderer() && !hasDisplayContents;
321     if (shouldCreateNewRenderer) {
322         if (element.hasCustomStyleResolveCallbacks())
323             element.willAttachRenderers();
324         createRenderer(element, RenderStyle::clone(*update.style));
325
326         renderingParent().didCreateOrDestroyChildRenderer = true;
327         return;
328     }
329
330     if (!element.renderer())
331         return;
332     auto& renderer = *element.renderer();
333
334     if (update.recompositeLayer) {
335         updateRendererStyle(renderer, RenderStyle::clone(*update.style), StyleDifference::RecompositeLayer);
336         return;
337     }
338
339     if (update.change == Style::NoChange) {
340         if (pseudoStyleCacheIsInvalid(&renderer, update.style.get())) {
341             updateRendererStyle(renderer, RenderStyle::clone(*update.style), StyleDifference::Equal);
342             return;
343         }
344         return;
345     }
346
347     updateRendererStyle(renderer, RenderStyle::clone(*update.style), StyleDifference::Equal);
348 }
349
350 void RenderTreeUpdater::createRenderer(Element& element, RenderStyle&& style)
351 {
352     auto computeInsertionPosition = [this, &element] () {
353         renderTreePosition().computeNextSibling(element);
354         return renderTreePosition();
355     };
356     
357     if (!shouldCreateRenderer(element, renderTreePosition().parent()))
358         return;
359
360     if (!element.rendererIsNeeded(style))
361         return;
362
363     RenderTreePosition insertionPosition = computeInsertionPosition();
364     auto newRenderer = element.createElementRenderer(WTFMove(style), insertionPosition);
365     if (!newRenderer)
366         return;
367
368     if (!insertionPosition.parent().isChildAllowed(*newRenderer, newRenderer->style()))
369         return;
370
371     element.setRenderer(newRenderer.get());
372
373     newRenderer->initializeStyle();
374
375 #if ENABLE(FULLSCREEN_API)
376     if (m_document.fullscreenManager().isFullscreen() && m_document.fullscreenManager().currentFullscreenElement() == &element) {
377         newRenderer = RenderFullScreen::wrapNewRenderer(m_builder, WTFMove(newRenderer), insertionPosition.parent(), m_document);
378         if (!newRenderer)
379             return;
380     }
381 #endif
382
383     m_builder.attach(insertionPosition, WTFMove(newRenderer));
384
385     if (AXObjectCache* cache = m_document.axObjectCache())
386         cache->updateCacheAfterNodeIsAttached(&element);
387 }
388
389 bool RenderTreeUpdater::textRendererIsNeeded(const Text& textNode)
390 {
391     auto& renderingParent = this->renderingParent();
392     auto& parentRenderer = renderingParent.renderTreePosition->parent();
393     if (!parentRenderer.canHaveChildren())
394         return false;
395     if (parentRenderer.element() && !parentRenderer.element()->childShouldCreateRenderer(textNode))
396         return false;
397     if (textNode.isEditingText())
398         return true;
399     if (!textNode.length())
400         return false;
401     if (!textNode.data().isAllSpecialCharacters<isHTMLSpace>())
402         return true;
403     if (is<RenderText>(renderingParent.previousChildRenderer))
404         return true;
405     // This text node has nothing but white space. We may still need a renderer in some cases.
406     if (parentRenderer.isTable() || parentRenderer.isTableRow() || parentRenderer.isTableSection() || parentRenderer.isRenderTableCol() || parentRenderer.isFrameSet())
407         return false;
408     if (parentRenderer.isFlexibleBox() && !parentRenderer.isRenderButton())
409         return false;
410     if (parentRenderer.style().preserveNewline()) // pre/pre-wrap/pre-line always make renderers.
411         return true;
412
413     auto* previousRenderer = renderingParent.previousChildRenderer;
414     if (previousRenderer && previousRenderer->isBR()) // <span><br/> <br/></span>
415         return false;
416
417     if (parentRenderer.isRenderInline()) {
418         // <span><div/> <div/></span>
419         if (previousRenderer && !previousRenderer->isInline())
420             return false;
421     } else {
422         if (parentRenderer.isRenderBlock() && !parentRenderer.childrenInline() && (!previousRenderer || !previousRenderer->isInline()))
423             return false;
424         
425         RenderObject* first = parentRenderer.firstChild();
426         while (first && first->isFloatingOrOutOfFlowPositioned())
427             first = first->nextSibling();
428         RenderObject* nextRenderer = textNode.renderer() ? textNode.renderer() :  renderTreePosition().nextSiblingRenderer(textNode);
429         if (!first || nextRenderer == first) {
430             // Whitespace at the start of a block just goes away. Don't even make a render object for this text.
431             return false;
432         }
433     }
434     return true;
435 }
436
437 void RenderTreeUpdater::createTextRenderer(Text& textNode, const Style::TextUpdate* textUpdate)
438 {
439     ASSERT(!textNode.renderer());
440
441     auto& renderTreePosition = this->renderTreePosition();
442     auto textRenderer = textNode.createTextRenderer(renderTreePosition.parent().style());
443
444     renderTreePosition.computeNextSibling(textNode);
445
446     if (!renderTreePosition.parent().isChildAllowed(*textRenderer, renderTreePosition.parent().style()))
447         return;
448
449     textNode.setRenderer(textRenderer.get());
450
451     if (textUpdate && textUpdate->inheritedDisplayContentsStyle && *textUpdate->inheritedDisplayContentsStyle) {
452         // Wrap text renderer into anonymous inline so we can give it a style.
453         // This is to support "<div style='display:contents;color:green'>text</div>" type cases
454         auto newDisplayContentsAnonymousWrapper = WebCore::createRenderer<RenderInline>(textNode.document(), RenderStyle::clone(**textUpdate->inheritedDisplayContentsStyle));
455         newDisplayContentsAnonymousWrapper->initializeStyle();
456         auto& displayContentsAnonymousWrapper = *newDisplayContentsAnonymousWrapper;
457         m_builder.attach(renderTreePosition, WTFMove(newDisplayContentsAnonymousWrapper));
458
459         textRenderer->setInlineWrapperForDisplayContents(&displayContentsAnonymousWrapper);
460         m_builder.attach(displayContentsAnonymousWrapper, WTFMove(textRenderer));
461         return;
462     }
463
464     m_builder.attach(renderTreePosition, WTFMove(textRenderer));
465 }
466
467 void RenderTreeUpdater::updateTextRenderer(Text& text, const Style::TextUpdate* textUpdate)
468 {
469     auto* existingRenderer = text.renderer();
470     bool needsRenderer = textRendererIsNeeded(text);
471
472     if (existingRenderer && textUpdate && textUpdate->inheritedDisplayContentsStyle) {
473         if (existingRenderer->inlineWrapperForDisplayContents() || *textUpdate->inheritedDisplayContentsStyle) {
474             // FIXME: We could update without teardown.
475             tearDownTextRenderer(text, m_builder);
476             existingRenderer = nullptr;
477         }
478     }
479
480     if (existingRenderer) {
481         if (needsRenderer) {
482             if (textUpdate)
483                 existingRenderer->setTextWithOffset(text.data(), textUpdate->offset, textUpdate->length);
484             return;
485         }
486         tearDownTextRenderer(text, m_builder);
487         renderingParent().didCreateOrDestroyChildRenderer = true;
488         return;
489     }
490     if (!needsRenderer)
491         return;
492     createTextRenderer(text, textUpdate);
493     renderingParent().didCreateOrDestroyChildRenderer = true;
494 }
495
496 void RenderTreeUpdater::storePreviousRenderer(Node& node)
497 {
498     auto* renderer = node.renderer();
499     if (!renderer)
500         return;
501     ASSERT(renderingParent().previousChildRenderer != renderer);
502     renderingParent().previousChildRenderer = renderer;
503 }
504
505 void RenderTreeUpdater::tearDownRenderers(Element& root)
506 {
507     auto* view = root.document().renderView();
508     if (!view)
509         return;
510     RenderTreeBuilder builder(*view);
511     tearDownRenderers(root, TeardownType::Full, builder);
512 }
513
514 void RenderTreeUpdater::tearDownRenderer(Text& text)
515 {
516     auto* view = text.document().renderView();
517     if (!view)
518         return;
519     RenderTreeBuilder builder(*view);
520     tearDownTextRenderer(text, builder);
521 }
522
523 void RenderTreeUpdater::tearDownRenderers(Element& root, TeardownType teardownType, RenderTreeBuilder& builder)
524 {
525     WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
526
527     Vector<Element*, 30> teardownStack;
528
529     auto push = [&] (Element& element) {
530         if (element.hasCustomStyleResolveCallbacks())
531             element.willDetachRenderers();
532         teardownStack.append(&element);
533     };
534
535     auto& document = root.document();
536     auto* timeline = document.existingTimeline();
537     auto& animationController = document.frame()->animation();    
538
539     auto pop = [&] (unsigned depth) {
540         while (teardownStack.size() > depth) {
541             auto& element = *teardownStack.takeLast();
542
543             if (teardownType == TeardownType::Full || teardownType == TeardownType::RendererUpdateCancelingAnimations) {
544                 if (timeline) {
545                     if (document.renderTreeBeingDestroyed())
546                         timeline->elementWasRemoved(element);
547                     else if (teardownType == TeardownType::RendererUpdateCancelingAnimations)
548                         timeline->cancelDeclarativeAnimationsForElement(element);
549                 }
550                 animationController.cancelAnimations(element);
551             }
552
553             if (teardownType == TeardownType::Full)
554                 element.clearHoverAndActiveStatusBeforeDetachingRenderer();
555
556             GeneratedContent::removeBeforePseudoElement(element, builder);
557             GeneratedContent::removeAfterPseudoElement(element, builder);
558
559             if (auto* renderer = element.renderer()) {
560                 builder.destroyAndCleanUpAnonymousWrappers(*renderer);
561                 element.setRenderer(nullptr);
562             }
563
564             // Make sure we don't leave any renderers behind in nodes outside the composed tree.
565             if (element.shadowRoot())
566                 tearDownLeftoverShadowHostChildren(element, builder);
567
568             if (element.hasCustomStyleResolveCallbacks())
569                 element.didDetachRenderers();
570         }
571     };
572
573     push(root);
574
575     auto descendants = composedTreeDescendants(root);
576     for (auto it = descendants.begin(), end = descendants.end(); it != end; ++it) {
577         pop(it.depth());
578
579         if (is<Text>(*it)) {
580             tearDownTextRenderer(downcast<Text>(*it), builder);
581             continue;
582         }
583
584         push(downcast<Element>(*it));
585     }
586
587     pop(0);
588
589     tearDownLeftoverPaginationRenderersIfNeeded(root, builder);
590 }
591
592 void RenderTreeUpdater::tearDownTextRenderer(Text& text, RenderTreeBuilder& builder)
593 {
594     auto* renderer = text.renderer();
595     if (!renderer)
596         return;
597     builder.destroyAndCleanUpAnonymousWrappers(*renderer);
598     text.setRenderer(nullptr);
599 }
600
601 void RenderTreeUpdater::tearDownLeftoverPaginationRenderersIfNeeded(Element& root, RenderTreeBuilder& builder)
602 {
603     if (&root != root.document().documentElement())
604         return;
605     for (auto* child = root.document().renderView()->firstChild(); child;) {
606         auto* nextSibling = child->nextSibling();
607         if (is<RenderMultiColumnFlow>(*child) || is<RenderMultiColumnSet>(*child))
608             builder.destroyAndCleanUpAnonymousWrappers(*child);
609         child = nextSibling;
610     }
611 }
612
613 void RenderTreeUpdater::tearDownLeftoverShadowHostChildren(Element& host, RenderTreeBuilder& builder)
614 {
615     for (auto* hostChild = host.firstChild(); hostChild; hostChild = hostChild->nextSibling()) {
616         if (!hostChild->renderer())
617             continue;
618         if (is<Text>(*hostChild)) {
619             tearDownTextRenderer(downcast<Text>(*hostChild), builder);
620             continue;
621         }
622         if (is<Element>(*hostChild))
623             tearDownRenderers(downcast<Element>(*hostChild), TeardownType::Full, builder);
624     }
625 }
626
627 RenderView& RenderTreeUpdater::renderView()
628 {
629     return *m_document.renderView();
630 }
631
632 }