Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / graphics / ImageBuffer.cpp
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.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
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.
19  *
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.
31  */
32
33 #include "config.h"
34 #include "platform/graphics/ImageBuffer.h"
35
36 #include "GrContext.h"
37 #include "platform/MIMETypeRegistry.h"
38 #include "platform/geometry/IntRect.h"
39 #include "platform/graphics/BitmapImage.h"
40 #include "platform/graphics/GraphicsContext.h"
41 #include "platform/graphics/GraphicsTypes3D.h"
42 #include "platform/graphics/ImageBufferClient.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/NativeImageSkia.h"
47 #include "platform/graphics/skia/SkiaUtils.h"
48 #include "platform/image-encoders/skia/JPEGImageEncoder.h"
49 #include "platform/image-encoders/skia/PNGImageEncoder.h"
50 #include "platform/image-encoders/skia/WEBPImageEncoder.h"
51 #include "public/platform/Platform.h"
52 #include "public/platform/WebExternalTextureMailbox.h"
53 #include "public/platform/WebGraphicsContext3D.h"
54 #include "public/platform/WebGraphicsContext3DProvider.h"
55 #include "third_party/skia/include/core/SkPicture.h"
56 #include "third_party/skia/include/effects/SkTableColorFilter.h"
57 #include "wtf/MathExtras.h"
58 #include "wtf/Vector.h"
59 #include "wtf/text/Base64.h"
60 #include "wtf/text/WTFString.h"
61
62 namespace blink {
63
64 PassOwnPtr<ImageBuffer> ImageBuffer::create(PassOwnPtr<ImageBufferSurface> surface)
65 {
66     if (!surface->isValid())
67         return nullptr;
68     return adoptPtr(new ImageBuffer(surface));
69 }
70
71 PassOwnPtr<ImageBuffer> ImageBuffer::create(const IntSize& size, OpacityMode opacityMode)
72 {
73     OwnPtr<ImageBufferSurface> surface = adoptPtr(new UnacceleratedImageBufferSurface(size, opacityMode));
74     if (!surface->isValid())
75         return nullptr;
76     return adoptPtr(new ImageBuffer(surface.release()));
77 }
78
79 ImageBuffer::ImageBuffer(PassOwnPtr<ImageBufferSurface> surface)
80     : m_surface(surface)
81     , m_client(0)
82 {
83     if (m_surface->canvas()) {
84         m_context = adoptPtr(new GraphicsContext(m_surface->canvas()));
85         m_context->setCertainlyOpaque(m_surface->opacityMode() == Opaque);
86         m_context->setAccelerated(m_surface->isAccelerated());
87     }
88     m_surface->setImageBuffer(this);
89 }
90
91 ImageBuffer::~ImageBuffer()
92 {
93 }
94
95 GraphicsContext* ImageBuffer::context() const
96 {
97     if (!isSurfaceValid())
98         return 0;
99     ASSERT(m_context.get());
100     return m_context.get();
101 }
102
103 const SkBitmap& ImageBuffer::bitmap() const
104 {
105     return m_surface->bitmap();
106 }
107
108 bool ImageBuffer::isSurfaceValid() const
109 {
110     return m_surface->isValid();
111 }
112
113 bool ImageBuffer::isDirty()
114 {
115     return m_client ? m_client->isDirty() : false;
116 }
117
118 void ImageBuffer::didFinalizeFrame()
119 {
120     if (m_client)
121         m_client->didFinalizeFrame();
122 }
123
124 void ImageBuffer::finalizeFrame(const FloatRect &dirtyRect)
125 {
126     m_surface->finalizeFrame(dirtyRect);
127     didFinalizeFrame();
128 }
129
130 bool ImageBuffer::restoreSurface() const
131 {
132     return m_surface->isValid() || m_surface->restore();
133 }
134
135 void ImageBuffer::notifySurfaceInvalid()
136 {
137     if (m_client)
138         m_client->notifySurfaceInvalid();
139 }
140
141 PassRefPtr<SkImage> ImageBuffer::newImageSnapshot() const
142 {
143     return m_surface->newImageSnapshot();
144 }
145
146 static SkBitmap deepSkBitmapCopy(const SkBitmap& bitmap)
147 {
148     SkBitmap tmp;
149     if (!bitmap.deepCopyTo(&tmp))
150         bitmap.copyTo(&tmp, bitmap.colorType());
151
152     return tmp;
153 }
154
155 PassRefPtr<Image> ImageBuffer::copyImage(BackingStoreCopy copyBehavior, ScaleBehavior) const
156 {
157     if (!isSurfaceValid())
158         return BitmapImage::create(NativeImageSkia::create());
159
160     const SkBitmap& bitmap = m_surface->bitmap();
161     return BitmapImage::create(NativeImageSkia::create(copyBehavior == CopyBackingStore ? deepSkBitmapCopy(bitmap) : bitmap));
162 }
163
164 BackingStoreCopy ImageBuffer::fastCopyImageMode()
165 {
166     return DontCopyBackingStore;
167 }
168
169 WebLayer* ImageBuffer::platformLayer() const
170 {
171     return m_surface->layer();
172 }
173
174 bool ImageBuffer::copyToPlatformTexture(WebGraphicsContext3D* context, Platform3DObject texture, GLenum internalFormat, GLenum destType, GLint level, bool premultiplyAlpha, bool flipY)
175 {
176     if (!m_surface->isAccelerated() || !getBackingTexture() || !isSurfaceValid())
177         return false;
178
179     if (!Extensions3DUtil::canUseCopyTextureCHROMIUM(internalFormat, destType, level))
180         return false;
181
182     OwnPtr<WebGraphicsContext3DProvider> provider = adoptPtr(Platform::current()->createSharedOffscreenGraphicsContext3DProvider());
183     if (!provider)
184         return false;
185     WebGraphicsContext3D* sharedContext = provider->context3d();
186     if (!sharedContext)
187         return false;
188
189     OwnPtr<WebExternalTextureMailbox> mailbox = adoptPtr(new WebExternalTextureMailbox);
190
191     // Contexts may be in a different share group. We must transfer the texture through a mailbox first
192     sharedContext->genMailboxCHROMIUM(mailbox->name);
193     sharedContext->produceTextureDirectCHROMIUM(getBackingTexture(), GL_TEXTURE_2D, mailbox->name);
194     sharedContext->flush();
195
196     mailbox->syncPoint = sharedContext->insertSyncPoint();
197
198     context->waitSyncPoint(mailbox->syncPoint);
199     Platform3DObject sourceTexture = context->createAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox->name);
200
201     // The canvas is stored in a premultiplied format, so unpremultiply if necessary.
202     context->pixelStorei(GC3D_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, !premultiplyAlpha);
203
204     // The canvas is stored in an inverted position, so the flip semantics are reversed.
205     context->pixelStorei(GC3D_UNPACK_FLIP_Y_CHROMIUM, !flipY);
206     context->copyTextureCHROMIUM(GL_TEXTURE_2D, sourceTexture, texture, level, internalFormat, destType);
207
208     context->pixelStorei(GC3D_UNPACK_FLIP_Y_CHROMIUM, false);
209     context->pixelStorei(GC3D_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, false);
210
211     context->deleteTexture(sourceTexture);
212
213     context->flush();
214     sharedContext->waitSyncPoint(context->insertSyncPoint());
215
216     // Undo grContext texture binding changes introduced in this function
217     provider->grContext()->resetContext(kTextureBinding_GrGLBackendState);
218
219     return true;
220 }
221
222 static bool drawNeedsCopy(GraphicsContext* src, GraphicsContext* dst)
223 {
224     ASSERT(dst);
225     return (src == dst);
226 }
227
228 Platform3DObject ImageBuffer::getBackingTexture()
229 {
230     return m_surface->getBackingTexture();
231 }
232
233 void ImageBuffer::didModifyBackingTexture()
234 {
235     m_surface->didModifyBackingTexture();
236 }
237
238 bool ImageBuffer::copyRenderingResultsFromDrawingBuffer(DrawingBuffer* drawingBuffer, bool fromFrontBuffer)
239 {
240     if (!drawingBuffer)
241         return false;
242     OwnPtr<WebGraphicsContext3DProvider> provider = adoptPtr(Platform::current()->createSharedOffscreenGraphicsContext3DProvider());
243     if (!provider)
244         return false;
245     WebGraphicsContext3D* context3D = provider->context3d();
246     Platform3DObject tex = m_surface->getBackingTexture();
247     if (!context3D || !tex)
248         return false;
249
250     m_surface->invalidateCachedBitmap();
251     bool result = drawingBuffer->copyToPlatformTexture(context3D, tex, GL_RGBA,
252         GL_UNSIGNED_BYTE, 0, true, false, fromFrontBuffer);
253
254     if (result) {
255         m_surface->didModifyBackingTexture();
256     }
257
258     return result;
259 }
260
261 void ImageBuffer::draw(GraphicsContext* context, const FloatRect& destRect, const FloatRect* srcPtr, CompositeOperator op, WebBlendMode blendMode)
262 {
263     if (!isSurfaceValid())
264         return;
265
266     FloatRect srcRect = srcPtr ? *srcPtr : FloatRect(FloatPoint(), size());
267     RefPtr<SkPicture> picture = m_surface->getPicture();
268     if (picture) {
269         context->drawPicture(picture.get(), destRect, srcRect, op, blendMode);
270         return;
271     }
272
273     SkBitmap bitmap = m_surface->bitmap();
274     // For ImageBufferSurface that enables cachedBitmap, Use the cached Bitmap for CPU side usage
275     // if it is available, otherwise generate and use it.
276     if (!context->isAccelerated() && m_surface->isAccelerated() && m_surface->cachedBitmapEnabled() && isSurfaceValid()) {
277         m_surface->updateCachedBitmapIfNeeded();
278         bitmap = m_surface->cachedBitmap();
279     }
280
281     RefPtr<Image> image = BitmapImage::create(NativeImageSkia::create(drawNeedsCopy(m_context.get(), context) ? deepSkBitmapCopy(bitmap) : bitmap));
282
283     context->drawImage(image.get(), destRect, srcRect, op, blendMode, DoNotRespectImageOrientation);
284 }
285
286 void ImageBuffer::flush()
287 {
288     if (m_surface->canvas()) {
289         m_surface->canvas()->flush();
290     }
291 }
292
293 void ImageBuffer::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const FloatSize& scale,
294     const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect, WebBlendMode blendMode, const IntSize& repeatSpacing)
295 {
296     if (!isSurfaceValid())
297         return;
298
299     const SkBitmap& bitmap = m_surface->bitmap();
300     RefPtr<Image> image = BitmapImage::create(NativeImageSkia::create(drawNeedsCopy(m_context.get(), context) ? deepSkBitmapCopy(bitmap) : bitmap));
301     image->drawPattern(context, srcRect, scale, phase, op, destRect, blendMode, repeatSpacing);
302 }
303
304 void ImageBuffer::transformColorSpace(ColorSpace srcColorSpace, ColorSpace dstColorSpace)
305 {
306     const uint8_t* lookUpTable = ColorSpaceUtilities::getConversionLUT(dstColorSpace, srcColorSpace);
307     if (!lookUpTable)
308         return;
309
310     // FIXME: Disable color space conversions on accelerated canvases (for now).
311     if (context()->isAccelerated() || !isSurfaceValid())
312         return;
313
314     const SkBitmap& bitmap = m_surface->bitmap();
315     if (bitmap.isNull())
316         return;
317
318     ASSERT(bitmap.colorType() == kN32_SkColorType);
319     IntSize size = m_surface->size();
320     SkAutoLockPixels bitmapLock(bitmap);
321     for (int y = 0; y < size.height(); ++y) {
322         uint32_t* srcRow = bitmap.getAddr32(0, y);
323         for (int x = 0; x < size.width(); ++x) {
324             SkColor color = SkPMColorToColor(srcRow[x]);
325             srcRow[x] = SkPreMultiplyARGB(
326                 SkColorGetA(color),
327                 lookUpTable[SkColorGetR(color)],
328                 lookUpTable[SkColorGetG(color)],
329                 lookUpTable[SkColorGetB(color)]);
330         }
331     }
332 }
333
334 PassRefPtr<SkColorFilter> ImageBuffer::createColorSpaceFilter(ColorSpace srcColorSpace,
335     ColorSpace dstColorSpace)
336 {
337     const uint8_t* lut = ColorSpaceUtilities::getConversionLUT(dstColorSpace, srcColorSpace);
338     if (!lut)
339         return nullptr;
340
341     return adoptRef(SkTableColorFilter::CreateARGB(0, lut, lut, lut));
342 }
343
344 PassRefPtr<Uint8ClampedArray> ImageBuffer::getImageData(Multiply multiplied, const IntRect& rect) const
345 {
346     if (!isSurfaceValid())
347         return Uint8ClampedArray::create(rect.width() * rect.height() * 4);
348
349     float area = 4.0f * rect.width() * rect.height();
350     if (area > static_cast<float>(std::numeric_limits<int>::max()))
351         return nullptr;
352
353     RefPtr<Uint8ClampedArray> result = Uint8ClampedArray::createUninitialized(rect.width() * rect.height() * 4);
354
355     if (rect.x() < 0
356         || rect.y() < 0
357         || rect.maxX() > m_surface->size().width()
358         || rect.maxY() > m_surface->size().height())
359         result->zeroFill();
360
361     SkAlphaType alphaType = (multiplied == Premultiplied) ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
362     SkImageInfo info = SkImageInfo::Make(rect.width(), rect.height(), kRGBA_8888_SkColorType, alphaType);
363
364     m_surface->willAccessPixels();
365     context()->readPixels(info, result->data(), 4 * rect.width(), rect.x(), rect.y());
366     return result.release();
367 }
368
369 void ImageBuffer::putByteArray(Multiply multiplied, Uint8ClampedArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
370 {
371     if (!isSurfaceValid())
372         return;
373
374     ASSERT(sourceRect.width() > 0);
375     ASSERT(sourceRect.height() > 0);
376
377     int originX = sourceRect.x();
378     int destX = destPoint.x() + sourceRect.x();
379     ASSERT(destX >= 0);
380     ASSERT(destX < m_surface->size().width());
381     ASSERT(originX >= 0);
382     ASSERT(originX < sourceRect.maxX());
383
384     int originY = sourceRect.y();
385     int destY = destPoint.y() + sourceRect.y();
386     ASSERT(destY >= 0);
387     ASSERT(destY < m_surface->size().height());
388     ASSERT(originY >= 0);
389     ASSERT(originY < sourceRect.maxY());
390
391     const size_t srcBytesPerRow = 4 * sourceSize.width();
392     const void* srcAddr = source->data() + originY * srcBytesPerRow + originX * 4;
393     SkAlphaType alphaType = (multiplied == Premultiplied) ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
394     SkImageInfo info = SkImageInfo::Make(sourceRect.width(), sourceRect.height(), kRGBA_8888_SkColorType, alphaType);
395
396     m_surface->willAccessPixels();
397
398     context()->writePixels(info, srcAddr, srcBytesPerRow, destX, destY);
399 }
400
401 template <typename T>
402 static bool encodeImage(T& source, const String& mimeType, const double* quality, Vector<char>* output)
403 {
404     Vector<unsigned char>* encodedImage = reinterpret_cast<Vector<unsigned char>*>(output);
405
406     if (mimeType == "image/jpeg") {
407         int compressionQuality = JPEGImageEncoder::DefaultCompressionQuality;
408         if (quality && *quality >= 0.0 && *quality <= 1.0)
409             compressionQuality = static_cast<int>(*quality * 100 + 0.5);
410         if (!JPEGImageEncoder::encode(source, compressionQuality, encodedImage))
411             return false;
412     } else if (mimeType == "image/webp") {
413         int compressionQuality = WEBPImageEncoder::DefaultCompressionQuality;
414         if (quality && *quality >= 0.0 && *quality <= 1.0)
415             compressionQuality = static_cast<int>(*quality * 100 + 0.5);
416         if (!WEBPImageEncoder::encode(source, compressionQuality, encodedImage))
417             return false;
418     } else {
419         if (!PNGImageEncoder::encode(source, encodedImage))
420             return false;
421         ASSERT(mimeType == "image/png");
422     }
423
424     return true;
425 }
426
427 String ImageBuffer::toDataURL(const String& mimeType, const double* quality) const
428 {
429     ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType));
430
431     Vector<char> encodedImage;
432     if (!isSurfaceValid() || !encodeImage(m_surface->bitmap(), mimeType, quality, &encodedImage))
433         return "data:,";
434
435     return "data:" + mimeType + ";base64," + base64Encode(encodedImage);
436 }
437
438 String ImageDataToDataURL(const ImageDataBuffer& imageData, const String& mimeType, const double* quality)
439 {
440     ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType));
441
442     Vector<char> encodedImage;
443     if (!encodeImage(imageData, mimeType, quality, &encodedImage))
444         return "data:,";
445
446     return "data:" + mimeType + ";base64," + base64Encode(encodedImage);
447 }
448
449 } // namespace blink