Introduce RenderTreeBuilder
[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::updateRemainingQuotes()
48 {
49     if (!m_updater.renderView().hasQuotesNeedingUpdate())
50         return;
51     updateQuotesUpTo(nullptr);
52     m_previousUpdatedQuote = nullptr;
53     m_updater.renderView().setHasQuotesNeedingUpdate(false);
54 }
55
56 void RenderTreeUpdater::GeneratedContent::updateQuotesUpTo(RenderQuote* lastQuote)
57 {
58     auto quoteRenderers = descendantsOfType<RenderQuote>(m_updater.renderView());
59     auto it = m_previousUpdatedQuote ? ++quoteRenderers.at(*m_previousUpdatedQuote) : quoteRenderers.begin();
60     auto end = quoteRenderers.end();
61     for (; it != end; ++it) {
62         auto& quote = *it;
63         // Quote character depends on quote depth so we chain the updates.
64         quote.updateRenderer(m_updater.m_builder, m_previousUpdatedQuote);
65         m_previousUpdatedQuote = &quote;
66         if (&quote == lastQuote)
67             return;
68     }
69     ASSERT(!lastQuote);
70 }
71
72 static void createContentRenderers(RenderTreeBuilder& builder, RenderElement& pseudoRenderer, const RenderStyle& style)
73 {
74     ASSERT(style.contentData());
75
76     for (const ContentData* content = style.contentData(); content; content = content->next()) {
77         auto child = content->createContentRenderer(pseudoRenderer.document(), style);
78         if (pseudoRenderer.isChildAllowed(*child, style))
79             builder.insertChild(pseudoRenderer, WTFMove(child));
80     }
81 }
82
83 static void updateStyleForContentRenderers(RenderElement& pseudoRenderer, const RenderStyle& style)
84 {
85     for (auto& contentRenderer : descendantsOfType<RenderElement>(pseudoRenderer)) {
86         // We only manage the style for the generated content which must be images or text.
87         if (!is<RenderImage>(contentRenderer) && !is<RenderQuote>(contentRenderer))
88             continue;
89         contentRenderer.setStyle(RenderStyle::createStyleInheritingFromPseudoStyle(style));
90     }
91 }
92
93 void RenderTreeUpdater::GeneratedContent::updatePseudoElement(Element& current, const std::optional<Style::ElementUpdate>& update, PseudoId pseudoId)
94 {
95     PseudoElement* pseudoElement = pseudoId == BEFORE ? current.beforePseudoElement() : current.afterPseudoElement();
96
97     if (auto* renderer = pseudoElement ? pseudoElement->renderer() : nullptr)
98         m_updater.renderTreePosition().invalidateNextSibling(*renderer);
99
100     if (!needsPseudoElement(update)) {
101         if (pseudoElement) {
102             if (pseudoId == BEFORE)
103                 removeBeforePseudoElement(current);
104             else
105                 removeAfterPseudoElement(current);
106         }
107         return;
108     }
109
110     RefPtr<PseudoElement> newPseudoElement;
111     if (!pseudoElement) {
112         newPseudoElement = PseudoElement::create(current, pseudoId);
113         pseudoElement = newPseudoElement.get();
114     }
115
116     if (update->change == Style::NoChange)
117         return;
118
119     if (newPseudoElement) {
120         if (pseudoId == BEFORE)
121             current.setBeforePseudoElement(newPseudoElement.releaseNonNull());
122         else
123             current.setAfterPseudoElement(newPseudoElement.releaseNonNull());
124     }
125
126     if (update->style->display() == CONTENTS) {
127         // For display:contents we create an inline wrapper that inherits its
128         // style from the display:contents style.
129         auto contentsStyle = RenderStyle::createPtr();
130         contentsStyle->setStyleType(pseudoId);
131         contentsStyle->inheritFrom(*update->style);
132         contentsStyle->copyContentFrom(*update->style);
133
134         Style::ElementUpdate contentsUpdate { WTFMove(contentsStyle), update->change, update->recompositeLayer };
135         m_updater.updateElementRenderer(*pseudoElement, contentsUpdate);
136         pseudoElement->storeDisplayContentsStyle(RenderStyle::clonePtr(*update->style));
137     } else {
138         m_updater.updateElementRenderer(*pseudoElement, *update);
139         ASSERT(!pseudoElement->hasDisplayContents());
140     }
141
142     auto* pseudoElementRenderer = pseudoElement->renderer();
143     if (!pseudoElementRenderer)
144         return;
145
146     if (update->change == Style::Detach)
147         createContentRenderers(m_updater.m_builder, *pseudoElementRenderer, *update->style);
148     else
149         updateStyleForContentRenderers(*pseudoElementRenderer, *update->style);
150
151     if (m_updater.renderView().hasQuotesNeedingUpdate()) {
152         for (auto& child : descendantsOfType<RenderQuote>(*pseudoElementRenderer))
153             updateQuotesUpTo(&child);
154     }
155     if (is<RenderListItem>(*pseudoElementRenderer))
156         ListItem::updateMarker(m_updater.m_builder, downcast<RenderListItem>(*pseudoElementRenderer));
157 }
158
159 bool RenderTreeUpdater::GeneratedContent::needsPseudoElement(const std::optional<Style::ElementUpdate>& update)
160 {
161     if (!update)
162         return false;
163     if (!m_updater.renderTreePosition().parent().canHaveGeneratedChildren())
164         return false;
165     if (!pseudoElementRendererIsNeeded(update->style.get()))
166         return false;
167     return true;
168 }
169
170 void RenderTreeUpdater::GeneratedContent::removeBeforePseudoElement(Element& element)
171 {
172     auto* pseudoElement = element.beforePseudoElement();
173     if (!pseudoElement)
174         return;
175     tearDownRenderers(*pseudoElement, TeardownType::Full);
176     element.clearBeforePseudoElement();
177 }
178
179 void RenderTreeUpdater::GeneratedContent::removeAfterPseudoElement(Element& element)
180 {
181     auto* pseudoElement = element.afterPseudoElement();
182     if (!pseudoElement)
183         return;
184     tearDownRenderers(*pseudoElement, TeardownType::Full);
185     element.clearAfterPseudoElement();
186 }
187
188 }