Update ANGLE
[WebKit-https.git] / Source / WebCore / platform / DragImage.cpp
1 /*
2  * Copyright (C) 2007 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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "DragImage.h"
28
29 #include "Frame.h"
30 #include "FrameSnapshotting.h"
31 #include "FrameView.h"
32 #include "ImageBuffer.h"
33 #include "NotImplemented.h"
34 #include "Range.h"
35 #include "RenderElement.h"
36 #include "RenderObject.h"
37 #include "RenderView.h"
38 #include "TextIndicator.h"
39
40 namespace WebCore {
41
42 #if PLATFORM(COCOA)
43 const float ColorSwatchCornerRadius = 4;
44 const float ColorSwatchStrokeSize = 4;
45 const float ColorSwatchWidth = 24;
46 #endif
47
48 DragImageRef fitDragImageToMaxSize(DragImageRef image, const IntSize& layoutSize, const IntSize& maxSize)
49 {
50     float heightResizeRatio = 0.0f;
51     float widthResizeRatio = 0.0f;
52     float resizeRatio = -1.0f;
53     IntSize originalSize = dragImageSize(image);
54
55     if (layoutSize.width() > maxSize.width()) {
56         widthResizeRatio = maxSize.width() / (float)layoutSize.width();
57         resizeRatio = widthResizeRatio;
58     }
59
60     if (layoutSize.height() > maxSize.height()) {
61         heightResizeRatio = maxSize.height() / (float)layoutSize.height();
62         if ((resizeRatio < 0.0f) || (resizeRatio > heightResizeRatio))
63             resizeRatio = heightResizeRatio;
64     }
65
66     if (layoutSize == originalSize)
67         return resizeRatio > 0.0f ? scaleDragImage(image, FloatSize(resizeRatio, resizeRatio)) : image;
68
69     // The image was scaled in the webpage so at minimum we must account for that scaling.
70     float scaleX = layoutSize.width() / (float)originalSize.width();
71     float scaleY = layoutSize.height() / (float)originalSize.height();
72     if (resizeRatio > 0.0f) {
73         scaleX *= resizeRatio;
74         scaleY *= resizeRatio;
75     }
76
77     return scaleDragImage(image, FloatSize(scaleX, scaleY));
78 }
79
80 struct ScopedNodeDragEnabler {
81     ScopedNodeDragEnabler(Frame& frame, Node& node)
82         : frame(frame)
83         , node(node)
84     {
85         if (node.renderer())
86             node.renderer()->updateDragState(true);
87         frame.document()->updateLayout();
88     }
89
90     ~ScopedNodeDragEnabler()
91     {
92         if (node.renderer())
93             node.renderer()->updateDragState(false);
94     }
95
96     const Frame& frame;
97     const Node& node;
98 };
99
100 static DragImageRef createDragImageFromSnapshot(std::unique_ptr<ImageBuffer> snapshot, Node* node)
101 {
102     if (!snapshot)
103         return nullptr;
104
105     ImageOrientation orientation;
106     if (node) {
107         RenderObject* renderer = node->renderer();
108         if (!renderer || !is<RenderElement>(renderer))
109             return nullptr;
110
111         orientation = downcast<RenderElement>(*renderer).imageOrientation();
112     }
113
114     RefPtr<Image> image = ImageBuffer::sinkIntoImage(WTFMove(snapshot), PreserveResolution::Yes);
115     if (!image)
116         return nullptr;
117     return createDragImageFromImage(image.get(), orientation);
118 }
119
120 DragImageRef createDragImageForNode(Frame& frame, Node& node)
121 {
122     ScopedNodeDragEnabler enableDrag(frame, node);
123     return createDragImageFromSnapshot(snapshotNode(frame, node), &node);
124 }
125
126 #if !ENABLE(DATA_INTERACTION)
127
128 DragImageRef createDragImageForSelection(Frame& frame, TextIndicatorData&, bool forceBlackText)
129 {
130     SnapshotOptions options = forceBlackText ? SnapshotOptionsForceBlackText : SnapshotOptionsNone;
131     return createDragImageFromSnapshot(snapshotSelection(frame, options), nullptr);
132 }
133
134 #endif
135
136 struct ScopedFrameSelectionState {
137     ScopedFrameSelectionState(Frame& frame)
138         : frame(frame)
139     {
140         if (auto* renderView = frame.contentRenderer())
141             selection = renderView->selection().get();
142     }
143
144     ~ScopedFrameSelectionState()
145     {
146         if (auto* renderView = frame.contentRenderer()) {
147             ASSERT(selection);
148             renderView->selection().set(selection.value(), SelectionRangeData::RepaintMode::Nothing);
149         }
150     }
151
152     const Frame& frame;
153     Optional<SelectionRangeData::Context> selection;
154 };
155
156 #if !PLATFORM(IOS_FAMILY)
157
158 DragImageRef createDragImageForRange(Frame& frame, Range& range, bool forceBlackText)
159 {
160     frame.document()->updateLayout();
161     RenderView* view = frame.contentRenderer();
162     if (!view)
163         return nullptr;
164
165     // To snapshot the range, temporarily select it and take selection snapshot.
166     Position start = range.startPosition();
167     Position candidate = start.downstream();
168     if (candidate.deprecatedNode() && candidate.deprecatedNode()->renderer())
169         start = candidate;
170
171     Position end = range.endPosition();
172     candidate = end.upstream();
173     if (candidate.deprecatedNode() && candidate.deprecatedNode()->renderer())
174         end = candidate;
175
176     if (start.isNull() || end.isNull() || start == end)
177         return nullptr;
178
179     const ScopedFrameSelectionState selectionState(frame);
180
181     RenderObject* startRenderer = start.deprecatedNode()->renderer();
182     RenderObject* endRenderer = end.deprecatedNode()->renderer();
183     if (!startRenderer || !endRenderer)
184         return nullptr;
185
186     SnapshotOptions options = SnapshotOptionsPaintSelectionOnly | (forceBlackText ? SnapshotOptionsForceBlackText : SnapshotOptionsNone);
187     int startOffset = start.deprecatedEditingOffset();
188     int endOffset = end.deprecatedEditingOffset();
189     ASSERT(startOffset >= 0 && endOffset >= 0);
190     view->selection().set({ startRenderer, endRenderer, static_cast<unsigned>(startOffset), static_cast<unsigned>(endOffset) }, SelectionRangeData::RepaintMode::Nothing);
191     // We capture using snapshotFrameRect() because we fake up the selection using
192     // FrameView but snapshotSelection() uses the selection from the Frame itself.
193     return createDragImageFromSnapshot(snapshotFrameRect(frame, view->selection().boundsClippedToVisibleContent(), options), nullptr);
194 }
195
196 #endif
197
198 DragImageRef createDragImageForImage(Frame& frame, Node& node, IntRect& imageRect, IntRect& elementRect)
199 {
200     ScopedNodeDragEnabler enableDrag(frame, node);
201
202     RenderObject* renderer = node.renderer();
203     if (!renderer)
204         return nullptr;
205
206     // Calculate image and element metrics for the client, then create drag image.
207     LayoutRect topLevelRect;
208     IntRect paintingRect = snappedIntRect(renderer->paintingRootRect(topLevelRect));
209
210     if (paintingRect.isEmpty())
211         return nullptr;
212
213     elementRect = snappedIntRect(topLevelRect);
214     imageRect = paintingRect;
215
216     return createDragImageFromSnapshot(snapshotNode(frame, node), &node);
217 }
218
219 #if !ENABLE(DATA_INTERACTION)
220 DragImageRef platformAdjustDragImageForDeviceScaleFactor(DragImageRef image, float deviceScaleFactor)
221 {
222     // Later code expects the drag image to be scaled by device's scale factor.
223     return scaleDragImage(image, { deviceScaleFactor, deviceScaleFactor });
224 }
225 #endif
226
227 #if !PLATFORM(MAC)
228 const int linkDragBorderInset = 2;
229
230 IntPoint dragOffsetForLinkDragImage(DragImageRef dragImage)
231 {
232     IntSize size = dragImageSize(dragImage);
233     return { -size.width() / 2, -linkDragBorderInset };
234 }
235
236 FloatPoint anchorPointForLinkDragImage(DragImageRef dragImage)
237 {
238     IntSize size = dragImageSize(dragImage);
239     return { 0.5, static_cast<float>((size.height() - linkDragBorderInset) / size.height()) };
240 }
241 #endif
242
243 DragImage::DragImage()
244     : m_dragImageRef { nullptr }
245 {
246 }
247
248 DragImage::DragImage(DragImageRef dragImageRef)
249     : m_dragImageRef { dragImageRef }
250 {
251 }
252
253 DragImage::DragImage(DragImage&& other)
254     : m_dragImageRef { std::exchange(other.m_dragImageRef, nullptr) }
255 {
256     m_indicatorData = other.m_indicatorData;
257     m_visiblePath = other.m_visiblePath;
258 }
259
260 DragImage& DragImage::operator=(DragImage&& other)
261 {
262     if (m_dragImageRef)
263         deleteDragImage(m_dragImageRef);
264
265     m_dragImageRef = std::exchange(other.m_dragImageRef, nullptr);
266     m_indicatorData = other.m_indicatorData;
267     m_visiblePath = other.m_visiblePath;
268
269     return *this;
270 }
271
272 DragImage::~DragImage()
273 {
274     if (m_dragImageRef)
275         deleteDragImage(m_dragImageRef);
276 }
277
278 #if !PLATFORM(COCOA) && !PLATFORM(GTK) && !PLATFORM(WIN)
279
280 IntSize dragImageSize(DragImageRef)
281 {
282     notImplemented();
283     return { 0, 0 };
284 }
285
286 void deleteDragImage(DragImageRef)
287 {
288     notImplemented();
289 }
290
291 DragImageRef scaleDragImage(DragImageRef, FloatSize)
292 {
293     notImplemented();
294     return nullptr;
295 }
296
297 DragImageRef dissolveDragImageToFraction(DragImageRef, float)
298 {
299     notImplemented();
300     return nullptr;
301 }
302
303 DragImageRef createDragImageFromImage(Image*, ImageOrientation)
304 {
305     notImplemented();
306     return nullptr;
307 }
308
309 DragImageRef createDragImageIconForCachedImageFilename(const String&)
310 {
311     notImplemented();
312     return nullptr;
313 }
314
315 DragImageRef createDragImageForLink(Element&, URL&, const String&, TextIndicatorData&, FontRenderingMode, float)
316 {
317     notImplemented();
318     return nullptr;
319 }
320
321 #endif
322
323 } // namespace WebCore
324