Use smart pointers for creating, adding and removing renderers
[WebKit-https.git] / Source / WebCore / style / RenderTreeUpdaterGeneratedContent.cpp
1 /*
2  * Copyright (C) 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 "RenderTreeUpdaterGeneratedContent.h"
28
29 #include "ContentData.h"
30 #include "InspectorInstrumentation.h"
31 #include "PseudoElement.h"
32 #include "RenderDescendantIterator.h"
33 #include "RenderElement.h"
34 #include "RenderImage.h"
35 #include "RenderQuote.h"
36 #include "RenderTreeUpdater.h"
37 #include "RenderTreeUpdaterListItem.h"
38 #include "StyleTreeResolver.h"
39
40 namespace WebCore {
41
42 RenderTreeUpdater::GeneratedContent::GeneratedContent(RenderTreeUpdater& updater)
43     : m_updater(updater)
44 {
45 }
46
47 void RenderTreeUpdater::GeneratedContent::updateBeforePseudoElement(Element& element)
48 {
49     updatePseudoElement(element, BEFORE);
50 }
51
52 void RenderTreeUpdater::GeneratedContent::updateAfterPseudoElement(Element& element)
53 {
54     updatePseudoElement(element, AFTER);
55 }
56
57 void RenderTreeUpdater::GeneratedContent::updateRemainingQuotes()
58 {
59     if (!m_updater.renderView().hasQuotesNeedingUpdate())
60         return;
61     updateQuotesUpTo(nullptr);
62     m_previousUpdatedQuote = nullptr;
63     m_updater.renderView().setHasQuotesNeedingUpdate(false);
64 }
65
66 void RenderTreeUpdater::GeneratedContent::updateQuotesUpTo(RenderQuote* lastQuote)
67 {
68     auto quoteRenderers = descendantsOfType<RenderQuote>(m_updater.renderView());
69     auto it = m_previousUpdatedQuote ? ++quoteRenderers.at(*m_previousUpdatedQuote) : quoteRenderers.begin();
70     auto end = quoteRenderers.end();
71     for (; it != end; ++it) {
72         auto& quote = *it;
73         // Quote character depends on quote depth so we chain the updates.
74         quote.updateRenderer(m_previousUpdatedQuote);
75         m_previousUpdatedQuote = &quote;
76         if (&quote == lastQuote)
77             return;
78     }
79     ASSERT(!lastQuote);
80 }
81
82 static void createContentRenderers(RenderElement& renderer)
83 {
84     auto& style = renderer.style();
85     ASSERT(style.contentData());
86
87     for (const ContentData* content = style.contentData(); content; content = content->next()) {
88         auto child = content->createContentRenderer(renderer.document(), style);
89         if (renderer.isChildAllowed(*child, style))
90             renderer.addChild(WTFMove(child));
91     }
92 }
93
94 static void updateStyleForContentRenderers(RenderElement& renderer)
95 {
96     for (auto* child = renderer.nextInPreOrder(&renderer); child; child = child->nextInPreOrder(&renderer)) {
97         // We only manage the style for the generated content which must be images or text.
98         if (!is<RenderImage>(*child) && !is<RenderQuote>(*child))
99             continue;
100         auto createdStyle = RenderStyle::createStyleInheritingFromPseudoStyle(renderer.style());
101         downcast<RenderElement>(*child).setStyle(WTFMove(createdStyle));
102     }
103 }
104
105 void RenderTreeUpdater::GeneratedContent::updatePseudoElement(Element& current, PseudoId pseudoId)
106 {
107     PseudoElement* pseudoElement = pseudoId == BEFORE ? current.beforePseudoElement() : current.afterPseudoElement();
108
109     if (auto* renderer = pseudoElement ? pseudoElement->renderer() : nullptr)
110         m_updater.renderTreePosition().invalidateNextSibling(*renderer);
111
112     if (!needsPseudoElement(current, pseudoId)) {
113         if (pseudoElement) {
114             if (pseudoId == BEFORE)
115                 current.clearBeforePseudoElement();
116             else
117                 current.clearAfterPseudoElement();
118         }
119         return;
120     }
121
122     RefPtr<PseudoElement> newPseudoElement;
123     if (!pseudoElement) {
124         newPseudoElement = PseudoElement::create(current, pseudoId);
125         pseudoElement = newPseudoElement.get();
126     }
127
128     auto newStyle = RenderStyle::clonePtr(*current.renderer()->getCachedPseudoStyle(pseudoId, &current.renderer()->style()));
129
130     auto elementUpdate = Style::TreeResolver::createAnimatedElementUpdate(WTFMove(newStyle), *pseudoElement, Style::NoChange);
131
132     if (elementUpdate.change == Style::NoChange)
133         return;
134
135     if (newPseudoElement) {
136         InspectorInstrumentation::pseudoElementCreated(m_updater.m_document.page(), *newPseudoElement);
137         if (pseudoId == BEFORE)
138             current.setBeforePseudoElement(newPseudoElement.releaseNonNull());
139         else
140             current.setAfterPseudoElement(newPseudoElement.releaseNonNull());
141     }
142
143     m_updater.updateElementRenderer(*pseudoElement, elementUpdate);
144
145     auto* pseudoRenderer = pseudoElement->renderer();
146     if (!pseudoRenderer)
147         return;
148
149     if (elementUpdate.change == Style::Detach)
150         createContentRenderers(*pseudoRenderer);
151     else
152         updateStyleForContentRenderers(*pseudoRenderer);
153
154     if (m_updater.renderView().hasQuotesNeedingUpdate()) {
155         for (auto& child : descendantsOfType<RenderQuote>(*pseudoRenderer))
156             updateQuotesUpTo(&child);
157     }
158     if (is<RenderListItem>(*pseudoRenderer))
159         ListItem::updateMarker(downcast<RenderListItem>(*pseudoRenderer));
160 }
161
162 bool RenderTreeUpdater::GeneratedContent::needsPseudoElement(Element& current, PseudoId pseudoId)
163 {
164     if (!current.renderer() || !current.renderer()->canHaveGeneratedChildren())
165         return false;
166     if (current.isPseudoElement())
167         return false;
168     if (!pseudoElementRendererIsNeeded(current.renderer()->getCachedPseudoStyle(pseudoId)))
169         return false;
170     return true;
171 }
172
173 }