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
45namespace WebCore {
46
47struct 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
70std::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
76std::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 std::unique_ptr<ImageBuffer> buffer = ImageBuffer::create(imageRect.size(), Unaccelerated, scaleFactor);
112 if (!buffer)
113 return nullptr;
114 buffer->context().translate(-imageRect.x(), -imageRect.y());
115
116 if (!clipRects.isEmpty()) {
117 Path clipPath;
118 for (auto& rect : clipRects)
119 clipPath.addRect(rect);
120 buffer->context().clipPath(clipPath);
121 }
122
123 frame.view()->paintContentsForSnapshot(buffer->context(), imageRect, shouldIncludeSelection, coordinateSpace);
124 return buffer;
125}
126
127std::unique_ptr<ImageBuffer> snapshotSelection(Frame& frame, SnapshotOptions options)
128{
129 auto& selection = frame.selection();
130
131 if (!selection.isRange())
132 return nullptr;
133
134 FloatRect selectionBounds = selection.selectionBounds();
135
136 // It is possible for the selection bounds to be empty; see https://bugs.webkit.org/show_bug.cgi?id=56645.
137 if (selectionBounds.isEmpty())
138 return nullptr;
139
140 options |= SnapshotOptionsPaintSelectionOnly;
141 return snapshotFrameRect(frame, enclosingIntRect(selectionBounds), options);
142}
143
144std::unique_ptr<ImageBuffer> snapshotNode(Frame& frame, Node& node)
145{
146 if (!node.renderer())
147 return nullptr;
148
149 ScopedFramePaintingState state(frame, &node);
150
151 frame.view()->setBaseBackgroundColor(Color::transparent);
152 frame.view()->setNodeToDraw(&node);
153
154 LayoutRect topLevelRect;
155 return snapshotFrameRect(frame, snappedIntRect(node.renderer()->paintingRootRect(topLevelRect)));
156}
157
158} // namespace WebCore
159