Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / graphics / RecordingImageBufferSurface.cpp
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "config.h"
6
7 #include "platform/graphics/RecordingImageBufferSurface.h"
8
9 #include "platform/graphics/GraphicsContext.h"
10 #include "platform/graphics/ImageBuffer.h"
11 #include "public/platform/Platform.h"
12 #include "third_party/skia/include/core/SkCanvas.h"
13 #include "third_party/skia/include/core/SkPictureRecorder.h"
14 #include "wtf/PassOwnPtr.h"
15 #include "wtf/PassRefPtr.h"
16
17 namespace blink {
18
19 RecordingImageBufferSurface::RecordingImageBufferSurface(const IntSize& size, OpacityMode opacityMode)
20     : ImageBufferSurface(size, opacityMode)
21     , m_imageBuffer(0)
22     , m_initialSaveCount(0)
23     , m_frameWasCleared(true)
24 {
25     initializeCurrentFrame();
26 }
27
28 RecordingImageBufferSurface::~RecordingImageBufferSurface()
29 { }
30
31 bool RecordingImageBufferSurface::initializeCurrentFrame()
32 {
33     StateStack stateStack;
34     bool saved = false;
35     if (m_currentFrame) {
36         saved = saveState(m_currentFrame->getRecordingCanvas(), &stateStack);
37         if (!saved)
38             return false;
39     }
40
41     static SkRTreeFactory rTreeFactory;
42     m_currentFrame = adoptPtr(new SkPictureRecorder);
43     m_currentFrame->beginRecording(size().width(), size().height(), &rTreeFactory);
44     m_initialSaveCount = m_currentFrame->getRecordingCanvas()->getSaveCount();
45     if (m_imageBuffer) {
46         m_imageBuffer->context()->resetCanvas(m_currentFrame->getRecordingCanvas());
47         m_imageBuffer->context()->setRegionTrackingMode(GraphicsContext::RegionTrackingOverwrite);
48     }
49
50     if (saved)
51         setCurrentState(m_currentFrame->getRecordingCanvas(), &stateStack);
52
53     return true;
54 }
55
56 void RecordingImageBufferSurface::setImageBuffer(ImageBuffer* imageBuffer)
57 {
58     m_imageBuffer = imageBuffer;
59     if (m_currentFrame && m_imageBuffer) {
60         m_imageBuffer->context()->setRegionTrackingMode(GraphicsContext::RegionTrackingOverwrite);
61         m_imageBuffer->context()->resetCanvas(m_currentFrame->getRecordingCanvas());
62     }
63 }
64
65 void RecordingImageBufferSurface::willAccessPixels()
66 {
67     fallBackToRasterCanvas();
68 }
69
70 void RecordingImageBufferSurface::fallBackToRasterCanvas()
71 {
72     if (m_rasterCanvas) {
73         ASSERT(!m_currentFrame);
74         return;
75     }
76
77     m_rasterCanvas = adoptPtr(SkCanvas::NewRasterN32(size().width(), size().height()));
78
79     if (m_previousFrame) {
80         m_previousFrame->draw(m_rasterCanvas.get());
81         m_previousFrame.clear();
82     }
83     if (m_currentFrame) {
84         RefPtr<SkPicture> currentPicture = adoptRef(m_currentFrame->endRecording());
85         currentPicture->draw(m_rasterCanvas.get());
86         m_currentFrame.clear();
87     }
88
89     if (m_imageBuffer) {
90         m_imageBuffer->context()->setRegionTrackingMode(GraphicsContext::RegionTrackingDisabled);
91         m_imageBuffer->context()->resetCanvas(m_rasterCanvas.get());
92     }
93 }
94
95 SkCanvas* RecordingImageBufferSurface::canvas() const
96 {
97     if (m_rasterCanvas)
98         return m_rasterCanvas.get();
99
100     ASSERT(m_currentFrame->getRecordingCanvas());
101     return m_currentFrame->getRecordingCanvas();
102 }
103
104 PassRefPtr<SkPicture> RecordingImageBufferSurface::getPicture()
105 {
106     bool canUsePicture = finalizeFrameInternal();
107     m_imageBuffer->didFinalizeFrame();
108
109     if (canUsePicture) {
110         return m_previousFrame;
111     }
112
113     if (!m_rasterCanvas)
114         fallBackToRasterCanvas();
115     return nullptr;
116 }
117
118 void RecordingImageBufferSurface::finalizeFrame(const FloatRect &)
119 {
120     if (!finalizeFrameInternal() && !m_rasterCanvas) {
121         fallBackToRasterCanvas();
122     }
123 }
124
125 void RecordingImageBufferSurface::didClearCanvas()
126 {
127     m_frameWasCleared = true;
128 }
129
130 bool RecordingImageBufferSurface::finalizeFrameInternal()
131 {
132     if (!m_imageBuffer->isDirty()) {
133         if (m_currentFrame && !m_previousFrame) {
134             // Create an initial blank frame
135             m_previousFrame = adoptRef(m_currentFrame->endRecording());
136             initializeCurrentFrame();
137         }
138         return m_currentFrame;
139     }
140
141     if (!m_currentFrame) {
142         return false;
143     }
144
145     IntRect canvasRect(IntPoint(0, 0), size());
146     if (!m_frameWasCleared && !m_imageBuffer->context()->opaqueRegion().asRect().contains(canvasRect)) {
147         return false;
148     }
149
150     m_previousFrame = adoptRef(m_currentFrame->endRecording());
151     if (!initializeCurrentFrame())
152         return false;
153
154
155     m_frameWasCleared = false;
156     return true;
157 }
158
159 bool RecordingImageBufferSurface::saveState(SkCanvas* srcCanvas, StateStack* stateStack)
160 {
161     StateRec state;
162
163     // we will remove all the saved state stack in endRecording anyway, so it makes no difference
164     while (srcCanvas->getSaveCount() > m_initialSaveCount) {
165         state.m_ctm = srcCanvas->getTotalMatrix();
166         // FIXME: don't mess up the state in case we will have to fallback, crbug.com/408392
167         if (!srcCanvas->getClipDeviceBounds(&state.m_clip))
168             return false;
169         stateStack->push(state);
170         srcCanvas->restore();
171     }
172
173     state.m_ctm = srcCanvas->getTotalMatrix();
174     // FIXME: don't mess up the state in case we will have to fallback, crbug.com/408392
175     if (!srcCanvas->getClipDeviceBounds(&state.m_clip))
176         return false;
177     stateStack->push(state);
178
179     return true;
180 }
181
182 void RecordingImageBufferSurface::setCurrentState(SkCanvas* dstCanvas, StateStack* stateStack)
183 {
184     while (stateStack->size() > 1) {
185         dstCanvas->resetMatrix();
186         dstCanvas->clipRect(SkRect::MakeFromIRect(stateStack->peek().m_clip));
187         dstCanvas->setMatrix(stateStack->peek().m_ctm);
188         dstCanvas->save();
189         stateStack->pop();
190     }
191
192     dstCanvas->resetMatrix();
193     dstCanvas->clipRect(SkRect::MakeFromIRect(stateStack->peek().m_clip));
194     dstCanvas->setMatrix(stateStack->peek().m_ctm);
195 }
196
197 } // namespace blink