12daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch/*
22daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch * Copyright (C) 2010 Apple Inc. All rights reserved.
32daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch * Copyright (C) 2010 Google Inc. All rights reserved.
42daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch * Copyright (C) 2011 Igalia S.L.
52daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch *
62daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch * Redistribution and use in source and binary forms, with or without
72daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch * modification, are permitted provided that the following conditions
82daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch * are met:
92daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch * 1. Redistributions of source code must retain the above copyright
102daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch *    notice, this list of conditions and the following disclaimer.
112daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch * 2. Redistributions in binary form must reproduce the above copyright
122daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch *    notice, this list of conditions and the following disclaimer in the
132daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch *    documentation and/or other materials provided with the distribution.
142daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch *
152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
162daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
172daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
182daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
192daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
202daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
212daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
222daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
232daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
242daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
252daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
262daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch */
272daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
282daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#include "config.h"
292daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#include "GraphicsContext3D.h"
302daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#include "PlatformContextCairo.h"
312daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
322daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#if ENABLE(WEBGL)
332daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
342daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#include "Image.h"
352daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#include "RefPtrCairo.h"
362daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#include <cairo.h>
372daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#include <wtf/PassOwnPtr.h>
382daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
392daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochnamespace WebCore {
402daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
412daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochbool GraphicsContext3D::getImageData(Image* image, unsigned int format, unsigned int type, bool premultiplyAlpha, bool ignoreGammaAndColorProfile, Vector<uint8_t>& outputVector)
422daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
432daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (!image)
442daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return false;
452daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    // We need this to stay in scope because the native image is just a shallow copy of the data.
462daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    ImageSource decoder(premultiplyAlpha ? ImageSource::AlphaPremultiplied : ImageSource::AlphaNotPremultiplied,
472daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                        ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied);
482daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    AlphaOp alphaOp = AlphaDoNothing;
492daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    RefPtr<cairo_surface_t> imageSurface;
502daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (image->data()) {
512daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        decoder.setData(image->data(), true);
522daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        if (!decoder.frameCount() || !decoder.frameIsCompleteAtIndex(0))
532daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            return false;
542daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        imageSurface = decoder.createFrameAtIndex(0);
552daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    } else {
562daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        imageSurface = image->nativeImageForCurrentFrame();
572daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        if (!premultiplyAlpha)
582daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            alphaOp = AlphaDoUnmultiply;
592daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    }
602daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
612daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (!imageSurface)
622daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return false;
632daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
642daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    int width = cairo_image_surface_get_width(imageSurface.get());
652daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    int height = cairo_image_surface_get_height(imageSurface.get());
662daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (!width || !height)
672daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return false;
682daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
692daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (cairo_image_surface_get_format(imageSurface.get()) != CAIRO_FORMAT_ARGB32)
702daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return false;
712daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
722daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    unsigned int srcUnpackAlignment = 1;
732daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    size_t bytesPerRow = cairo_image_surface_get_stride(imageSurface.get());
742daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    size_t bitsPerPixel = 32;
752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    unsigned int padding = bytesPerRow - bitsPerPixel / 8 * width;
762daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (padding) {
772daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        srcUnpackAlignment = padding + 1;
782daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        while (bytesPerRow % srcUnpackAlignment)
792daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch            ++srcUnpackAlignment;
802daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    }
812daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
822daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    outputVector.resize(width * height * 4);
832daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    return packPixels(cairo_image_surface_get_data(imageSurface.get()), SourceFormatBGRA8,
842daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch                      width, height, srcUnpackAlignment, format, type, alphaOp, outputVector.data());
852daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
862daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
872daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochvoid GraphicsContext3D::paintToCanvas(const unsigned char* imagePixels, int imageWidth, int imageHeight, int canvasWidth, int canvasHeight, PlatformContextCairo* context)
882daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
892daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    if (!imagePixels || imageWidth <= 0 || imageHeight <= 0 || canvasWidth <= 0 || canvasHeight <= 0 || !context)
902daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        return;
912daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
922daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    cairo_t *cr = context->cr();
932daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    context->save();
942daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
952daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    cairo_rectangle(cr, 0, 0, canvasWidth, canvasHeight);
962daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
972daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    cairo_paint(cr);
982daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
992daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    RefPtr<cairo_surface_t> imageSurface = adoptRef(cairo_image_surface_create_for_data(
1002daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch        const_cast<unsigned char*>(imagePixels), CAIRO_FORMAT_ARGB32, imageWidth, imageHeight, imageWidth * 4));
1012daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1022daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    // OpenGL keeps the pixels stored bottom up, so we need to flip the image here.
1032daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    cairo_translate(cr, 0, imageHeight);
1042daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    cairo_scale(cr, 1, -1);
1052daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1062daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1072daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    cairo_set_source_surface(cr, imageSurface.get(), 0, 0);
1082daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    cairo_rectangle(cr, 0, 0, canvasWidth, -canvasHeight);
1092daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1102daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    cairo_fill(cr);
1112daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    context->restore();
1122daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
1132daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1142daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochvoid GraphicsContext3D::setContextLostCallback(PassOwnPtr<ContextLostCallback>)
1152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
1162daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
1172daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1182daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} // namespace WebCore
1192daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1202daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#endif // ENABLE(WEBGL)
121