Another attempt to fix Windows build after r222697.
[WebKit-https.git] / Source / WebCore / rendering / SelectionRangeData.cpp
1 /*
2  * Copyright (C) 2014 Igalia S.L.
3  * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above
10  *    copyright notice, this list of conditions and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above
13  *    copyright notice, this list of conditions and the following
14  *    disclaimer in the documentation and/or other materials
15  *    provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
27  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "SelectionRangeData.h"
33
34 #include "Document.h"
35 #include "FrameSelection.h"
36 #include "Position.h"
37 #include "Range.h"
38 #include "RenderLayer.h"
39 #include "RenderMultiColumnSpannerPlaceholder.h"
40 #include "RenderObject.h"
41 #include "RenderView.h"
42 #include "VisibleSelection.h"
43
44 namespace WebCore {
45     
46 struct SelectionData {
47     using RendererMap = HashMap<RenderObject*, std::unique_ptr<RenderSelectionInfo>>;
48     using RenderBlockMap = HashMap<const RenderBlock*, std::unique_ptr<RenderBlockSelectionInfo>>;
49
50     std::optional<unsigned> startPosition;
51     std::optional<unsigned> endPosition;
52     RendererMap renderers;
53     RenderBlockMap blocks;
54 };
55
56 class SelectionIterator {
57 public:
58     SelectionIterator(RenderObject* start)
59         : m_current(start)
60     {
61         checkForSpanner();
62     }
63     
64     RenderObject* current() const
65     {
66         return m_current;
67     }
68     
69     RenderObject* next()
70     {
71         RenderObject* currentSpan = m_spannerStack.isEmpty() ? nullptr : m_spannerStack.last()->spanner();
72         m_current = m_current->nextInPreOrder(currentSpan);
73         checkForSpanner();
74         if (!m_current && currentSpan) {
75             RenderObject* placeholder = m_spannerStack.last();
76             m_spannerStack.removeLast();
77             m_current = placeholder->nextInPreOrder();
78             checkForSpanner();
79         }
80         return m_current;
81     }
82
83 private:
84     void checkForSpanner()
85     {
86         if (!is<RenderMultiColumnSpannerPlaceholder>(m_current))
87             return;
88         auto& placeholder = downcast<RenderMultiColumnSpannerPlaceholder>(*m_current);
89         m_spannerStack.append(&placeholder);
90         m_current = placeholder.spanner();
91     }
92
93     RenderObject* m_current { nullptr };
94     Vector<RenderMultiColumnSpannerPlaceholder*> m_spannerStack;
95 };
96
97 static RenderObject* rendererAfterPosition(const RenderObject& renderer, unsigned offset)
98 {
99     auto* child = renderer.childAt(offset);
100     return child ? child : renderer.nextInPreOrderAfterChildren();
101 }
102
103 static bool isValidRendererForSelection(const RenderObject& renderer, const SelectionRangeData::Context& selection)
104 {
105     return (renderer.canBeSelectionLeaf() || &renderer == selection.start || &renderer == selection.end)
106         && renderer.selectionState() != RenderObject::SelectionNone
107         && renderer.containingBlock();
108 }
109
110 static RenderBlock* containingBlockBelowView(const RenderObject& renderer)
111 {
112     auto* containingBlock = renderer.containingBlock();
113     return is<RenderView>(containingBlock) ? nullptr : containingBlock;
114 }
115
116 static SelectionData collect(const SelectionRangeData::Context& selection, bool repaintDifference)
117 {
118     SelectionData oldSelectionData { selection.startPosition, selection.endPosition, { }, { } };
119     // Blocks contain selected objects and fill gaps between them, either on the left, right, or in between lines and blocks.
120     // In order to get the repaint rect right, we have to examine left, middle, and right rects individually, since otherwise
121     // the union of those rects might remain the same even when changes have occurred.
122     RenderObject* start = selection.start;
123     RenderObject* stop = nullptr;
124     if (selection.end)
125         stop = rendererAfterPosition(*selection.end, selection.endPosition.value());
126     SelectionIterator selectionIterator(start);
127     while (start && start != stop) {
128         if (isValidRendererForSelection(*start, selection)) {
129             // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well.
130             oldSelectionData.renderers.set(start, std::make_unique<RenderSelectionInfo>(*start, true));
131             if (repaintDifference) {
132                 for (auto* block = containingBlockBelowView(*start); block; block = containingBlockBelowView(*block)) {
133                     auto& blockInfo = oldSelectionData.blocks.add(block, nullptr).iterator->value;
134                     if (blockInfo)
135                         break;
136                     blockInfo = std::make_unique<RenderBlockSelectionInfo>(*block);
137                 }
138             }
139         }
140         start = selectionIterator.next();
141     }
142     return oldSelectionData;
143 }
144
145 SelectionRangeData::SelectionRangeData(RenderView& view)
146     : m_renderView(view)
147 #if ENABLE(SERVICE_CONTROLS)
148     , m_selectionRectGatherer(view)
149 #endif
150 {
151 }
152
153 void SelectionRangeData::set(const Context& selection, RepaintMode blockRepaintMode)
154 {
155     // Make sure both our start and end objects are defined.
156     // Check www.msnbc.com and try clicking around to find the case where this happened.
157     if ((selection.start && !selection.end) || (selection.end && !selection.start))
158         return;
159     // Just return if the selection hasn't changed.
160     auto isCaret = m_renderView.frame().selection().isCaret();
161     if (selection == m_selectionContext && m_selectionWasCaret == isCaret)
162         return;
163 #if ENABLE(SERVICE_CONTROLS)
164     // Clear the current rects and create a notifier for the new rects we are about to gather.
165     // The Notifier updates the Editor when it goes out of scope and is destroyed.
166     auto rectNotifier = m_selectionRectGatherer.clearAndCreateNotifier();
167 #endif
168     m_selectionWasCaret = isCaret;
169     apply(selection, blockRepaintMode);
170 }
171
172 void SelectionRangeData::clear()
173 {
174     m_renderView.layer()->repaintBlockSelectionGaps();
175     set(SelectionRangeData::Context(), SelectionRangeData::RepaintMode::NewMinusOld);
176 }
177
178 void SelectionRangeData::repaint() const
179 {
180     HashSet<RenderBlock*> processedBlocks;
181     RenderObject* end = nullptr;
182     if (m_selectionContext.end)
183         end = rendererAfterPosition(*m_selectionContext.end, m_selectionContext.endPosition.value());
184     SelectionIterator selectionIterator(m_selectionContext.start);
185     for (auto* renderer = selectionIterator.current(); renderer && renderer != end; renderer = selectionIterator.next()) {
186         if (!renderer->canBeSelectionLeaf() && renderer != m_selectionContext.start && renderer != m_selectionContext.end)
187             continue;
188         if (renderer->selectionState() == RenderObject::SelectionNone)
189             continue;
190         RenderSelectionInfo(*renderer, true).repaint();
191         // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well.
192         for (auto* block = containingBlockBelowView(*renderer); block; block = containingBlockBelowView(*block)) {
193             if (!processedBlocks.add(block).isNewEntry)
194                 break;
195             RenderSelectionInfo(*block, true).repaint();
196         }
197     }
198 }
199
200 IntRect SelectionRangeData::collectBounds(ClipToVisibleContent clipToVisibleContent) const
201 {
202     SelectionData::RendererMap renderers;
203     RenderObject* start = m_selectionContext.start;
204     RenderObject* stop = nullptr;
205     if (m_selectionContext.end)
206         stop = rendererAfterPosition(*m_selectionContext.end, m_selectionContext.endPosition.value());
207     SelectionIterator selectionIterator(start);
208     while (start && start != stop) {
209         if ((start->canBeSelectionLeaf() || start == m_selectionContext.start || start == m_selectionContext.end)
210             && start->selectionState() != RenderObject::SelectionNone) {
211             // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well.
212             renderers.set(start, std::make_unique<RenderSelectionInfo>(*start, clipToVisibleContent == ClipToVisibleContent::Yes));
213             auto* block = start->containingBlock();
214             while (block && !is<RenderView>(*block)) {
215                 std::unique_ptr<RenderSelectionInfo>& blockInfo = renderers.add(block, nullptr).iterator->value;
216                 if (blockInfo)
217                     break;
218                 blockInfo = std::make_unique<RenderSelectionInfo>(*block, clipToVisibleContent == ClipToVisibleContent::Yes);
219                 block = block->containingBlock();
220             }
221         }
222         start = selectionIterator.next();
223     }
224
225     // Now create a single bounding box rect that encloses the whole selection.
226     LayoutRect selectionRect;
227     for (auto& info : renderers.values()) {
228         // RenderSelectionInfo::rect() is in the coordinates of the repaintContainer, so map to page coordinates.
229         LayoutRect currentRect = info->rect();
230         if (auto* repaintContainer = info->repaintContainer()) {
231             FloatQuad absQuad = repaintContainer->localToAbsoluteQuad(FloatRect(currentRect));
232             currentRect = absQuad.enclosingBoundingBox();
233         }
234         selectionRect.unite(currentRect);
235     }
236     return snappedIntRect(selectionRect);
237 }
238
239 void SelectionRangeData::apply(const Context& newSelection, RepaintMode blockRepaintMode)
240 {
241     auto oldSelectionData = collect(m_selectionContext, blockRepaintMode == RepaintMode::NewXOROld);
242     // Remove current selection.
243     for (auto* renderer : oldSelectionData.renderers.keys())
244         renderer->setSelectionStateIfNeeded(RenderObject::SelectionNone);
245     m_selectionContext = newSelection;
246     // Update the selection status of all objects between selectionStart and selectionEnd
247     if (m_selectionContext.start && m_selectionContext.start == m_selectionContext.end)
248         m_selectionContext.start->setSelectionStateIfNeeded(RenderObject::SelectionBoth);
249     else {
250         if (m_selectionContext.start)
251             m_selectionContext.start->setSelectionStateIfNeeded(RenderObject::SelectionStart);
252         if (m_selectionContext.end)
253             m_selectionContext.end->setSelectionStateIfNeeded(RenderObject::SelectionEnd);
254     }
255
256     auto* selectionStart = m_selectionContext.start;
257     auto* selectionDataEnd = m_selectionContext.end;
258     RenderObject* selectionEnd = nullptr;
259     if (selectionDataEnd)
260         selectionEnd = rendererAfterPosition(*selectionDataEnd, m_selectionContext.endPosition.value());
261     SelectionIterator selectionIterator(selectionStart);
262     for (auto* currentRenderer = selectionStart; currentRenderer && currentRenderer != selectionEnd; currentRenderer = selectionIterator.next()) {
263         if (currentRenderer == m_selectionContext.start || currentRenderer == m_selectionContext.end)
264             continue;
265         if (!currentRenderer->canBeSelectionLeaf())
266             continue;
267         currentRenderer->setSelectionStateIfNeeded(RenderObject::SelectionInside);
268     }
269
270     if (blockRepaintMode != RepaintMode::Nothing)
271         m_renderView.layer()->clearBlockSelectionGapsBounds();
272
273     // Now that the selection state has been updated for the new objects, walk them again and
274     // put them in the new objects list.
275     SelectionData::RendererMap newSelectedRenderers;
276     SelectionData::RenderBlockMap newSelectedBlocks;
277     selectionIterator = SelectionIterator(selectionStart);
278     for (auto* currentRenderer = selectionStart; currentRenderer && currentRenderer != selectionEnd; currentRenderer = selectionIterator.next()) {
279         if (isValidRendererForSelection(*currentRenderer, m_selectionContext)) {
280             std::unique_ptr<RenderSelectionInfo> selectionInfo = std::make_unique<RenderSelectionInfo>(*currentRenderer, true);
281 #if ENABLE(SERVICE_CONTROLS)
282             for (auto& rect : selectionInfo->collectedSelectionRects())
283                 m_selectionRectGatherer.addRect(selectionInfo->repaintContainer(), rect);
284             if (!currentRenderer->isTextOrLineBreak())
285                 m_selectionRectGatherer.setTextOnly(false);
286 #endif
287             newSelectedRenderers.set(currentRenderer, WTFMove(selectionInfo));
288             auto* containingBlock = currentRenderer->containingBlock();
289             while (containingBlock && !is<RenderView>(*containingBlock)) {
290                 std::unique_ptr<RenderBlockSelectionInfo>& blockInfo = newSelectedBlocks.add(containingBlock, nullptr).iterator->value;
291                 if (blockInfo)
292                     break;
293                 blockInfo = std::make_unique<RenderBlockSelectionInfo>(*containingBlock);
294                 containingBlock = containingBlock->containingBlock();
295 #if ENABLE(SERVICE_CONTROLS)
296                 m_selectionRectGatherer.addGapRects(blockInfo->repaintContainer(), blockInfo->rects());
297 #endif
298             }
299         }
300     }
301
302     if (blockRepaintMode == RepaintMode::Nothing)
303         return;
304
305     // Have any of the old selected objects changed compared to the new selection?
306     for (auto& selectedRendererInfo : oldSelectionData.renderers) {
307         auto* renderer = selectedRendererInfo.key;
308         auto* newInfo = newSelectedRenderers.get(renderer);
309         auto* oldInfo = selectedRendererInfo.value.get();
310         if (!newInfo || oldInfo->rect() != newInfo->rect() || oldInfo->state() != newInfo->state()
311             || (m_selectionContext.start == renderer && oldSelectionData.startPosition != m_selectionContext.startPosition)
312             || (m_selectionContext.end == renderer && oldSelectionData.endPosition != m_selectionContext.endPosition)) {
313             oldInfo->repaint();
314             if (newInfo) {
315                 newInfo->repaint();
316                 newSelectedRenderers.remove(renderer);
317             }
318         }
319     }
320
321     // Any new objects that remain were not found in the old objects dict, and so they need to be updated.
322     for (auto& selectedRendererInfo : newSelectedRenderers)
323         selectedRendererInfo.value->repaint();
324
325     // Have any of the old blocks changed?
326     for (auto& selectedBlockInfo : oldSelectionData.blocks) {
327         auto* block = selectedBlockInfo.key;
328         auto* newInfo = newSelectedBlocks.get(block);
329         auto* oldInfo = selectedBlockInfo.value.get();
330         if (!newInfo || oldInfo->rects() != newInfo->rects() || oldInfo->state() != newInfo->state()) {
331             oldInfo->repaint();
332             if (newInfo) {
333                 newInfo->repaint();
334                 newSelectedBlocks.remove(block);
335             }
336         }
337     }
338
339     // Any new blocks that remain were not found in the old blocks dict, and so they need to be updated.
340     for (auto& selectedBlockInfo : newSelectedBlocks)
341         selectedBlockInfo.value->repaint();
342 }
343
344 } // namespace WebCore