0d1424cf0afcc3a82d1c23dec6cea1d0026e8f4d
[WebKit-https.git] / Source / WebCore / style / RenderTreeUpdater.cpp
1 /*
2  * Copyright (C) 2016 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 "ComposedTreeAncestorIterator.h"
31 #include "ComposedTreeIterator.h"
32 #include "Document.h"
33 #include "Element.h"
34 #include "FlowThreadController.h"
35 #include "HTMLSlotElement.h"
36 #include "InspectorInstrumentation.h"
37 #include "PseudoElement.h"
38 #include "RenderFullScreen.h"
39 #include "RenderNamedFlowThread.h"
40 #include "StyleResolver.h"
41 #include "StyleTreeResolver.h"
42
43 namespace WebCore {
44
45 RenderTreeUpdater::Parent::Parent(ContainerNode& root)
46     : element(is<Document>(root) ? nullptr : downcast<Element>(&root))
47     , renderTreePosition(RenderTreePosition(*root.renderer()))
48 {
49 }
50
51 RenderTreeUpdater::Parent::Parent(Element& element, Style::Change styleChange)
52     : element(&element)
53     , styleChange(styleChange)
54     , renderTreePosition(element.renderer() ? makeOptional(RenderTreePosition(*element.renderer())) : Nullopt)
55 {
56 }
57
58
59 RenderTreeUpdater::RenderTreeUpdater(Document& document)
60     : m_document(document)
61 {
62 }
63
64 static ContainerNode* findRenderingRoot(ContainerNode& node)
65 {
66     if (node.renderer())
67         return &node;
68     for (auto& ancestor : composedTreeAncestors(node)) {
69         if (ancestor.renderer())
70             return &ancestor;
71         if (!hasImplicitDisplayContents(ancestor))
72             return nullptr;
73     }
74     return &node.document();
75 }
76
77 static ListHashSet<ContainerNode*> findRenderingRoots(const Style::Update& update)
78 {
79     ListHashSet<ContainerNode*> renderingRoots;
80     for (auto* root : update.roots()) {
81         auto* renderingRoot = findRenderingRoot(*root);
82         if (!renderingRoot)
83             continue;
84         renderingRoots.add(renderingRoot);
85     }
86     return renderingRoots;
87 }
88
89 void RenderTreeUpdater::commit(std::unique_ptr<const Style::Update> styleUpdate)
90 {
91     ASSERT(&m_document == &styleUpdate->document());
92
93     if (!m_document.shouldCreateRenderers() || !m_document.renderView())
94         return;
95
96     m_styleUpdate = WTFMove(styleUpdate);
97
98     for (auto* root : findRenderingRoots(*m_styleUpdate))
99         updateRenderTree(*root);
100
101     m_styleUpdate = nullptr;
102 }
103
104 static bool shouldCreateRenderer(const Element& element, const RenderElement& parentRenderer)
105 {
106     if (!parentRenderer.canHaveChildren() && !(element.isPseudoElement() && parentRenderer.canHaveGeneratedChildren()))
107         return false;
108     if (parentRenderer.element() && !parentRenderer.element()->childShouldCreateRenderer(element))
109         return false;
110     return true;
111 }
112
113 void RenderTreeUpdater::updateRenderTree(ContainerNode& root)
114 {
115     ASSERT(root.renderer());
116     ASSERT(m_parentStack.isEmpty());
117
118     m_parentStack.append(Parent(root));
119
120     auto descendants = composedTreeDescendants(root);
121     auto it = descendants.begin();
122     auto end = descendants.end();
123
124     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=156172
125     it.dropAssertions();
126
127     while (it != end) {
128         popParentsToDepth(it.depth());
129
130         auto& node = *it;
131
132         if (auto* renderer = node.renderer())
133             renderTreePosition().invalidateNextSibling(*renderer);
134
135         if (is<Text>(node)) {
136             auto& text = downcast<Text>(node);
137             if (parent().styleChange == Style::Detach || m_styleUpdate->textUpdate(text) || m_invalidatedWhitespaceOnlyTextSiblings.contains(&text))
138                 updateTextRenderer(text);
139
140             it.traverseNextSkippingChildren();
141             continue;
142         }
143
144         auto& element = downcast<Element>(node);
145
146         auto* elementUpdate = m_styleUpdate->elementUpdate(element);
147         if (!elementUpdate) {
148             it.traverseNextSkippingChildren();
149             continue;
150         }
151
152         updateElementRenderer(element, *elementUpdate);
153
154         bool mayHaveRenderedDescendants = element.renderer() || (hasImplicitDisplayContents(element) && shouldCreateRenderer(element, renderTreePosition().parent()));
155         if (!mayHaveRenderedDescendants) {
156             it.traverseNextSkippingChildren();
157             continue;
158         }
159
160         pushParent(element, elementUpdate ? elementUpdate->change : Style::NoChange);
161
162         it.traverseNext();
163     }
164
165     popParentsToDepth(0);
166
167     m_invalidatedWhitespaceOnlyTextSiblings.clear();
168 }
169
170 RenderTreePosition& RenderTreeUpdater::renderTreePosition()
171 {
172     for (unsigned i = m_parentStack.size(); i; --i) {
173         if (auto& position = m_parentStack[i - 1].renderTreePosition)
174             return *position;
175     }
176     ASSERT_NOT_REACHED();
177     return *m_parentStack.last().renderTreePosition;
178 }
179
180 void RenderTreeUpdater::pushParent(Element& element, Style::Change changeType)
181 {
182     m_parentStack.append(Parent(element, changeType));
183
184     updateBeforeOrAfterPseudoElement(element, BEFORE);
185 }
186
187 void RenderTreeUpdater::popParent()
188 {
189     auto& parent = m_parentStack.last();
190
191     if (parent.element) {
192         updateBeforeOrAfterPseudoElement(*parent.element, AFTER);
193
194         if (parent.element->hasCustomStyleResolveCallbacks() && parent.styleChange == Style::Detach && parent.element->renderer())
195             parent.element->didAttachRenderers();
196     }
197     m_parentStack.removeLast();
198 }
199
200 void RenderTreeUpdater::popParentsToDepth(unsigned depth)
201 {
202     ASSERT(m_parentStack.size() >= depth);
203
204     while (m_parentStack.size() > depth)
205         popParent();
206 }
207
208 static bool pseudoStyleCacheIsInvalid(RenderElement* renderer, RenderStyle* newStyle)
209 {
210     const RenderStyle& currentStyle = renderer->style();
211
212     const PseudoStyleCache* pseudoStyleCache = currentStyle.cachedPseudoStyles();
213     if (!pseudoStyleCache)
214         return false;
215
216     for (auto& cache : *pseudoStyleCache) {
217         RefPtr<RenderStyle> newPseudoStyle;
218         PseudoId pseudoId = cache->styleType();
219         if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
220             newPseudoStyle = renderer->uncachedFirstLineStyle(newStyle);
221         else
222             newPseudoStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle);
223         if (!newPseudoStyle)
224             return true;
225         if (*newPseudoStyle != *cache) {
226             if (pseudoId < FIRST_INTERNAL_PSEUDOID)
227                 newStyle->setHasPseudoStyle(pseudoId);
228             newStyle->addCachedPseudoStyle(newPseudoStyle);
229             if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
230                 // FIXME: We should do an actual diff to determine whether a repaint vs. layout
231                 // is needed, but for now just assume a layout will be required. The diff code
232                 // in RenderObject::setStyle would need to be factored out so that it could be reused.
233                 renderer->setNeedsLayoutAndPrefWidthsRecalc();
234             }
235             return true;
236         }
237     }
238     return false;
239 }
240
241 void RenderTreeUpdater::updateElementRenderer(Element& element, const Style::ElementUpdate& update)
242 {
243     bool shouldTearDownRenderers = update.change == Style::Detach && (element.renderer() || element.isNamedFlowContentNode());
244     if (shouldTearDownRenderers)
245         detachRenderTree(element, Style::ReattachDetach);
246
247     bool shouldCreateNewRenderer = !element.renderer() && update.style && !hasImplicitDisplayContents(element);
248     if (shouldCreateNewRenderer) {
249         if (element.hasCustomStyleResolveCallbacks())
250             element.willAttachRenderers();
251         createRenderer(element, *update.style);
252         invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(element);
253         return;
254     }
255
256     if (!element.renderer())
257         return;
258     auto& renderer = *element.renderer();
259
260     if (update.isSynthetic) {
261         renderer.setStyle(*update.style, StyleDifferenceRecompositeLayer);
262         return;
263     }
264
265     if (update.change == Style::NoChange) {
266         if (pseudoStyleCacheIsInvalid(&renderer, update.style.get()) || (parent().styleChange == Style::Force && renderer.requiresForcedStyleRecalcPropagation())) {
267             renderer.setStyle(*update.style, StyleDifferenceEqual);
268             return;
269         }
270         return;
271     }
272
273     renderer.setStyle(*update.style, StyleDifferenceEqual);
274 }
275
276 #if ENABLE(CSS_REGIONS)
277 static RenderNamedFlowThread* moveToFlowThreadIfNeeded(Element& element, const RenderStyle& style)
278 {
279     if (!element.shouldMoveToFlowThread(style))
280         return nullptr;
281
282     FlowThreadController& flowThreadController = element.document().renderView()->flowThreadController();
283     RenderNamedFlowThread& parentFlowRenderer = flowThreadController.ensureRenderFlowThreadWithName(style.flowThread());
284     flowThreadController.registerNamedFlowContentElement(element, parentFlowRenderer);
285     return &parentFlowRenderer;
286 }
287 #endif
288
289 void RenderTreeUpdater::createRenderer(Element& element, RenderStyle& style)
290 {
291     if (!shouldCreateRenderer(element, renderTreePosition().parent()))
292         return;
293
294     RenderNamedFlowThread* parentFlowRenderer = nullptr;
295 #if ENABLE(CSS_REGIONS)
296     parentFlowRenderer = moveToFlowThreadIfNeeded(element, style);
297 #endif
298
299     if (!element.rendererIsNeeded(style))
300         return;
301
302     renderTreePosition().computeNextSibling(element);
303
304     RenderTreePosition insertionPosition = parentFlowRenderer
305         ? RenderTreePosition(*parentFlowRenderer, parentFlowRenderer->nextRendererForElement(element))
306         : renderTreePosition();
307
308     RenderElement* newRenderer = element.createElementRenderer(style, insertionPosition).leakPtr();
309     if (!newRenderer)
310         return;
311     if (!insertionPosition.canInsert(*newRenderer)) {
312         newRenderer->destroy();
313         return;
314     }
315
316     // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
317     // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
318     newRenderer->setFlowThreadState(insertionPosition.parent().flowThreadState());
319
320     element.setRenderer(newRenderer);
321
322     Ref<RenderStyle> animatedStyle = newRenderer->style();
323     newRenderer->animation().updateAnimations(*newRenderer, animatedStyle, animatedStyle);
324     newRenderer->setStyleInternal(WTFMove(animatedStyle));
325
326     newRenderer->initializeStyle();
327
328 #if ENABLE(FULLSCREEN_API)
329     if (m_document.webkitIsFullScreen() && m_document.webkitCurrentFullScreenElement() == &element) {
330         newRenderer = RenderFullScreen::wrapRenderer(newRenderer, &insertionPosition.parent(), m_document);
331         if (!newRenderer)
332             return;
333     }
334 #endif
335     // Note: Adding newRenderer instead of renderer(). renderer() may be a child of newRenderer.
336     insertionPosition.insert(*newRenderer);
337
338     if (AXObjectCache* cache = m_document.axObjectCache())
339         cache->updateCacheAfterNodeIsAttached(&element);
340 }
341
342 static bool textRendererIsNeeded(const Text& textNode, const RenderTreePosition& renderTreePosition)
343 {
344     const RenderElement& parentRenderer = renderTreePosition.parent();
345     if (!parentRenderer.canHaveChildren())
346         return false;
347     if (parentRenderer.element() && !parentRenderer.element()->childShouldCreateRenderer(textNode))
348         return false;
349     if (textNode.isEditingText())
350         return true;
351     if (!textNode.length())
352         return false;
353     if (!textNode.containsOnlyWhitespace())
354         return true;
355     // This text node has nothing but white space. We may still need a renderer in some cases.
356     if (parentRenderer.isTable() || parentRenderer.isTableRow() || parentRenderer.isTableSection() || parentRenderer.isRenderTableCol() || parentRenderer.isFrameSet())
357         return false;
358     if (parentRenderer.style().preserveNewline()) // pre/pre-wrap/pre-line always make renderers.
359         return true;
360
361     RenderObject* previousRenderer = renderTreePosition.previousSiblingRenderer(textNode);
362     if (previousRenderer && previousRenderer->isBR()) // <span><br/> <br/></span>
363         return false;
364
365     if (parentRenderer.isRenderInline()) {
366         // <span><div/> <div/></span>
367         if (previousRenderer && !previousRenderer->isInline())
368             return false;
369     } else {
370         if (parentRenderer.isRenderBlock() && !parentRenderer.childrenInline() && (!previousRenderer || !previousRenderer->isInline()))
371             return false;
372         
373         RenderObject* first = parentRenderer.firstChild();
374         while (first && first->isFloatingOrOutOfFlowPositioned())
375             first = first->nextSibling();
376         RenderObject* nextRenderer = renderTreePosition.nextSiblingRenderer(textNode);
377         if (!first || nextRenderer == first) {
378             // Whitespace at the start of a block just goes away. Don't even make a render object for this text.
379             return false;
380         }
381     }
382     return true;
383 }
384
385 static void createTextRenderer(Text& textNode, RenderTreePosition& renderTreePosition)
386 {
387     ASSERT(!textNode.renderer());
388
389     auto newRenderer = textNode.createTextRenderer(renderTreePosition.parent().style());
390     ASSERT(newRenderer);
391
392     renderTreePosition.computeNextSibling(textNode);
393
394     if (!renderTreePosition.canInsert(*newRenderer))
395         return;
396
397     // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
398     // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
399     newRenderer->setFlowThreadState(renderTreePosition.parent().flowThreadState());
400
401     textNode.setRenderer(newRenderer.get());
402     renderTreePosition.insert(*newRenderer.leakPtr());
403 }
404
405 void RenderTreeUpdater::updateTextRenderer(Text& text)
406 {
407     bool hasRenderer = text.renderer();
408     bool needsRenderer = textRendererIsNeeded(text, renderTreePosition());
409     if (hasRenderer) {
410         if (needsRenderer)
411             return;
412         Style::detachTextRenderer(text);
413         invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(text);
414         return;
415     }
416     if (!needsRenderer)
417         return;
418     createTextRenderer(text, renderTreePosition());
419     invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(text);
420 }
421
422 void RenderTreeUpdater::invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(Node& current)
423 {
424     // FIXME: This needs to traverse in composed tree order.
425
426     // This function finds sibling text renderers where the results of textRendererIsNeeded may have changed as a result of
427     // the current node gaining or losing the renderer. This can only affect white space text nodes.
428     for (Node* sibling = current.nextSibling(); sibling; sibling = sibling->nextSibling()) {
429         if (is<Element>(*sibling)) {
430             if (m_styleUpdate->elementUpdate(downcast<Element>(*sibling)))
431                 return;
432             // Text renderers beyond rendered elements can't be affected.
433             if (!sibling->renderer() || RenderTreePosition::isRendererReparented(*sibling->renderer()))
434                 continue;
435             return;
436         }
437         if (!is<Text>(*sibling))
438             continue;
439         Text& textSibling = downcast<Text>(*sibling);
440         if (m_styleUpdate->textUpdate(textSibling))
441             return;
442         if (!textSibling.containsOnlyWhitespace())
443             continue;
444         m_invalidatedWhitespaceOnlyTextSiblings.add(&textSibling);
445     }
446 }
447
448 static bool needsPseudoElement(Element& current, PseudoId pseudoId)
449 {
450     if (!current.renderer() || !current.renderer()->canHaveGeneratedChildren())
451         return false;
452     if (current.isPseudoElement())
453         return false;
454     if (!pseudoElementRendererIsNeeded(current.renderer()->getCachedPseudoStyle(pseudoId)))
455         return false;
456     return true;
457 }
458
459 void RenderTreeUpdater::updateBeforeOrAfterPseudoElement(Element& current, PseudoId pseudoId)
460 {
461     PseudoElement* pseudoElement = pseudoId == BEFORE ? current.beforePseudoElement() : current.afterPseudoElement();
462
463     auto* renderer = pseudoElement ? pseudoElement->renderer() : nullptr;
464     if (renderer)
465         renderTreePosition().invalidateNextSibling(*renderer);
466
467     bool needsPseudoElement = WebCore::needsPseudoElement(current, pseudoId);
468     if (!needsPseudoElement) {
469         if (pseudoElement) {
470             if (pseudoId == BEFORE)
471                 current.clearBeforePseudoElement();
472             else
473                 current.clearAfterPseudoElement();
474         }
475         return;
476     }
477
478     Style::ElementUpdate elementUpdate;
479
480     Ref<RenderStyle> newStyle = *current.renderer()->getCachedPseudoStyle(pseudoId, &current.renderer()->style());
481
482     if (renderer && m_document.frame()->animation().updateAnimations(*renderer, newStyle, newStyle))
483         elementUpdate.isSynthetic = true;
484
485     elementUpdate.change = renderer ? Style::determineChange(renderer->style(), newStyle) : Style::Detach;
486     elementUpdate.style = WTFMove(newStyle);
487
488     if (elementUpdate.change == Style::NoChange)
489         return;
490
491     if (!pseudoElement) {
492         auto newPseudoElement = PseudoElement::create(current, pseudoId);
493         pseudoElement = newPseudoElement.ptr();
494         InspectorInstrumentation::pseudoElementCreated(m_document.page(), newPseudoElement);
495         if (pseudoId == BEFORE)
496             current.setBeforePseudoElement(WTFMove(newPseudoElement));
497         else
498             current.setAfterPseudoElement(WTFMove(newPseudoElement));
499     }
500
501     updateElementRenderer(*pseudoElement, elementUpdate);
502
503     if (elementUpdate.change == Style::Detach)
504         pseudoElement->didAttachRenderers();
505     else
506         pseudoElement->didRecalcStyle(elementUpdate.change);
507 }
508
509 }