2 * Copyright (C) 2007 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "DragImage.h"
30 #include "FrameSnapshotting.h"
31 #include "FrameView.h"
32 #include "ImageBuffer.h"
34 #include "RenderObject.h"
35 #include "RenderView.h"
39 DragImageRef fitDragImageToMaxSize(DragImageRef image, const IntSize& layoutSize, const IntSize& maxSize)
41 float heightResizeRatio = 0.0f;
42 float widthResizeRatio = 0.0f;
43 float resizeRatio = -1.0f;
44 IntSize originalSize = dragImageSize(image);
46 if (layoutSize.width() > maxSize.width()) {
47 widthResizeRatio = maxSize.width() / (float)layoutSize.width();
48 resizeRatio = widthResizeRatio;
51 if (layoutSize.height() > maxSize.height()) {
52 heightResizeRatio = maxSize.height() / (float)layoutSize.height();
53 if ((resizeRatio < 0.0f) || (resizeRatio > heightResizeRatio))
54 resizeRatio = heightResizeRatio;
57 if (layoutSize == originalSize)
58 return resizeRatio > 0.0f ? scaleDragImage(image, FloatSize(resizeRatio, resizeRatio)) : image;
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;
68 return scaleDragImage(image, FloatSize(scaleX, scaleY));
71 struct ScopedNodeDragEnabler {
72 ScopedNodeDragEnabler(Frame& frame, Node& node)
77 node.renderer()->updateDragState(true);
78 frame.document()->updateLayout();
81 ~ScopedNodeDragEnabler()
84 node.renderer()->updateDragState(false);
91 static DragImageRef createDragImageFromSnapshot(std::unique_ptr<ImageBuffer> snapshot, Node* node)
96 ImageOrientationDescription orientation;
97 #if ENABLE(CSS_IMAGE_ORIENTATION)
99 RenderObject* renderer = node->renderer();
103 orientation.setRespectImageOrientation(renderer->shouldRespectImageOrientation());
104 orientation.setImageOrientationEnum(renderer->style().imageOrientation());
109 RefPtr<Image> image = ImageBuffer::sinkIntoImage(WTFMove(snapshot), Unscaled);
112 return createDragImageFromImage(image.get(), orientation);
115 DragImageRef createDragImageForNode(Frame& frame, Node& node)
117 ScopedNodeDragEnabler enableDrag(frame, node);
118 return createDragImageFromSnapshot(snapshotNode(frame, node), &node);
121 DragImageRef createDragImageForSelection(Frame& frame, bool forceBlackText)
123 SnapshotOptions options = forceBlackText ? SnapshotOptionsForceBlackText : SnapshotOptionsNone;
124 return createDragImageFromSnapshot(snapshotSelection(frame, options), nullptr);
127 struct ScopedFrameSelectionState {
128 ScopedFrameSelectionState(Frame& frame)
131 if (RenderView* root = frame.contentRenderer())
132 root->getSelection(startRenderer, startOffset, endRenderer, endOffset);
135 ~ScopedFrameSelectionState()
137 if (RenderView* root = frame.contentRenderer())
138 root->setSelection(startRenderer, startOffset, endRenderer, endOffset, RenderView::RepaintNothing);
142 RenderObject* startRenderer;
143 RenderObject* endRenderer;
144 Optional<unsigned> startOffset;
145 Optional<unsigned> endOffset;
148 DragImageRef createDragImageForRange(Frame& frame, Range& range, bool forceBlackText)
150 frame.document()->updateLayout();
151 RenderView* view = frame.contentRenderer();
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())
161 Position end = range.endPosition();
162 candidate = end.upstream();
163 if (candidate.deprecatedNode() && candidate.deprecatedNode()->renderer())
166 if (start.isNull() || end.isNull() || start == end)
169 const ScopedFrameSelectionState selectionState(frame);
171 RenderObject* startRenderer = start.deprecatedNode()->renderer();
172 RenderObject* endRenderer = end.deprecatedNode()->renderer();
173 if (!startRenderer || !endRenderer)
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);
186 DragImageRef createDragImageForImage(Frame& frame, Node& node, IntRect& imageRect, IntRect& elementRect)
188 ScopedNodeDragEnabler enableDrag(frame, node);
190 RenderObject* renderer = node.renderer();
194 // Calculate image and element metrics for the client, then create drag image.
195 LayoutRect topLevelRect;
196 IntRect paintingRect = snappedIntRect(renderer->paintingRootRect(topLevelRect));
198 if (paintingRect.isEmpty())
201 elementRect = snappedIntRect(topLevelRect);
202 imageRect = paintingRect;
204 return createDragImageFromSnapshot(snapshotNode(frame, node), &node);
207 #if !PLATFORM(COCOA) && !PLATFORM(WIN)
208 DragImageRef createDragImageForLink(URL&, const String&, FontRenderingMode)
214 } // namespace WebCore