1/* 2 * Copyright (C) 2013 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 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 13 * distribution. 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. 17 * 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. 29 */ 30 31#include "config.h" 32#include "platform/graphics/GraphicsContextRecorder.h" 33 34#include "platform/graphics/ImageBuffer.h" 35#include "platform/graphics/ImageSource.h" 36#include "platform/graphics/LoggingCanvas.h" 37#include "platform/graphics/ProfilingCanvas.h" 38#include "platform/graphics/ReplayingCanvas.h" 39#include "platform/image-decoders/ImageDecoder.h" 40#include "platform/image-decoders/ImageFrame.h" 41#include "platform/image-encoders/skia/PNGImageEncoder.h" 42#include "third_party/skia/include/core/SkBitmapDevice.h" 43#include "third_party/skia/include/core/SkPictureRecorder.h" 44#include "third_party/skia/include/core/SkStream.h" 45#include "wtf/HexNumber.h" 46#include "wtf/text/Base64.h" 47#include "wtf/text/TextEncoding.h" 48 49namespace blink { 50 51GraphicsContext* GraphicsContextRecorder::record(const IntSize& size, bool isCertainlyOpaque) 52{ 53 ASSERT(!m_picture); 54 ASSERT(!m_recorder); 55 ASSERT(!m_context); 56 m_isCertainlyOpaque = isCertainlyOpaque; 57 m_recorder = adoptPtr(new SkPictureRecorder); 58 SkCanvas* canvas = m_recorder->beginRecording(size.width(), size.height(), 0, 0); 59 m_context = adoptPtr(new GraphicsContext(canvas)); 60 m_context->setRegionTrackingMode(isCertainlyOpaque ? GraphicsContext::RegionTrackingOpaque : GraphicsContext::RegionTrackingDisabled); 61 m_context->setCertainlyOpaque(isCertainlyOpaque); 62 return m_context.get(); 63} 64 65PassRefPtr<GraphicsContextSnapshot> GraphicsContextRecorder::stop() 66{ 67 m_context.clear(); 68 m_picture = adoptRef(m_recorder->endRecording()); 69 m_recorder.clear(); 70 return adoptRef(new GraphicsContextSnapshot(m_picture.release())); 71} 72 73GraphicsContextSnapshot::GraphicsContextSnapshot(PassRefPtr<SkPicture> picture) 74 : m_picture(picture) 75{ 76} 77 78static bool decodeBitmap(const void* data, size_t length, SkBitmap* result) 79{ 80 RefPtr<SharedBuffer> buffer = SharedBuffer::create(static_cast<const char*>(data), length); 81 OwnPtr<ImageDecoder> imageDecoder = ImageDecoder::create(*buffer, ImageSource::AlphaPremultiplied, ImageSource::GammaAndColorProfileIgnored); 82 if (!imageDecoder) 83 return false; 84 imageDecoder->setData(buffer.get(), true); 85 ImageFrame* frame = imageDecoder->frameBufferAtIndex(0); 86 if (!frame) 87 return true; 88 *result = frame->getSkBitmap(); 89 return true; 90} 91 92PassRefPtr<GraphicsContextSnapshot> GraphicsContextSnapshot::load(const char* data, size_t size) 93{ 94 SkMemoryStream stream(data, size); 95 RefPtr<SkPicture> picture = adoptRef(SkPicture::CreateFromStream(&stream, decodeBitmap)); 96 if (!picture) 97 return nullptr; 98 return adoptRef(new GraphicsContextSnapshot(picture)); 99} 100 101PassOwnPtr<Vector<char> > GraphicsContextSnapshot::replay(unsigned fromStep, unsigned toStep, double scale) const 102{ 103 int width = ceil(scale * m_picture->width()); 104 int height = ceil(scale * m_picture->height()); 105 SkBitmap bitmap; 106 bitmap.allocPixels(SkImageInfo::MakeN32Premul(width, height)); 107 { 108 ReplayingCanvas canvas(bitmap, fromStep, toStep); 109 canvas.scale(scale, scale); 110 canvas.resetStepCount(); 111 m_picture->draw(&canvas, &canvas); 112 } 113 OwnPtr<Vector<char> > base64Data = adoptPtr(new Vector<char>()); 114 Vector<char> encodedImage; 115 if (!PNGImageEncoder::encode(bitmap, reinterpret_cast<Vector<unsigned char>*>(&encodedImage))) 116 return nullptr; 117 base64Encode(encodedImage, *base64Data); 118 return base64Data.release(); 119} 120 121PassOwnPtr<GraphicsContextSnapshot::Timings> GraphicsContextSnapshot::profile(unsigned minRepeatCount, double minDuration) const 122{ 123 OwnPtr<GraphicsContextSnapshot::Timings> timings = adoptPtr(new GraphicsContextSnapshot::Timings()); 124 timings->reserveCapacity(minRepeatCount); 125 SkBitmap bitmap; 126 bitmap.allocPixels(SkImageInfo::MakeN32Premul(m_picture->width(), m_picture->height())); 127 OwnPtr<ProfilingCanvas> canvas = adoptPtr(new ProfilingCanvas(bitmap)); 128 129 double now = WTF::monotonicallyIncreasingTime(); 130 double stopTime = now + minDuration; 131 for (unsigned step = 0; step < minRepeatCount || now < stopTime; ++step) { 132 timings->append(Vector<double>()); 133 Vector<double>* currentTimings = &timings->last(); 134 if (timings->size() > 1) 135 currentTimings->reserveCapacity(timings->begin()->size()); 136 if (step) 137 canvas = adoptPtr(new ProfilingCanvas(bitmap)); 138 canvas->setTimings(currentTimings); 139 m_picture->draw(canvas.get()); 140 now = WTF::monotonicallyIncreasingTime(); 141 } 142 return timings.release(); 143} 144 145PassRefPtr<JSONArray> GraphicsContextSnapshot::snapshotCommandLog() const 146{ 147 LoggingCanvas canvas(m_picture->width(), m_picture->height()); 148 m_picture->draw(&canvas); 149 return canvas.log(); 150} 151 152} // namespace blink 153