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/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"
19 RecordingImageBufferSurface::RecordingImageBufferSurface(const IntSize& size, OpacityMode opacityMode)
20 : ImageBufferSurface(size, opacityMode)
22 , m_initialSaveCount(0)
23 , m_frameWasCleared(true)
25 initializeCurrentFrame();
28 RecordingImageBufferSurface::~RecordingImageBufferSurface()
31 bool RecordingImageBufferSurface::initializeCurrentFrame()
33 StateStack stateStack;
36 saved = saveState(m_currentFrame->getRecordingCanvas(), &stateStack);
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();
46 m_imageBuffer->context()->resetCanvas(m_currentFrame->getRecordingCanvas());
47 m_imageBuffer->context()->setRegionTrackingMode(GraphicsContext::RegionTrackingOverwrite);
51 setCurrentState(m_currentFrame->getRecordingCanvas(), &stateStack);
56 void RecordingImageBufferSurface::setImageBuffer(ImageBuffer* imageBuffer)
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());
65 void RecordingImageBufferSurface::willAccessPixels()
67 fallBackToRasterCanvas();
70 void RecordingImageBufferSurface::fallBackToRasterCanvas()
73 ASSERT(!m_currentFrame);
77 m_rasterCanvas = adoptPtr(SkCanvas::NewRasterN32(size().width(), size().height()));
79 if (m_previousFrame) {
80 m_previousFrame->draw(m_rasterCanvas.get());
81 m_previousFrame.clear();
84 RefPtr<SkPicture> currentPicture = adoptRef(m_currentFrame->endRecording());
85 currentPicture->draw(m_rasterCanvas.get());
86 m_currentFrame.clear();
90 m_imageBuffer->context()->setRegionTrackingMode(GraphicsContext::RegionTrackingDisabled);
91 m_imageBuffer->context()->resetCanvas(m_rasterCanvas.get());
95 SkCanvas* RecordingImageBufferSurface::canvas() const
98 return m_rasterCanvas.get();
100 ASSERT(m_currentFrame->getRecordingCanvas());
101 return m_currentFrame->getRecordingCanvas();
104 PassRefPtr<SkPicture> RecordingImageBufferSurface::getPicture()
106 bool canUsePicture = finalizeFrameInternal();
107 m_imageBuffer->didFinalizeFrame();
110 return m_previousFrame;
114 fallBackToRasterCanvas();
118 void RecordingImageBufferSurface::finalizeFrame(const FloatRect &)
120 if (!finalizeFrameInternal() && !m_rasterCanvas) {
121 fallBackToRasterCanvas();
125 void RecordingImageBufferSurface::didClearCanvas()
127 m_frameWasCleared = true;
130 bool RecordingImageBufferSurface::finalizeFrameInternal()
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();
138 return m_currentFrame;
141 if (!m_currentFrame) {
145 IntRect canvasRect(IntPoint(0, 0), size());
146 if (!m_frameWasCleared && !m_imageBuffer->context()->opaqueRegion().asRect().contains(canvasRect)) {
150 m_previousFrame = adoptRef(m_currentFrame->endRecording());
151 if (!initializeCurrentFrame())
155 m_frameWasCleared = false;
159 bool RecordingImageBufferSurface::saveState(SkCanvas* srcCanvas, StateStack* stateStack)
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))
169 stateStack->push(state);
170 srcCanvas->restore();
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))
177 stateStack->push(state);
182 void RecordingImageBufferSurface::setCurrentState(SkCanvas* dstCanvas, StateStack* stateStack)
184 while (stateStack->size() > 1) {
185 dstCanvas->resetMatrix();
186 dstCanvas->clipRect(SkRect::MakeFromIRect(stateStack->peek().m_clip));
187 dstCanvas->setMatrix(stateStack->peek().m_ctm);
192 dstCanvas->resetMatrix();
193 dstCanvas->clipRect(SkRect::MakeFromIRect(stateStack->peek().m_clip));
194 dstCanvas->setMatrix(stateStack->peek().m_ctm);