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