2 * Copyright (c) 2008, Google Inc. All rights reserved.
3 * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
4 * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "platform/graphics/ImageBuffer.h"
36 #include "GrContext.h"
37 #include "platform/MIMETypeRegistry.h"
38 #include "platform/geometry/IntRect.h"
39 #include "platform/graphics/GraphicsContext.h"
40 #include "platform/graphics/GraphicsTypes3D.h"
41 #include "platform/graphics/ImageBufferClient.h"
42 #include "platform/graphics/StaticBitmapImage.h"
43 #include "platform/graphics/UnacceleratedImageBufferSurface.h"
44 #include "platform/graphics/gpu/DrawingBuffer.h"
45 #include "platform/graphics/gpu/Extensions3DUtil.h"
46 #include "platform/graphics/skia/SkiaUtils.h"
47 #include "platform/image-encoders/skia/JPEGImageEncoder.h"
48 #include "platform/image-encoders/skia/PNGImageEncoder.h"
49 #include "platform/image-encoders/skia/WEBPImageEncoder.h"
50 #include "public/platform/Platform.h"
51 #include "public/platform/WebExternalTextureMailbox.h"
52 #include "public/platform/WebGraphicsContext3D.h"
53 #include "public/platform/WebGraphicsContext3DProvider.h"
54 #include "third_party/skia/include/core/SkPicture.h"
55 #include "wtf/ArrayBufferContents.h"
56 #include "wtf/MathExtras.h"
57 #include "wtf/Vector.h"
58 #include "wtf/text/Base64.h"
59 #include "wtf/text/WTFString.h"
63 PassOwnPtr
<ImageBuffer
> ImageBuffer::create(PassOwnPtr
<ImageBufferSurface
> surface
)
65 if (!surface
->isValid())
67 return adoptPtr(new ImageBuffer(surface
));
70 PassOwnPtr
<ImageBuffer
> ImageBuffer::create(const IntSize
& size
, OpacityMode opacityMode
)
72 OwnPtr
<ImageBufferSurface
> surface(adoptPtr(new UnacceleratedImageBufferSurface(size
, opacityMode
)));
73 if (!surface
->isValid())
75 return adoptPtr(new ImageBuffer(surface
.release()));
78 ImageBuffer::ImageBuffer(PassOwnPtr
<ImageBufferSurface
> surface
)
79 : m_snapshotState(InitialSnapshotState
)
83 m_surface
->setImageBuffer(this);
86 ImageBuffer::~ImageBuffer()
90 SkCanvas
* ImageBuffer::canvas() const
92 if (!isSurfaceValid())
94 return m_surface
->canvas();
97 void ImageBuffer::disableDeferral() const
99 return m_surface
->disableDeferral();
102 bool ImageBuffer::writePixels(const SkImageInfo
& info
, const void* pixels
, size_t rowBytes
, int x
, int y
)
104 return m_surface
->writePixels(info
, pixels
, rowBytes
, x
, y
);
107 const SkBitmap
& ImageBuffer::deprecatedBitmapForOverwrite() const
109 return m_surface
->deprecatedBitmapForOverwrite();
112 bool ImageBuffer::isSurfaceValid() const
114 return m_surface
->isValid();
117 bool ImageBuffer::isDirty()
119 return m_client
? m_client
->isDirty() : false;
122 void ImageBuffer::didFinalizeFrame()
125 m_client
->didFinalizeFrame();
128 void ImageBuffer::finalizeFrame(const FloatRect
&dirtyRect
)
130 m_surface
->finalizeFrame(dirtyRect
);
134 bool ImageBuffer::restoreSurface() const
136 return m_surface
->isValid() || m_surface
->restore();
139 void ImageBuffer::notifySurfaceInvalid()
142 m_client
->notifySurfaceInvalid();
145 void ImageBuffer::resetCanvas(SkCanvas
* canvas
) const
148 m_client
->restoreCanvasMatrixClipStack(canvas
);
151 PassRefPtr
<SkImage
> ImageBuffer::newSkImageSnapshot() const
153 if (m_snapshotState
== InitialSnapshotState
)
154 m_snapshotState
= DidAcquireSnapshot
;
156 if (!isSurfaceValid())
158 return m_surface
->newImageSnapshot();
161 PassRefPtr
<Image
> ImageBuffer::newImageSnapshot() const
163 RefPtr
<SkImage
> snapshot
= newSkImageSnapshot();
166 return StaticBitmapImage::create(snapshot
);
169 void ImageBuffer::didDraw(const FloatRect
& rect
) const
171 if (m_snapshotState
== DidAcquireSnapshot
)
172 m_snapshotState
= DrawnToAfterSnapshot
;
173 m_surface
->didDraw(rect
);
176 WebLayer
* ImageBuffer::platformLayer() const
178 return m_surface
->layer();
181 bool ImageBuffer::copyToPlatformTexture(WebGraphicsContext3D
* context
, Platform3DObject texture
, GLenum internalFormat
, GLenum destType
, GLint level
, bool premultiplyAlpha
, bool flipY
)
183 if (!m_surface
->isAccelerated() || !isSurfaceValid())
186 if (!Extensions3DUtil::canUseCopyTextureCHROMIUM(GL_TEXTURE_2D
, internalFormat
, destType
, level
))
189 RefPtr
<const SkImage
> textureImage
= m_surface
->newImageSnapshot();
193 ASSERT(textureImage
->isTextureBacked()); // isAccelerated() check above should guarantee this
194 // Get the texture ID, flushing pending operations if needed.
195 Platform3DObject textureId
= textureImage
->getTextureHandle(true);
199 OwnPtr
<WebGraphicsContext3DProvider
> provider
= adoptPtr(Platform::current()->createSharedOffscreenGraphicsContext3DProvider());
202 WebGraphicsContext3D
* sharedContext
= provider
->context3d();
206 OwnPtr
<WebExternalTextureMailbox
> mailbox
= adoptPtr(new WebExternalTextureMailbox
);
208 // Contexts may be in a different share group. We must transfer the texture through a mailbox first
209 sharedContext
->genMailboxCHROMIUM(mailbox
->name
);
210 sharedContext
->produceTextureDirectCHROMIUM(textureId
, GL_TEXTURE_2D
, mailbox
->name
);
211 sharedContext
->flush();
213 mailbox
->syncPoint
= sharedContext
->insertSyncPoint();
215 context
->waitSyncPoint(mailbox
->syncPoint
);
216 Platform3DObject sourceTexture
= context
->createAndConsumeTextureCHROMIUM(GL_TEXTURE_2D
, mailbox
->name
);
218 // The canvas is stored in a premultiplied format, so unpremultiply if necessary.
219 // The canvas is stored in an inverted position, so the flip semantics are reversed.
220 context
->copyTextureCHROMIUM(GL_TEXTURE_2D
, sourceTexture
, texture
, internalFormat
, destType
, flipY
? GL_FALSE
: GL_TRUE
, GL_FALSE
, premultiplyAlpha
? GL_FALSE
: GL_TRUE
);
222 context
->deleteTexture(sourceTexture
);
225 sharedContext
->waitSyncPoint(context
->insertSyncPoint());
227 // Undo grContext texture binding changes introduced in this function
228 provider
->grContext()->resetContext(kTextureBinding_GrGLBackendState
);
233 bool ImageBuffer::copyRenderingResultsFromDrawingBuffer(DrawingBuffer
* drawingBuffer
, SourceDrawingBuffer sourceBuffer
)
235 if (!drawingBuffer
|| !m_surface
->isAccelerated())
237 OwnPtr
<WebGraphicsContext3DProvider
> provider
= adoptPtr(Platform::current()->createSharedOffscreenGraphicsContext3DProvider());
240 WebGraphicsContext3D
* context3D
= provider
->context3d();
243 Platform3DObject textureId
= m_surface
->getBackingTextureHandleForOverwrite();
249 return drawingBuffer
->copyToPlatformTexture(context3D
, textureId
, GL_RGBA
,
250 GL_UNSIGNED_BYTE
, 0, true, false, sourceBuffer
);
253 void ImageBuffer::draw(GraphicsContext
* context
, const FloatRect
& destRect
, const FloatRect
* srcPtr
, SkXfermode::Mode op
)
255 if (!isSurfaceValid())
258 FloatRect srcRect
= srcPtr
? *srcPtr
: FloatRect(FloatPoint(), size());
259 m_surface
->draw(context
, destRect
, srcRect
, op
);
262 void ImageBuffer::flush()
264 if (m_surface
->canvas()) {
269 void ImageBuffer::flushGpu()
271 if (m_surface
->canvas()) {
272 m_surface
->flushGpu();
276 bool ImageBuffer::getImageData(Multiply multiplied
, const IntRect
& rect
, WTF::ArrayBufferContents
& contents
) const
278 Checked
<int, RecordOverflow
> dataSize
= 4;
279 dataSize
*= rect
.width();
280 dataSize
*= rect
.height();
281 if (dataSize
.hasOverflowed())
284 if (!isSurfaceValid()) {
285 WTF::ArrayBufferContents
result(rect
.width() * rect
.height(), 4, WTF::ArrayBufferContents::NotShared
, WTF::ArrayBufferContents::ZeroInitialize
);
286 result
.transfer(contents
);
290 const bool mayHaveStrayArea
=
291 m_surface
->isAccelerated() // GPU readback may fail silently
294 || rect
.maxX() > m_surface
->size().width()
295 || rect
.maxY() > m_surface
->size().height();
296 WTF::ArrayBufferContents
result(
297 rect
.width() * rect
.height(), 4,
298 WTF::ArrayBufferContents::NotShared
,
300 ? WTF::ArrayBufferContents::ZeroInitialize
301 : WTF::ArrayBufferContents::DontInitialize
);
303 SkAlphaType alphaType
= (multiplied
== Premultiplied
) ? kPremul_SkAlphaType
: kUnpremul_SkAlphaType
;
304 SkImageInfo info
= SkImageInfo::Make(rect
.width(), rect
.height(), kRGBA_8888_SkColorType
, alphaType
);
307 RefPtr
<SkImage
> snapshot
= m_surface
->newImageSnapshot();
310 snapshot
->readPixels(info
, result
.data(), 4 * rect
.width(), rect
.x(), rect
.y());
311 result
.transfer(contents
);
315 void ImageBuffer::putByteArray(Multiply multiplied
, const unsigned char* source
, const IntSize
& sourceSize
, const IntRect
& sourceRect
, const IntPoint
& destPoint
)
317 if (!isSurfaceValid())
320 ASSERT(sourceRect
.width() > 0);
321 ASSERT(sourceRect
.height() > 0);
323 int originX
= sourceRect
.x();
324 int destX
= destPoint
.x() + sourceRect
.x();
326 ASSERT(destX
< m_surface
->size().width());
327 ASSERT(originX
>= 0);
328 ASSERT(originX
< sourceRect
.maxX());
330 int originY
= sourceRect
.y();
331 int destY
= destPoint
.y() + sourceRect
.y();
333 ASSERT(destY
< m_surface
->size().height());
334 ASSERT(originY
>= 0);
335 ASSERT(originY
< sourceRect
.maxY());
337 const size_t srcBytesPerRow
= 4 * sourceSize
.width();
338 const void* srcAddr
= source
+ originY
* srcBytesPerRow
+ originX
* 4;
339 SkAlphaType alphaType
= (multiplied
== Premultiplied
) ? kPremul_SkAlphaType
: kUnpremul_SkAlphaType
;
340 SkImageInfo info
= SkImageInfo::Make(sourceRect
.width(), sourceRect
.height(), kRGBA_8888_SkColorType
, alphaType
);
341 m_surface
->writePixels(info
, srcAddr
, srcBytesPerRow
, destX
, destY
);
344 bool ImageDataBuffer::encodeImage(const String
& mimeType
, const double* quality
, Vector
<char>* output
) const
346 Vector
<unsigned char>* encodedImage
= reinterpret_cast<Vector
<unsigned char>*>(output
);
348 if (mimeType
== "image/jpeg") {
349 int compressionQuality
= JPEGImageEncoder::DefaultCompressionQuality
;
350 if (quality
&& *quality
>= 0.0 && *quality
<= 1.0)
351 compressionQuality
= static_cast<int>(*quality
* 100 + 0.5);
352 if (!JPEGImageEncoder::encode(*this, compressionQuality
, encodedImage
))
354 } else if (mimeType
== "image/webp") {
355 int compressionQuality
= WEBPImageEncoder::DefaultCompressionQuality
;
356 if (quality
&& *quality
>= 0.0 && *quality
<= 1.0)
357 compressionQuality
= static_cast<int>(*quality
* 100 + 0.5);
358 if (!WEBPImageEncoder::encode(*this, compressionQuality
, encodedImage
))
361 if (!PNGImageEncoder::encode(*this, encodedImage
))
363 ASSERT(mimeType
== "image/png");
369 String
ImageDataBuffer::toDataURL(const String
& mimeType
, const double* quality
) const
371 ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType
));
373 Vector
<char> encodedImage
;
374 if (!encodeImage(mimeType
, quality
, &encodedImage
))
377 return "data:" + mimeType
+ ";base64," + base64Encode(encodedImage
);