2 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "platform/graphics/GraphicsContextRecorder.h"
34 #include "platform/graphics/ImageBuffer.h"
35 #include "platform/graphics/ImageSource.h"
36 #include "platform/image-decoders/ImageDecoder.h"
37 #include "platform/image-decoders/ImageFrame.h"
38 #include "third_party/skia/include/core/SkBitmapDevice.h"
39 #include "third_party/skia/include/core/SkPictureRecorder.h"
40 #include "third_party/skia/include/core/SkStream.h"
44 GraphicsContext* GraphicsContextRecorder::record(const IntSize& size, bool isCertainlyOpaque)
49 m_isCertainlyOpaque = isCertainlyOpaque;
50 m_recorder = adoptPtr(new SkPictureRecorder);
51 SkCanvas* canvas = m_recorder->beginRecording(size.width(), size.height(), 0, 0);
52 m_context = adoptPtr(new GraphicsContext(canvas));
53 m_context->setTrackOpaqueRegion(isCertainlyOpaque);
54 m_context->setCertainlyOpaque(isCertainlyOpaque);
55 return m_context.get();
58 PassRefPtr<GraphicsContextSnapshot> GraphicsContextRecorder::stop()
61 m_picture = adoptRef(m_recorder->endRecording());
63 return adoptRef(new GraphicsContextSnapshot(m_picture.release(), m_isCertainlyOpaque));
66 GraphicsContextSnapshot::GraphicsContextSnapshot(PassRefPtr<SkPicture> picture, bool isCertainlyOpaque)
68 , m_isCertainlyOpaque(isCertainlyOpaque)
73 class SnapshotPlayer : public SkDrawPictureCallback {
74 WTF_MAKE_NONCOPYABLE(SnapshotPlayer);
76 explicit SnapshotPlayer(PassRefPtr<SkPicture> picture, SkCanvas* canvas)
82 SkCanvas* canvas() { return m_canvas; }
86 m_picture->draw(m_canvas, this);
90 RefPtr<SkPicture> m_picture;
94 class FragmentSnapshotPlayer : public SnapshotPlayer {
96 FragmentSnapshotPlayer(PassRefPtr<SkPicture> picture, SkCanvas* canvas)
97 : SnapshotPlayer(picture, canvas)
101 void play(unsigned fromStep, unsigned toStep)
103 m_fromStep = fromStep;
106 SnapshotPlayer::play();
109 virtual bool abortDrawing() OVERRIDE
112 if (m_stepCount == m_fromStep) {
113 const SkBitmap& bitmap = canvas()->getDevice()->accessBitmap(true);
114 bitmap.eraseARGB(0, 0, 0, 0); // FIXME: get layers background color, it might make resulting image a bit more plausable.
116 return m_toStep && m_stepCount > m_toStep;
122 unsigned m_stepCount;
125 class ProfilingSnapshotPlayer : public SnapshotPlayer {
127 ProfilingSnapshotPlayer(PassRefPtr<SkPicture> picture, SkCanvas* canvas)
128 : SnapshotPlayer(picture, canvas)
132 void play(GraphicsContextSnapshot::Timings* timingsVector, unsigned minRepeatCount, double minDuration)
134 m_timingsVector = timingsVector;
135 m_timingsVector->reserveCapacity(minRepeatCount);
137 double now = WTF::monotonicallyIncreasingTime();
138 double stopTime = now + minDuration;
139 for (unsigned step = 0; step < minRepeatCount || now < stopTime; ++step) {
140 m_timingsVector->append(Vector<double>());
141 m_currentTimings = &m_timingsVector->last();
142 if (m_timingsVector->size() > 1)
143 m_currentTimings->reserveCapacity(m_timingsVector->begin()->size());
144 SnapshotPlayer::play();
145 now = WTF::monotonicallyIncreasingTime();
146 m_currentTimings->append(now);
150 virtual bool abortDrawing() OVERRIDE
152 m_currentTimings->append(WTF::monotonicallyIncreasingTime());
156 const GraphicsContextSnapshot::Timings& timingsVector() const { return *m_timingsVector; }
159 GraphicsContextSnapshot::Timings* m_timingsVector;
160 Vector<double>* m_currentTimings;
163 class LoggingSnapshotPlayer : public SnapshotPlayer {
165 LoggingSnapshotPlayer(PassRefPtr<SkPicture> picture, SkCanvas* canvas)
166 : SnapshotPlayer(picture, canvas)
170 virtual bool abortDrawing() OVERRIDE
176 class LoggingCanvas : public SkCanvas {
180 m_log = JSONArray::create();
183 void clear(SkColor) OVERRIDE
188 void drawPaint(const SkPaint& paint) OVERRIDE
190 addItem("drawPaint");
193 void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint&) OVERRIDE
195 addItem("drawPoints");
198 void drawPicture(SkPicture&) OVERRIDE
200 addItem("drawPicture");
203 void drawRect(const SkRect& rect, const SkPaint& paint) OVERRIDE
208 void drawOval(const SkRect&, const SkPaint&) OVERRIDE
213 void drawRRect(const SkRRect&, const SkPaint&) OVERRIDE
215 addItem("drawRRect");
218 void drawPath(const SkPath& path, const SkPaint&) OVERRIDE
223 void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, const SkPaint*) OVERRIDE
225 addItem("drawBitmap");
228 void drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, const SkPaint* paint, DrawBitmapRectFlags flags) OVERRIDE
230 addItem("drawBitmapRectToRect");
233 void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m, const SkPaint*) OVERRIDE
235 addItem("drawBitmapMatrix");
238 void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint* paint = 0) OVERRIDE
240 addItem("drawBitmapNine");
243 void drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint*) OVERRIDE
245 addItem("drawSprite");
248 void drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
249 const uint16_t indices[], int indexCount, const SkPaint&) OVERRIDE
251 addItem("drawVertices");
254 void drawData(const void* data, size_t length) OVERRIDE
259 PassRefPtr<JSONArray> log()
265 RefPtr<JSONArray> m_log;
267 void addItem(const String& name)
269 RefPtr<JSONObject> item = JSONObject::create();
270 item->setString("name", name);
271 m_log->pushObject(item.release());
275 static bool decodeBitmap(const void* data, size_t length, SkBitmap* result)
277 RefPtr<SharedBuffer> buffer = SharedBuffer::create(static_cast<const char*>(data), length);
278 OwnPtr<ImageDecoder> imageDecoder = ImageDecoder::create(*buffer, ImageSource::AlphaPremultiplied, ImageSource::GammaAndColorProfileIgnored);
281 imageDecoder->setData(buffer.get(), true);
282 ImageFrame* frame = imageDecoder->frameBufferAtIndex(0);
285 *result = frame->getSkBitmap();
289 PassRefPtr<GraphicsContextSnapshot> GraphicsContextSnapshot::load(const char* data, size_t size)
291 SkMemoryStream stream(data, size);
292 RefPtr<SkPicture> picture = adoptRef(SkPicture::CreateFromStream(&stream, decodeBitmap));
295 return adoptRef(new GraphicsContextSnapshot(picture, false));
298 PassOwnPtr<ImageBuffer> GraphicsContextSnapshot::replay(unsigned fromStep, unsigned toStep) const
300 OwnPtr<ImageBuffer> imageBuffer = createImageBuffer();
301 FragmentSnapshotPlayer player(m_picture, imageBuffer->context()->canvas());
302 player.play(fromStep, toStep);
303 return imageBuffer.release();
306 PassOwnPtr<GraphicsContextSnapshot::Timings> GraphicsContextSnapshot::profile(unsigned minRepeatCount, double minDuration) const
308 OwnPtr<GraphicsContextSnapshot::Timings> timings = adoptPtr(new GraphicsContextSnapshot::Timings());
309 OwnPtr<ImageBuffer> imageBuffer = createImageBuffer();
310 ProfilingSnapshotPlayer player(m_picture, imageBuffer->context()->canvas());
311 player.play(timings.get(), minRepeatCount, minDuration);
312 return timings.release();
315 PassOwnPtr<ImageBuffer> GraphicsContextSnapshot::createImageBuffer() const
317 return ImageBuffer::create(IntSize(m_picture->width(), m_picture->height()), m_isCertainlyOpaque ? Opaque : NonOpaque);
320 PassRefPtr<JSONArray> GraphicsContextSnapshot::snapshotCommandLog() const
322 LoggingCanvas canvas;
323 FragmentSnapshotPlayer player(m_picture, &canvas);