Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / platform / graphics / ImageBuffer.cpp
blobd1f305d1b878f65dc20522116998343b0293a356
1 /*
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
8 * met:
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
15 * distribution.
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.
33 #include "config.h"
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"
61 namespace blink {
63 PassOwnPtr<ImageBuffer> ImageBuffer::create(PassOwnPtr<ImageBufferSurface> surface)
65 if (!surface->isValid())
66 return nullptr;
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())
74 return nullptr;
75 return adoptPtr(new ImageBuffer(surface.release()));
78 ImageBuffer::ImageBuffer(PassOwnPtr<ImageBufferSurface> surface)
79 : m_snapshotState(InitialSnapshotState)
80 , m_surface(surface)
81 , m_client(0)
83 m_surface->setImageBuffer(this);
86 ImageBuffer::~ImageBuffer()
90 SkCanvas* ImageBuffer::canvas() const
92 if (!isSurfaceValid())
93 return nullptr;
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()
124 if (m_client)
125 m_client->didFinalizeFrame();
128 void ImageBuffer::finalizeFrame(const FloatRect &dirtyRect)
130 m_surface->finalizeFrame(dirtyRect);
131 didFinalizeFrame();
134 bool ImageBuffer::restoreSurface() const
136 return m_surface->isValid() || m_surface->restore();
139 void ImageBuffer::notifySurfaceInvalid()
141 if (m_client)
142 m_client->notifySurfaceInvalid();
145 void ImageBuffer::resetCanvas(SkCanvas* canvas) const
147 if (m_client)
148 m_client->restoreCanvasMatrixClipStack(canvas);
151 PassRefPtr<SkImage> ImageBuffer::newSkImageSnapshot() const
153 if (m_snapshotState == InitialSnapshotState)
154 m_snapshotState = DidAcquireSnapshot;
156 if (!isSurfaceValid())
157 return nullptr;
158 return m_surface->newImageSnapshot();
161 PassRefPtr<Image> ImageBuffer::newImageSnapshot() const
163 RefPtr<SkImage> snapshot = newSkImageSnapshot();
164 if (!snapshot)
165 return nullptr;
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())
184 return false;
186 if (!Extensions3DUtil::canUseCopyTextureCHROMIUM(GL_TEXTURE_2D, internalFormat, destType, level))
187 return false;
189 RefPtr<const SkImage> textureImage = m_surface->newImageSnapshot();
190 if (!textureImage)
191 return false;
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);
196 if (!textureId)
197 return false;
199 OwnPtr<WebGraphicsContext3DProvider> provider = adoptPtr(Platform::current()->createSharedOffscreenGraphicsContext3DProvider());
200 if (!provider)
201 return false;
202 WebGraphicsContext3D* sharedContext = provider->context3d();
203 if (!sharedContext)
204 return false;
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);
224 context->flush();
225 sharedContext->waitSyncPoint(context->insertSyncPoint());
227 // Undo grContext texture binding changes introduced in this function
228 provider->grContext()->resetContext(kTextureBinding_GrGLBackendState);
230 return true;
233 bool ImageBuffer::copyRenderingResultsFromDrawingBuffer(DrawingBuffer* drawingBuffer, SourceDrawingBuffer sourceBuffer)
235 if (!drawingBuffer || !m_surface->isAccelerated())
236 return false;
237 OwnPtr<WebGraphicsContext3DProvider> provider = adoptPtr(Platform::current()->createSharedOffscreenGraphicsContext3DProvider());
238 if (!provider)
239 return false;
240 WebGraphicsContext3D* context3D = provider->context3d();
241 if (!context3D)
242 return false;
243 Platform3DObject textureId = m_surface->getBackingTextureHandleForOverwrite();
244 if (!textureId)
245 return false;
247 context3D->flush();
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())
256 return;
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()) {
265 m_surface->flush();
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())
282 return false;
284 if (!isSurfaceValid()) {
285 WTF::ArrayBufferContents result(rect.width() * rect.height(), 4, WTF::ArrayBufferContents::NotShared, WTF::ArrayBufferContents::ZeroInitialize);
286 result.transfer(contents);
287 return true;
290 const bool mayHaveStrayArea =
291 m_surface->isAccelerated() // GPU readback may fail silently
292 || rect.x() < 0
293 || rect.y() < 0
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,
299 mayHaveStrayArea
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);
306 ASSERT(canvas());
307 RefPtr<SkImage> snapshot = m_surface->newImageSnapshot();
308 if (!snapshot)
309 return false;
310 snapshot->readPixels(info, result.data(), 4 * rect.width(), rect.x(), rect.y());
311 result.transfer(contents);
312 return true;
315 void ImageBuffer::putByteArray(Multiply multiplied, const unsigned char* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
317 if (!isSurfaceValid())
318 return;
320 ASSERT(sourceRect.width() > 0);
321 ASSERT(sourceRect.height() > 0);
323 int originX = sourceRect.x();
324 int destX = destPoint.x() + sourceRect.x();
325 ASSERT(destX >= 0);
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();
332 ASSERT(destY >= 0);
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))
353 return false;
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))
359 return false;
360 } else {
361 if (!PNGImageEncoder::encode(*this, encodedImage))
362 return false;
363 ASSERT(mimeType == "image/png");
366 return true;
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))
375 return "data:,";
377 return "data:" + mimeType + ";base64," + base64Encode(encodedImage);
380 } // namespace blink