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