Add CSS -webkit-appearance property for Apple Pay buttons
[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 "Range.h"
34 #include "RenderObject.h"
35 #include "RenderView.h"
36
37 namespace WebCore {
38
39 DragImageRef fitDragImageToMaxSize(DragImageRef image, const IntSize& layoutSize, const IntSize& maxSize)
40 {
41     float heightResizeRatio = 0.0f;
42     float widthResizeRatio = 0.0f;
43     float resizeRatio = -1.0f;
44     IntSize originalSize = dragImageSize(image);
45
46     if (layoutSize.width() > maxSize.width()) {
47         widthResizeRatio = maxSize.width() / (float)layoutSize.width();
48         resizeRatio = widthResizeRatio;
49     }
50
51     if (layoutSize.height() > maxSize.height()) {
52         heightResizeRatio = maxSize.height() / (float)layoutSize.height();
53         if ((resizeRatio < 0.0f) || (resizeRatio > heightResizeRatio))
54             resizeRatio = heightResizeRatio;
55     }
56
57     if (layoutSize == originalSize)
58         return resizeRatio > 0.0f ? scaleDragImage(image, FloatSize(resizeRatio, resizeRatio)) : image;
59
60     // The image was scaled in the webpage so at minimum we must account for that scaling.
61     float scaleX = layoutSize.width() / (float)originalSize.width();
62     float scaleY = layoutSize.height() / (float)originalSize.height();
63     if (resizeRatio > 0.0f) {
64         scaleX *= resizeRatio;
65         scaleY *= resizeRatio;
66     }
67
68     return scaleDragImage(image, FloatSize(scaleX, scaleY));
69 }
70
71 struct ScopedNodeDragEnabler {
72     ScopedNodeDragEnabler(Frame& frame, Node& node)
73         : frame(frame)
74         , node(node)
75     {
76         if (node.renderer())
77             node.renderer()->updateDragState(true);
78         frame.document()->updateLayout();
79     }
80
81     ~ScopedNodeDragEnabler()
82     {
83         if (node.renderer())
84             node.renderer()->updateDragState(false);
85     }
86
87     const Frame& frame;
88     const Node& node;
89 };
90
91 static DragImageRef createDragImageFromSnapshot(std::unique_ptr<ImageBuffer> snapshot, Node* node)
92 {
93     if (!snapshot)
94         return nullptr;
95
96     ImageOrientationDescription orientation;
97 #if ENABLE(CSS_IMAGE_ORIENTATION)
98     if (node) {
99         RenderObject* renderer = node->renderer();
100         if (!renderer)
101             return nullptr;
102
103         orientation.setRespectImageOrientation(renderer->shouldRespectImageOrientation());
104         orientation.setImageOrientationEnum(renderer->style().imageOrientation());
105     }
106 #else
107     UNUSED_PARAM(node);
108 #endif
109     RefPtr<Image> image = ImageBuffer::sinkIntoImage(WTFMove(snapshot), Unscaled);
110     if (!image)
111         return nullptr;
112     return createDragImageFromImage(image.get(), orientation);
113 }
114
115 DragImageRef createDragImageForNode(Frame& frame, Node& node)
116 {
117     ScopedNodeDragEnabler enableDrag(frame, node);
118     return createDragImageFromSnapshot(snapshotNode(frame, node), &node);
119 }
120
121 DragImageRef createDragImageForSelection(Frame& frame, bool forceBlackText)
122 {
123     SnapshotOptions options = forceBlackText ? SnapshotOptionsForceBlackText : SnapshotOptionsNone;
124     return createDragImageFromSnapshot(snapshotSelection(frame, options), nullptr);
125 }
126
127 struct ScopedFrameSelectionState {
128     ScopedFrameSelectionState(Frame& frame)
129         : frame(frame)
130     {
131         if (RenderView* root = frame.contentRenderer())
132             root->getSelection(startRenderer, startOffset, endRenderer, endOffset);
133     }
134
135     ~ScopedFrameSelectionState()
136     {
137         if (RenderView* root = frame.contentRenderer())
138             root->setSelection(startRenderer, startOffset, endRenderer, endOffset, RenderView::RepaintNothing);
139     }
140
141     const Frame& frame;
142     RenderObject* startRenderer;
143     RenderObject* endRenderer;
144     Optional<unsigned> startOffset;
145     Optional<unsigned> endOffset;
146 };
147
148 DragImageRef createDragImageForRange(Frame& frame, Range& range, bool forceBlackText)
149 {
150     frame.document()->updateLayout();
151     RenderView* view = frame.contentRenderer();
152     if (!view)
153         return nullptr;
154
155     // To snapshot the range, temporarily select it and take selection snapshot.
156     Position start = range.startPosition();
157     Position candidate = start.downstream();
158     if (candidate.deprecatedNode() && candidate.deprecatedNode()->renderer())
159         start = candidate;
160
161     Position end = range.endPosition();
162     candidate = end.upstream();
163     if (candidate.deprecatedNode() && candidate.deprecatedNode()->renderer())
164         end = candidate;
165
166     if (start.isNull() || end.isNull() || start == end)
167         return nullptr;
168
169     const ScopedFrameSelectionState selectionState(frame);
170
171     RenderObject* startRenderer = start.deprecatedNode()->renderer();
172     RenderObject* endRenderer = end.deprecatedNode()->renderer();
173     if (!startRenderer || !endRenderer)
174         return nullptr;
175
176     SnapshotOptions options = SnapshotOptionsPaintSelectionOnly | (forceBlackText ? SnapshotOptionsForceBlackText : SnapshotOptionsNone);
177     int startOffset = start.deprecatedEditingOffset();
178     int endOffset = end.deprecatedEditingOffset();
179     ASSERT(startOffset >= 0 && endOffset >= 0);
180     view->setSelection(startRenderer, startOffset, endRenderer, endOffset, RenderView::RepaintNothing);
181     // We capture using snapshotFrameRect() because we fake up the selection using
182     // FrameView but snapshotSelection() uses the selection from the Frame itself.
183     return createDragImageFromSnapshot(snapshotFrameRect(frame, view->selectionBounds(), options), nullptr);
184 }
185
186 DragImageRef createDragImageForImage(Frame& frame, Node& node, IntRect& imageRect, IntRect& elementRect)
187 {
188     ScopedNodeDragEnabler enableDrag(frame, node);
189
190     RenderObject* renderer = node.renderer();
191     if (!renderer)
192         return nullptr;
193
194     // Calculate image and element metrics for the client, then create drag image.
195     LayoutRect topLevelRect;
196     IntRect paintingRect = snappedIntRect(renderer->paintingRootRect(topLevelRect));
197
198     if (paintingRect.isEmpty())
199         return nullptr;
200
201     elementRect = snappedIntRect(topLevelRect);
202     imageRect = paintingRect;
203
204     return createDragImageFromSnapshot(snapshotNode(frame, node), &node);
205 }
206
207 #if !PLATFORM(COCOA) && !PLATFORM(WIN)
208 DragImageRef createDragImageForLink(URL&, const String&, FontRenderingMode)
209 {
210     return nullptr;
211 }
212 #endif
213
214 } // namespace WebCore
215