Upstream version 9.38.198.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 void RecordingImageBufferSurface::initializeCurrentFrame()
32 {
33     static SkRTreeFactory rTreeFactory;
34     m_currentFrame = adoptPtr(new SkPictureRecorder);
35     m_currentFrame->beginRecording(size().width(), size().height(), &rTreeFactory);
36     m_initialSaveCount = m_currentFrame->getRecordingCanvas()->getSaveCount();
37     if (m_imageBuffer) {
38         m_imageBuffer->context()->resetCanvas(m_currentFrame->getRecordingCanvas());
39         m_imageBuffer->context()->setRegionTrackingMode(GraphicsContext::RegionTrackingOverwrite);
40     }
41 }
42
43 void RecordingImageBufferSurface::setImageBuffer(ImageBuffer* imageBuffer)
44 {
45     m_imageBuffer = imageBuffer;
46     if (m_currentFrame && m_imageBuffer) {
47         m_imageBuffer->context()->setRegionTrackingMode(GraphicsContext::RegionTrackingOverwrite);
48         m_imageBuffer->context()->resetCanvas(m_currentFrame->getRecordingCanvas());
49     }
50 }
51
52 void RecordingImageBufferSurface::willAccessPixels()
53 {
54     fallBackToRasterCanvas();
55 }
56
57 void RecordingImageBufferSurface::fallBackToRasterCanvas()
58 {
59     if (m_rasterCanvas) {
60         ASSERT(!m_currentFrame);
61         return;
62     }
63
64     m_rasterCanvas = adoptPtr(SkCanvas::NewRasterN32(size().width(), size().height()));
65
66     if (m_previousFrame) {
67         m_previousFrame->draw(m_rasterCanvas.get());
68         m_previousFrame.clear();
69     }
70     if (m_currentFrame) {
71         RefPtr<SkPicture> currentPicture = adoptRef(m_currentFrame->endRecording());
72         currentPicture->draw(m_rasterCanvas.get());
73         m_currentFrame.clear();
74     }
75
76     if (m_imageBuffer) {
77         m_imageBuffer->context()->setRegionTrackingMode(GraphicsContext::RegionTrackingDisabled);
78         m_imageBuffer->context()->resetCanvas(m_rasterCanvas.get());
79     }
80 }
81
82 SkCanvas* RecordingImageBufferSurface::canvas() const
83 {
84     if (m_rasterCanvas)
85         return m_rasterCanvas.get();
86
87     ASSERT(m_currentFrame->getRecordingCanvas());
88     return m_currentFrame->getRecordingCanvas();
89 }
90
91 PassRefPtr<SkPicture> RecordingImageBufferSurface::getPicture()
92 {
93     bool canUsePicture = finalizeFrameInternal();
94     m_imageBuffer->didFinalizeFrame();
95
96     if (canUsePicture) {
97         return m_previousFrame;
98     }
99
100     if (!m_rasterCanvas)
101         fallBackToRasterCanvas();
102     return nullptr;
103 }
104
105 void RecordingImageBufferSurface::finalizeFrame()
106 {
107     if (!finalizeFrameInternal() && !m_rasterCanvas) {
108         fallBackToRasterCanvas();
109     }
110 }
111
112 void RecordingImageBufferSurface::didClearCanvas()
113 {
114     m_frameWasCleared = true;
115 }
116
117 bool RecordingImageBufferSurface::finalizeFrameInternal()
118 {
119     if (!m_imageBuffer->isDirty()) {
120         if (m_currentFrame && !m_previousFrame) {
121             // Create an initial blank frame
122             m_previousFrame = adoptRef(m_currentFrame->endRecording());
123             initializeCurrentFrame();
124         }
125         return m_currentFrame;
126     }
127
128     if (!m_currentFrame) {
129         return false;
130     }
131
132     IntRect canvasRect(IntPoint(0, 0), size());
133     if (!m_frameWasCleared && !m_imageBuffer->context()->opaqueRegion().asRect().contains(canvasRect)) {
134         return false;
135     }
136
137     SkCanvas* oldCanvas = m_currentFrame->getRecordingCanvas(); // Could be raster or picture
138
139     // FIXME(crbug.com/392614): handle transferring complex state from the current picture to the new one.
140     if (oldCanvas->getSaveCount() > m_initialSaveCount)
141         return false;
142
143     if (!oldCanvas->isClipRect())
144         return false;
145
146     SkMatrix ctm = oldCanvas->getTotalMatrix();
147     SkRect clip;
148     oldCanvas->getClipBounds(&clip);
149
150     m_previousFrame = adoptRef(m_currentFrame->endRecording());
151     initializeCurrentFrame();
152
153     SkCanvas* newCanvas = m_currentFrame->getRecordingCanvas();
154     newCanvas->concat(ctm);
155     newCanvas->clipRect(clip);
156
157     m_frameWasCleared = false;
158     return true;
159 }
160
161 } // namespace blink