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