1635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project/* 2635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * Copyright (c) 2008, Google Inc. All rights reserved. 30bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> 45af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved. 52fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * 6635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * Redistribution and use in source and binary forms, with or without 7635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * modification, are permitted provided that the following conditions are 8635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * met: 92fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * 10635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * * Redistributions of source code must retain the above copyright 11635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * notice, this list of conditions and the following disclaimer. 12635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * * Redistributions in binary form must reproduce the above 13635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * copyright notice, this list of conditions and the following disclaimer 14635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * in the documentation and/or other materials provided with the 15635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * distribution. 16635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * * Neither the name of Google Inc. nor the names of its 17635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * contributors may be used to endorse or promote products derived from 18635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * this software without specific prior written permission. 192fc2651226baac27029e38c9d6ef883fa32084dbSteve Block * 20635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project */ 32635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 33635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "config.h" 34635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "ImageBuffer.h" 35635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 368f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian#include "Base64.h" 37635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "BitmapImage.h" 38635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "BitmapImageSingleFrameSkia.h" 395abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick#include "DrawingBuffer.h" 405abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick#include "GLES2Canvas.h" 41635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "GraphicsContext.h" 42635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "ImageData.h" 43f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#include "JPEGImageEncoder.h" 44f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#include "MIMETypeRegistry.h" 458f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian#include "PNGImageEncoder.h" 465abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick#include "PlatformContextSkia.h" 47231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "SkColorPriv.h" 48635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "SkiaUtils.h" 49635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 50a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include <wtf/text/StringConcatenate.h> 51a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 52635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectusing namespace std; 53635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 54635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectnamespace WebCore { 55635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 56635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// We pass a technically-uninitialized canvas to the platform context here since 57635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// the canvas initialization completes in ImageBuffer::ImageBuffer. But 58635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// PlatformContext doesn't actually need to use the object, and this makes all 59635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// the ownership easier to manage. 60635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectImageBufferData::ImageBufferData(const IntSize& size) 61635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project : m_platformContext(0) // Canvas is set in ImageBuffer constructor. 62635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 63635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 64635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 65f05b935882198ccf7d81675736e3aeb089c5113aBen MurdochImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, bool& success) 66635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project : m_data(size) 67635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project , m_size(size) 68635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 692daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch SkCanvas* canvas = skia::CreateBitmapCanvas(size.width(), size.height(), false); 702daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (!canvas) { 71635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project success = false; 72635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return; 73635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 74635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch m_data.m_canvas = canvas; 762daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch m_data.m_platformContext.setCanvas(m_data.m_canvas.get()); 77635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project m_context.set(new GraphicsContext(&m_data.m_platformContext)); 788f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian m_context->platformContext()->setDrawingToImageBuffer(true); 79635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 80635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Make the background transparent. It would be nice if this wasn't 81635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // required, but the canvas is currently filled with the magic transparency 82635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // color. Can we have another way to manage this? 832daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch m_data.m_canvas->drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode); 84635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project success = true; 85635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 86635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 87635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectImageBuffer::~ImageBuffer() 88635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 89635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 90635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 91635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectGraphicsContext* ImageBuffer::context() const 92635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 93635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return m_context.get(); 94635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 95635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 96ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdochsize_t ImageBuffer::dataSize() const 97ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch{ 98ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch return m_size.width() * m_size.height() * 4; 99ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch} 100ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch 101f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrickbool ImageBuffer::drawsUsingCopy() const 102635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 103e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return false; 104f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick} 105f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick 106f486d19d62f1bc33246748b14b14a9dfa617b57fIain MerrickPassRefPtr<Image> ImageBuffer::copyImage() const 107f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick{ 108e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block m_context->platformContext()->syncSoftwareCanvas(); 109e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return BitmapImageSingleFrameSkia::create(*m_data.m_platformContext.bitmap(), true); 110f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick} 111f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick 112f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrickvoid ImageBuffer::clip(GraphicsContext* context, const FloatRect& rect) const 113f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick{ 114f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick context->platformContext()->beginLayerClippedToImage(rect, this); 115f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick} 116f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick 117f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrickvoid ImageBuffer::draw(GraphicsContext* context, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, 118f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick CompositeOperator op, bool useLowQualityScale) 119f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick{ 1205abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick if (m_data.m_platformContext.useGPU() && context->platformContext()->useGPU()) { 1215abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick if (context->platformContext()->canAccelerate()) { 1222daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch m_data.m_platformContext.prepareForHardwareDraw(); 1235abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick DrawingBuffer* sourceDrawingBuffer = m_data.m_platformContext.gpuCanvas()->drawingBuffer(); 1246b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner unsigned sourceTexture = static_cast<unsigned>(sourceDrawingBuffer->platformColorBuffer()); 12565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch FloatRect destRectNormalized(normalizeRect(destRect)); 12665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch FloatRect srcRectFlipped(normalizeRect(srcRect)); 12765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch srcRectFlipped.setY(m_size.height() - srcRect.y()); 12865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch srcRectFlipped.setHeight(-srcRect.height()); 1295abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick context->platformContext()->prepareForHardwareDraw(); 13065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch context->platformContext()->gpuCanvas()->drawTexturedRect(sourceTexture, m_size, srcRectFlipped, destRectNormalized, styleColorSpace, op); 1315abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick return; 1325abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick } 1335abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick m_data.m_platformContext.syncSoftwareCanvas(); 1345abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick } 1355abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick 136e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block RefPtr<Image> image = BitmapImageSingleFrameSkia::create(*m_data.m_platformContext.bitmap(), context == m_context); 137e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block context->drawImage(image.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale); 138f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick} 139f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick 140f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrickvoid ImageBuffer::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform, 141f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect) 142f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick{ 143e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block RefPtr<Image> image = BitmapImageSingleFrameSkia::create(*m_data.m_platformContext.bitmap(), context == m_context); 144e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block image->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, op, destRect); 145635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 146635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 1470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) 1480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{ 1490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch const SkBitmap& bitmap = *context()->platformContext()->bitmap(); 150643ca7872b450ea4efacab6188849e5aac2ba161Steve Block if (bitmap.isNull()) 151643ca7872b450ea4efacab6188849e5aac2ba161Steve Block return; 152643ca7872b450ea4efacab6188849e5aac2ba161Steve Block 1530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config); 1540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch SkAutoLockPixels bitmapLock(bitmap); 1550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch for (int y = 0; y < m_size.height(); ++y) { 1560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch uint32_t* srcRow = bitmap.getAddr32(0, y); 1570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch for (int x = 0; x < m_size.width(); ++x) { 1580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch SkColor color = SkPMColorToColor(srcRow[x]); 159643ca7872b450ea4efacab6188849e5aac2ba161Steve Block srcRow[x] = SkPreMultiplyARGB(SkColorGetA(color), 1600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch lookUpTable[SkColorGetR(color)], 1610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch lookUpTable[SkColorGetG(color)], 1620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch lookUpTable[SkColorGetB(color)]); 1630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } 1640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } 1650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch} 1660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 167231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blocktemplate <Multiply multiplied> 1682fc2651226baac27029e38c9d6ef883fa32084dbSteve BlockPassRefPtr<ByteArray> getImageData(const IntRect& rect, SkDevice& srcDevice, 169231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block const IntSize& size) 170635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 171d0147a863b872ecaa451ab0dce2a348760e99e2cBen Murdoch float area = 4.0f * rect.width() * rect.height(); 172d0147a863b872ecaa451ab0dce2a348760e99e2cBen Murdoch if (area > static_cast<float>(std::numeric_limits<int>::max())) 173d0147a863b872ecaa451ab0dce2a348760e99e2cBen Murdoch return 0; 174d0147a863b872ecaa451ab0dce2a348760e99e2cBen Murdoch 175cad810f21b803229eb11403f9209855525a25d57Steve Block RefPtr<ByteArray> result = ByteArray::create(rect.width() * rect.height() * 4); 1760617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen 1772fc2651226baac27029e38c9d6ef883fa32084dbSteve Block SkBitmap::Config srcConfig = srcDevice.accessBitmap(false).config(); 1782fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 1792fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (srcConfig == SkBitmap::kNo_Config) { 1800617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen // This is an empty SkBitmap that could not be configured. 181dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch ASSERT(!size.width() || !size.height()); 182cad810f21b803229eb11403f9209855525a25d57Steve Block return result.release(); 1830617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen } 1840617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen 185cad810f21b803229eb11403f9209855525a25d57Steve Block unsigned char* data = result->data(); 186635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 187cad810f21b803229eb11403f9209855525a25d57Steve Block if (rect.x() < 0 188cad810f21b803229eb11403f9209855525a25d57Steve Block || rect.y() < 0 1892fc2651226baac27029e38c9d6ef883fa32084dbSteve Block || rect.maxX() > size.width() 1902fc2651226baac27029e38c9d6ef883fa32084dbSteve Block || rect.maxY() > size.height()) 191cad810f21b803229eb11403f9209855525a25d57Steve Block memset(data, 0, result->length()); 192635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 193635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project int originX = rect.x(); 194635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project int destX = 0; 195635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (originX < 0) { 196635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project destX = -originX; 197635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project originX = 0; 198635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 1992fc2651226baac27029e38c9d6ef883fa32084dbSteve Block int endX = rect.maxX(); 200231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (endX > size.width()) 201231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block endX = size.width(); 202635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project int numColumns = endX - originX; 203635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 2042fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (numColumns <= 0) 205cad810f21b803229eb11403f9209855525a25d57Steve Block return result.release(); 2064576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang 207635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project int originY = rect.y(); 208635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project int destY = 0; 209635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (originY < 0) { 210635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project destY = -originY; 211635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project originY = 0; 212635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 2132fc2651226baac27029e38c9d6ef883fa32084dbSteve Block int endY = rect.maxY(); 214231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (endY > size.height()) 215231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block endY = size.height(); 216635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project int numRows = endY - originY; 217635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 2182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (numRows <= 0) 219cad810f21b803229eb11403f9209855525a25d57Steve Block return result.release(); 2204576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang 2212fc2651226baac27029e38c9d6ef883fa32084dbSteve Block ASSERT(srcConfig == SkBitmap::kARGB_8888_Config); 222635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 223635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project unsigned destBytesPerRow = 4 * rect.width(); 2242fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 2252fc2651226baac27029e38c9d6ef883fa32084dbSteve Block SkBitmap srcBitmap; 2262fc2651226baac27029e38c9d6ef883fa32084dbSteve Block srcDevice.readPixels(SkIRect::MakeXYWH(originX, originY, numColumns, numRows), &srcBitmap); 2272fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 228635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project unsigned char* destRow = data + destY * destBytesPerRow + destX * 4; 229635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 2302fc2651226baac27029e38c9d6ef883fa32084dbSteve Block // Do conversion of byte order and alpha divide (if necessary) 231635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project for (int y = 0; y < numRows; ++y) { 2322fc2651226baac27029e38c9d6ef883fa32084dbSteve Block SkPMColor* srcBitmapRow = srcBitmap.getAddr32(0, y); 233635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project for (int x = 0; x < numColumns; ++x) { 2342fc2651226baac27029e38c9d6ef883fa32084dbSteve Block SkPMColor srcPMColor = srcBitmapRow[x]; 235635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project unsigned char* destPixel = &destRow[x * 4]; 236231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (multiplied == Unmultiplied) { 2372fc2651226baac27029e38c9d6ef883fa32084dbSteve Block unsigned char a = SkGetPackedA32(srcPMColor); 2382fc2651226baac27029e38c9d6ef883fa32084dbSteve Block destPixel[0] = a ? SkGetPackedR32(srcPMColor) * 255 / a : 0; 2392fc2651226baac27029e38c9d6ef883fa32084dbSteve Block destPixel[1] = a ? SkGetPackedG32(srcPMColor) * 255 / a : 0; 2402fc2651226baac27029e38c9d6ef883fa32084dbSteve Block destPixel[2] = a ? SkGetPackedB32(srcPMColor) * 255 / a : 0; 241643ca7872b450ea4efacab6188849e5aac2ba161Steve Block destPixel[3] = a; 242231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } else { 243231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block // Input and output are both pre-multiplied, we just need to re-arrange the 244231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block // bytes from the bitmap format to RGBA. 2452fc2651226baac27029e38c9d6ef883fa32084dbSteve Block destPixel[0] = SkGetPackedR32(srcPMColor); 2462fc2651226baac27029e38c9d6ef883fa32084dbSteve Block destPixel[1] = SkGetPackedG32(srcPMColor); 2472fc2651226baac27029e38c9d6ef883fa32084dbSteve Block destPixel[2] = SkGetPackedB32(srcPMColor); 2482fc2651226baac27029e38c9d6ef883fa32084dbSteve Block destPixel[3] = SkGetPackedA32(srcPMColor); 249231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 250635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 251635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project destRow += destBytesPerRow; 252635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 253635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 254cad810f21b803229eb11403f9209855525a25d57Steve Block return result.release(); 255635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 256635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 257cad810f21b803229eb11403f9209855525a25d57Steve BlockPassRefPtr<ByteArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const 258231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 259db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block context()->platformContext()->syncSoftwareCanvas(); 2602fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return getImageData<Unmultiplied>(rect, *context()->platformContext()->canvas()->getDevice(), m_size); 261231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 262231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 263cad810f21b803229eb11403f9209855525a25d57Steve BlockPassRefPtr<ByteArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const 264231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 265db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block context()->platformContext()->syncSoftwareCanvas(); 2662fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return getImageData<Premultiplied>(rect, *context()->platformContext()->canvas()->getDevice(), m_size); 267231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 268231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 269231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blocktemplate <Multiply multiplied> 2702fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockvoid putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, 2712fc2651226baac27029e38c9d6ef883fa32084dbSteve Block SkDevice* dstDevice, const IntSize& size) 272635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 273635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project ASSERT(sourceRect.width() > 0); 274635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project ASSERT(sourceRect.height() > 0); 275635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 276635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project int originX = sourceRect.x(); 277635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project int destX = destPoint.x() + sourceRect.x(); 278635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project ASSERT(destX >= 0); 279231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block ASSERT(destX < size.width()); 280635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project ASSERT(originX >= 0); 2812fc2651226baac27029e38c9d6ef883fa32084dbSteve Block ASSERT(originX < sourceRect.maxX()); 282635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 2832fc2651226baac27029e38c9d6ef883fa32084dbSteve Block int endX = destPoint.x() + sourceRect.maxX(); 284231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block ASSERT(endX <= size.width()); 285635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 286635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project int numColumns = endX - destX; 287635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 288635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project int originY = sourceRect.y(); 289635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project int destY = destPoint.y() + sourceRect.y(); 290635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project ASSERT(destY >= 0); 291231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block ASSERT(destY < size.height()); 292635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project ASSERT(originY >= 0); 2932fc2651226baac27029e38c9d6ef883fa32084dbSteve Block ASSERT(originY < sourceRect.maxY()); 294635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 2952fc2651226baac27029e38c9d6ef883fa32084dbSteve Block int endY = destPoint.y() + sourceRect.maxY(); 296231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block ASSERT(endY <= size.height()); 297635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project int numRows = endY - destY; 298635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 299cad810f21b803229eb11403f9209855525a25d57Steve Block unsigned srcBytesPerRow = 4 * sourceSize.width(); 300635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 3012fc2651226baac27029e38c9d6ef883fa32084dbSteve Block SkBitmap deviceBitmap = dstDevice->accessBitmap(true); 3022fc2651226baac27029e38c9d6ef883fa32084dbSteve Block SkAutoLockPixels deviceAutoLock(deviceBitmap); 303635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 3042fc2651226baac27029e38c9d6ef883fa32084dbSteve Block // If the device's bitmap doesn't have pixels we will make a temp and call writePixels on the device. 3052fc2651226baac27029e38c9d6ef883fa32084dbSteve Block bool temporaryBitmap = !deviceBitmap.getPixels(); 3062fc2651226baac27029e38c9d6ef883fa32084dbSteve Block SkBitmap destBitmap; 3072fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 3082fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (temporaryBitmap) { 3092fc2651226baac27029e38c9d6ef883fa32084dbSteve Block destBitmap.setConfig(SkBitmap::kARGB_8888_Config, numColumns, numRows, srcBytesPerRow); 3102fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (!destBitmap.allocPixels()) 3112fc2651226baac27029e38c9d6ef883fa32084dbSteve Block CRASH(); 3122fc2651226baac27029e38c9d6ef883fa32084dbSteve Block } else 3132fc2651226baac27029e38c9d6ef883fa32084dbSteve Block deviceBitmap.extractSubset(&destBitmap, SkIRect::MakeXYWH(destX, destY, numColumns, numRows)); 3142fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 3152fc2651226baac27029e38c9d6ef883fa32084dbSteve Block // Whether we made a temporary or not destBitmap is always configured to be written at 0,0 3162fc2651226baac27029e38c9d6ef883fa32084dbSteve Block SkAutoLockPixels destAutoLock(destBitmap); 3172fc2651226baac27029e38c9d6ef883fa32084dbSteve Block const unsigned char* srcRow = source->data() + originY * srcBytesPerRow + originX * 4; 318635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project for (int y = 0; y < numRows; ++y) { 3192fc2651226baac27029e38c9d6ef883fa32084dbSteve Block SkPMColor* destRow = destBitmap.getAddr32(0, y); 320635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project for (int x = 0; x < numColumns; ++x) { 321635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project const unsigned char* srcPixel = &srcRow[x * 4]; 3226b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner if (multiplied == Unmultiplied) { 3236b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner unsigned char alpha = srcPixel[3]; 324f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch unsigned char r = SkMulDiv255Ceiling(srcPixel[0], alpha); 325f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch unsigned char g = SkMulDiv255Ceiling(srcPixel[1], alpha); 326f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch unsigned char b = SkMulDiv255Ceiling(srcPixel[2], alpha); 3276b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner destRow[x] = SkPackARGB32(alpha, r, g, b); 3286b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner } else 3292fc2651226baac27029e38c9d6ef883fa32084dbSteve Block destRow[x] = SkPackARGB32(srcPixel[3], srcPixel[0], srcPixel[1], srcPixel[2]); 330635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 331635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project srcRow += srcBytesPerRow; 332635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 3332fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 3342fc2651226baac27029e38c9d6ef883fa32084dbSteve Block // If we used a temporary then write it to the device 3352fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (temporaryBitmap) 3362fc2651226baac27029e38c9d6ef883fa32084dbSteve Block dstDevice->writePixels(destBitmap, destX, destY); 337635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 338635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 339cad810f21b803229eb11403f9209855525a25d57Steve Blockvoid ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint) 340231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 3412fc2651226baac27029e38c9d6ef883fa32084dbSteve Block context()->platformContext()->syncSoftwareCanvas(); 3422fc2651226baac27029e38c9d6ef883fa32084dbSteve Block putImageData<Unmultiplied>(source, sourceSize, sourceRect, destPoint, context()->platformContext()->canvas()->getDevice(), m_size); 343231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 344231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 345cad810f21b803229eb11403f9209855525a25d57Steve Blockvoid ImageBuffer::putPremultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint) 346231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 3472fc2651226baac27029e38c9d6ef883fa32084dbSteve Block context()->platformContext()->syncSoftwareCanvas(); 3482fc2651226baac27029e38c9d6ef883fa32084dbSteve Block putImageData<Premultiplied>(source, sourceSize, sourceRect, destPoint, context()->platformContext()->canvas()->getDevice(), m_size); 349231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 350231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 3512bde8e466a4451c7319e3a072d118917957d6554Steve Blocktemplate <typename T> 3522bde8e466a4451c7319e3a072d118917957d6554Steve Blockstatic String ImageToDataURL(T& source, const String& mimeType, const double* quality) 3532bde8e466a4451c7319e3a072d118917957d6554Steve Block{ 3542daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)); 3552daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 3562bde8e466a4451c7319e3a072d118917957d6554Steve Block Vector<unsigned char> encodedImage; 3572bde8e466a4451c7319e3a072d118917957d6554Steve Block if (mimeType == "image/jpeg") { 3582bde8e466a4451c7319e3a072d118917957d6554Steve Block int compressionQuality = JPEGImageEncoder::DefaultCompressionQuality; 3592bde8e466a4451c7319e3a072d118917957d6554Steve Block if (quality && *quality >= 0.0 && *quality <= 1.0) 3602bde8e466a4451c7319e3a072d118917957d6554Steve Block compressionQuality = static_cast<int>(*quality * 100 + 0.5); 3612bde8e466a4451c7319e3a072d118917957d6554Steve Block if (!JPEGImageEncoder::encode(source, compressionQuality, &encodedImage)) 3622bde8e466a4451c7319e3a072d118917957d6554Steve Block return "data:,"; 3632bde8e466a4451c7319e3a072d118917957d6554Steve Block } else { 3642bde8e466a4451c7319e3a072d118917957d6554Steve Block if (!PNGImageEncoder::encode(source, &encodedImage)) 3652bde8e466a4451c7319e3a072d118917957d6554Steve Block return "data:,"; 3662bde8e466a4451c7319e3a072d118917957d6554Steve Block ASSERT(mimeType == "image/png"); 3672bde8e466a4451c7319e3a072d118917957d6554Steve Block } 3682bde8e466a4451c7319e3a072d118917957d6554Steve Block 3692bde8e466a4451c7319e3a072d118917957d6554Steve Block Vector<char> base64Data; 3702bde8e466a4451c7319e3a072d118917957d6554Steve Block base64Encode(*reinterpret_cast<Vector<char>*>(&encodedImage), base64Data); 3712bde8e466a4451c7319e3a072d118917957d6554Steve Block 3722bde8e466a4451c7319e3a072d118917957d6554Steve Block return makeString("data:", mimeType, ";base64,", base64Data); 3732bde8e466a4451c7319e3a072d118917957d6554Steve Block} 3742bde8e466a4451c7319e3a072d118917957d6554Steve Block 375f05b935882198ccf7d81675736e3aeb089c5113aBen MurdochString ImageBuffer::toDataURL(const String& mimeType, const double* quality) const 376635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 3772fc2651226baac27029e38c9d6ef883fa32084dbSteve Block SkDevice* device = context()->platformContext()->canvas()->getDevice(); 3782fc2651226baac27029e38c9d6ef883fa32084dbSteve Block SkBitmap bitmap = device->accessBitmap(false); 3792fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 3802fc2651226baac27029e38c9d6ef883fa32084dbSteve Block // if we can't see the pixels directly, call readPixels() to get a copy. 3812fc2651226baac27029e38c9d6ef883fa32084dbSteve Block // this could happen if the device is backed by a GPU. 3822fc2651226baac27029e38c9d6ef883fa32084dbSteve Block bitmap.lockPixels(); // balanced by our destructor, or explicitly if getPixels() fails 3832fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (!bitmap.getPixels()) { 3842fc2651226baac27029e38c9d6ef883fa32084dbSteve Block bitmap.unlockPixels(); 3852fc2651226baac27029e38c9d6ef883fa32084dbSteve Block SkIRect bounds = SkIRect::MakeWH(device->width(), device->height()); 3862fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (!device->readPixels(bounds, &bitmap)) 3872fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return "data:,"; 3882fc2651226baac27029e38c9d6ef883fa32084dbSteve Block } 389f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 3902bde8e466a4451c7319e3a072d118917957d6554Steve Block return ImageToDataURL(bitmap, mimeType, quality); 3912bde8e466a4451c7319e3a072d118917957d6554Steve Block} 392f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 3932bde8e466a4451c7319e3a072d118917957d6554Steve BlockString ImageDataToDataURL(const ImageData& source, const String& mimeType, const double* quality) 3942bde8e466a4451c7319e3a072d118917957d6554Steve Block{ 3952bde8e466a4451c7319e3a072d118917957d6554Steve Block return ImageToDataURL(source, mimeType, quality); 396635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 397635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 398635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} // namespace WebCore 399