Subpixel fringes around TextIndicator snapshots at non-integral scale factors
[WebKit-https.git] / Source / WebCore / page / FrameSnapshotting.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013 Apple Inc. All rights reserved.
3  * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
4  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
5  * Copyright (C) 2013 University of Washington.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1.  Redistributions of source code must retain the above copyright
12  *     notice, this list of conditions and the following disclaimer.
13  * 2.  Redistributions in binary form must reproduce the above copyright
14  *     notice, this list of conditions and the following disclaimer in the
15  *     documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30
31 #include "config.h"
32 #include "FrameSnapshotting.h"
33
34 #include "Document.h"
35 #include "FloatRect.h"
36 #include "Frame.h"
37 #include "FrameSelection.h"
38 #include "FrameView.h"
39 #include "GraphicsContext.h"
40 #include "ImageBuffer.h"
41 #include "Page.h"
42 #include "RenderObject.h"
43 #include "Settings.h"
44
45 namespace WebCore {
46
47 struct ScopedFramePaintingState {
48     ScopedFramePaintingState(Frame& frame, Node* node)
49         : frame(frame)
50         , node(node)
51         , paintBehavior(frame.view()->paintBehavior())
52         , backgroundColor(frame.view()->baseBackgroundColor())
53     {
54         ASSERT(!node || node->renderer());
55     }
56
57     ~ScopedFramePaintingState()
58     {
59         frame.view()->setPaintBehavior(paintBehavior);
60         frame.view()->setBaseBackgroundColor(backgroundColor);
61         frame.view()->setNodeToDraw(nullptr);
62     }
63
64     const Frame& frame;
65     const Node* node;
66     const OptionSet<PaintBehavior> paintBehavior;
67     const Color backgroundColor;
68 };
69
70 std::unique_ptr<ImageBuffer> snapshotFrameRect(Frame& frame, const IntRect& imageRect, SnapshotOptions options)
71 {
72     Vector<FloatRect> clipRects;
73     return snapshotFrameRectWithClip(frame, imageRect, clipRects, options);
74 }
75
76 std::unique_ptr<ImageBuffer> snapshotFrameRectWithClip(Frame& frame, const IntRect& imageRect, const Vector<FloatRect>& clipRects, SnapshotOptions options)
77 {
78     if (!frame.page())
79         return nullptr;
80
81     frame.document()->updateLayout();
82
83     FrameView::SelectionInSnapshot shouldIncludeSelection = FrameView::IncludeSelection;
84     if (options & SnapshotOptionsExcludeSelectionHighlighting)
85         shouldIncludeSelection = FrameView::ExcludeSelection;
86
87     FrameView::CoordinateSpaceForSnapshot coordinateSpace = FrameView::DocumentCoordinates;
88     if (options & SnapshotOptionsInViewCoordinates)
89         coordinateSpace = FrameView::ViewCoordinates;
90
91     ScopedFramePaintingState state(frame, nullptr);
92
93     auto paintBehavior = state.paintBehavior;
94     if (options & SnapshotOptionsForceBlackText)
95         paintBehavior.add(PaintBehavior::ForceBlackText);
96     if (options & SnapshotOptionsPaintSelectionOnly)
97         paintBehavior.add(PaintBehavior::SelectionOnly);
98     if (options & SnapshotOptionsPaintSelectionAndBackgroundsOnly)
99         paintBehavior.add(PaintBehavior::SelectionAndBackgroundsOnly);
100     if (options & SnapshotOptionsPaintEverythingExcludingSelection)
101         paintBehavior.add(PaintBehavior::ExcludeSelection);
102
103     // Other paint behaviors are set by paintContentsForSnapshot.
104     frame.view()->setPaintBehavior(paintBehavior);
105
106     float scaleFactor = frame.page()->deviceScaleFactor();
107
108     if (frame.settings().delegatesPageScaling())
109         scaleFactor *= frame.page()->pageScaleFactor();
110
111     if (options & SnapshotOptionsPaintWithIntegralScaleFactor)
112         scaleFactor = ceilf(scaleFactor);
113
114     std::unique_ptr<ImageBuffer> buffer = ImageBuffer::create(imageRect.size(), Unaccelerated, scaleFactor);
115     if (!buffer)
116         return nullptr;
117     buffer->context().translate(-imageRect.x(), -imageRect.y());
118
119     if (!clipRects.isEmpty()) {
120         Path clipPath;
121         for (auto& rect : clipRects)
122             clipPath.addRect(encloseRectToDevicePixels(rect, scaleFactor));
123         buffer->context().clipPath(clipPath);
124     }
125
126     frame.view()->paintContentsForSnapshot(buffer->context(), imageRect, shouldIncludeSelection, coordinateSpace);
127     return buffer;
128 }
129
130 std::unique_ptr<ImageBuffer> snapshotSelection(Frame& frame, SnapshotOptions options)
131 {
132     auto& selection = frame.selection();
133
134     if (!selection.isRange())
135         return nullptr;
136
137     FloatRect selectionBounds = selection.selectionBounds();
138
139     // It is possible for the selection bounds to be empty; see https://bugs.webkit.org/show_bug.cgi?id=56645.
140     if (selectionBounds.isEmpty())
141         return nullptr;
142
143     options |= SnapshotOptionsPaintSelectionOnly;
144     return snapshotFrameRect(frame, enclosingIntRect(selectionBounds), options);
145 }
146
147 std::unique_ptr<ImageBuffer> snapshotNode(Frame& frame, Node& node)
148 {
149     if (!node.renderer())
150         return nullptr;
151
152     ScopedFramePaintingState state(frame, &node);
153
154     frame.view()->setBaseBackgroundColor(Color::transparent);
155     frame.view()->setNodeToDraw(&node);
156
157     LayoutRect topLevelRect;
158     return snapshotFrameRect(frame, snappedIntRect(node.renderer()->paintingRootRect(topLevelRect)));
159 }
160
161 } // namespace WebCore