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.
7 #include "platform/graphics/RecordingImageBufferSurface.h"
9 #include "platform/graphics/ExpensiveCanvasHeuristicParameters.h"
10 #include "platform/graphics/GraphicsContext.h"
11 #include "platform/graphics/ImageBuffer.h"
12 #include "public/platform/Platform.h"
13 #include "third_party/skia/include/core/SkCanvas.h"
14 #include "third_party/skia/include/core/SkPictureRecorder.h"
15 #include "wtf/PassOwnPtr.h"
16 #include "wtf/PassRefPtr.h"
20 RecordingImageBufferSurface::RecordingImageBufferSurface(const IntSize
& size
, PassOwnPtr
<RecordingImageBufferFallbackSurfaceFactory
> fallbackFactory
, OpacityMode opacityMode
)
21 : ImageBufferSurface(size
, opacityMode
)
23 , m_currentFramePixelCount(0)
24 , m_previousFramePixelCount(0)
25 , m_frameWasCleared(true)
26 , m_didRecordDrawCommandsInCurrentFrame(false)
27 , m_currentFrameHasExpensiveOp(false)
28 , m_previousFrameHasExpensiveOp(false)
29 , m_fallbackFactory(fallbackFactory
)
31 initializeCurrentFrame();
34 RecordingImageBufferSurface::~RecordingImageBufferSurface()
37 bool RecordingImageBufferSurface::initializeCurrentFrame()
39 static SkRTreeFactory rTreeFactory
;
40 m_currentFrame
= adoptPtr(new SkPictureRecorder
);
41 m_currentFrame
->beginRecording(size().width(), size().height(), &rTreeFactory
);
43 m_imageBuffer
->resetCanvas(m_currentFrame
->getRecordingCanvas());
45 m_didRecordDrawCommandsInCurrentFrame
= false;
46 m_currentFrameHasExpensiveOp
= false;
47 m_currentFramePixelCount
= 0;
51 void RecordingImageBufferSurface::setImageBuffer(ImageBuffer
* imageBuffer
)
53 m_imageBuffer
= imageBuffer
;
54 if (m_currentFrame
&& m_imageBuffer
) {
55 m_imageBuffer
->resetCanvas(m_currentFrame
->getRecordingCanvas());
57 if (m_fallbackSurface
) {
58 m_fallbackSurface
->setImageBuffer(imageBuffer
);
62 bool RecordingImageBufferSurface::writePixels(const SkImageInfo
& origInfo
, const void* pixels
, size_t rowBytes
, int x
, int y
)
64 if (!m_fallbackSurface
) {
65 if (x
<= 0 && y
<= 0 && x
+ origInfo
.width() >= size().width() && y
+ origInfo
.height() >= size().height()) {
66 willOverwriteCanvas();
68 fallBackToRasterCanvas();
70 return m_fallbackSurface
->writePixels(origInfo
, pixels
, rowBytes
, x
, y
);
73 void RecordingImageBufferSurface::fallBackToRasterCanvas()
75 if (m_fallbackSurface
) {
76 ASSERT(!m_currentFrame
);
80 m_fallbackSurface
= m_fallbackFactory
->createSurface(size(), opacityMode());
81 m_fallbackSurface
->setImageBuffer(m_imageBuffer
);
83 if (m_previousFrame
) {
84 m_previousFrame
->playback(m_fallbackSurface
->canvas());
85 m_previousFrame
.clear();
89 RefPtr
<SkPicture
> currentPicture
= adoptRef(m_currentFrame
->endRecording());
90 currentPicture
->playback(m_fallbackSurface
->canvas());
91 m_currentFrame
.clear();
95 m_imageBuffer
->resetCanvas(m_fallbackSurface
->canvas());
100 PassRefPtr
<SkImage
> RecordingImageBufferSurface::newImageSnapshot()
102 if (!m_fallbackSurface
)
103 fallBackToRasterCanvas();
104 return m_fallbackSurface
->newImageSnapshot();
107 SkCanvas
* RecordingImageBufferSurface::canvas()
109 if (m_fallbackSurface
)
110 return m_fallbackSurface
->canvas();
112 ASSERT(m_currentFrame
->getRecordingCanvas());
113 return m_currentFrame
->getRecordingCanvas();
116 void RecordingImageBufferSurface::disableDeferral()
118 if (!m_fallbackSurface
)
119 fallBackToRasterCanvas();
122 PassRefPtr
<SkPicture
> RecordingImageBufferSurface::getPicture()
124 if (m_fallbackSurface
)
127 bool canUsePicture
= finalizeFrameInternal();
128 m_imageBuffer
->didFinalizeFrame();
131 return m_previousFrame
;
134 if (!m_fallbackSurface
)
135 fallBackToRasterCanvas();
139 void RecordingImageBufferSurface::finalizeFrame(const FloatRect
&dirtyRect
)
141 if (m_fallbackSurface
) {
142 m_fallbackSurface
->finalizeFrame(dirtyRect
);
146 if (!finalizeFrameInternal())
147 fallBackToRasterCanvas();
150 void RecordingImageBufferSurface::flush()
152 if (!m_fallbackSurface
)
153 fallBackToRasterCanvas();
154 m_fallbackSurface
->flush();
157 void RecordingImageBufferSurface::willOverwriteCanvas()
159 m_frameWasCleared
= true;
160 m_previousFrame
.clear();
161 m_previousFrameHasExpensiveOp
= false;
162 m_previousFramePixelCount
= 0;
163 if (m_didRecordDrawCommandsInCurrentFrame
) {
164 // Discard previous draw commands
165 adoptRef(m_currentFrame
->endRecording());
166 initializeCurrentFrame();
170 void RecordingImageBufferSurface::didDraw(const FloatRect
& rect
)
172 m_didRecordDrawCommandsInCurrentFrame
= true;
173 IntRect pixelBounds
= enclosingIntRect(rect
);
174 m_currentFramePixelCount
+= pixelBounds
.width() * pixelBounds
.height();
177 bool RecordingImageBufferSurface::finalizeFrameInternal()
179 ASSERT(!m_fallbackSurface
);
180 ASSERT(m_currentFrame
);
181 ASSERT(m_currentFrame
->getRecordingCanvas());
183 if (!m_imageBuffer
->isDirty()) {
184 if (!m_previousFrame
) {
185 // Create an initial blank frame
186 m_previousFrame
= adoptRef(m_currentFrame
->endRecording());
187 initializeCurrentFrame();
189 return m_currentFrame
;
192 if (!m_frameWasCleared
|| m_currentFrame
->getRecordingCanvas()->getSaveCount() > ExpensiveCanvasHeuristicParameters::ExpensiveRecordingStackDepth
) {
196 m_previousFrame
= adoptRef(m_currentFrame
->endRecording());
197 m_previousFrameHasExpensiveOp
= m_currentFrameHasExpensiveOp
;
198 m_previousFramePixelCount
= m_currentFramePixelCount
;
199 if (!initializeCurrentFrame())
202 m_frameWasCleared
= false;
206 void RecordingImageBufferSurface::draw(GraphicsContext
* context
, const FloatRect
& destRect
, const FloatRect
& srcRect
, SkXfermode::Mode op
)
208 if (m_fallbackSurface
) {
209 m_fallbackSurface
->draw(context
, destRect
, srcRect
, op
);
213 RefPtr
<SkPicture
> picture
= getPicture();
215 context
->compositePicture(picture
.get(), destRect
, srcRect
, op
);
217 ImageBufferSurface::draw(context
, destRect
, srcRect
, op
);
221 bool RecordingImageBufferSurface::isExpensiveToPaint()
223 if (m_fallbackSurface
)
224 return m_fallbackSurface
->isExpensiveToPaint();
226 if (m_didRecordDrawCommandsInCurrentFrame
) {
227 if (m_currentFrameHasExpensiveOp
)
230 if (m_currentFramePixelCount
>= (size().width() * size().height() * ExpensiveCanvasHeuristicParameters::ExpensiveOverdrawThreshold
))
233 if (m_frameWasCleared
)
234 return false; // early exit because previous frame is overdrawn
237 if (m_previousFrame
) {
238 if (m_previousFrameHasExpensiveOp
)
241 if (m_previousFramePixelCount
>= (size().width() * size().height() * ExpensiveCanvasHeuristicParameters::ExpensiveOverdrawThreshold
))
248 const SkBitmap
& RecordingImageBufferSurface::deprecatedBitmapForOverwrite()
250 if (!m_fallbackSurface
) {
251 willOverwriteCanvas();
252 fallBackToRasterCanvas();
254 return m_fallbackSurface
->deprecatedBitmapForOverwrite();
257 // Fallback passthroughs
259 bool RecordingImageBufferSurface::restore()
261 if (m_fallbackSurface
)
262 return m_fallbackSurface
->restore();
263 return ImageBufferSurface::restore();
266 WebLayer
* RecordingImageBufferSurface::layer() const
268 if (m_fallbackSurface
)
269 return m_fallbackSurface
->layer();
270 return ImageBufferSurface::layer();
273 bool RecordingImageBufferSurface::isAccelerated() const
275 if (m_fallbackSurface
)
276 return m_fallbackSurface
->isAccelerated();
277 return ImageBufferSurface::isAccelerated();
280 void RecordingImageBufferSurface::setIsHidden(bool hidden
)
282 if (m_fallbackSurface
)
283 m_fallbackSurface
->setIsHidden(hidden
);
285 ImageBufferSurface::setIsHidden(hidden
);