Beispiel #1
0
static void loadBufferingImageData()
{
    static bool loaded = false;
    if (!loaded) {
        static Image* bufferingIcon = Image::loadPlatformResource("vidbuffer").leakRef();
        NativeImageSkia* nativeImage = bufferingIcon->nativeImageForCurrentFrame();
        if (!nativeImage)
            return;

        if (!nativeImage->isDataComplete())
            return;

        loaded = true;
        nativeImage->lockPixels();

        int bufSize = nativeImage->width() * nativeImage->height() * 4;
        s_bufferingImageWidth = nativeImage->width();
        s_bufferingImageHeight = nativeImage->height();
        s_bufferingImageData = static_cast<char*>(malloc(bufSize));
        memcpy(s_bufferingImageData, nativeImage->getPixels(), bufSize);

        nativeImage->unlockPixels();
        bufferingIcon->deref();
    }
}
bool GraphicsContext3D::getImageData(Image* image,
                                     GC3Denum format,
                                     GC3Denum type,
                                     bool premultiplyAlpha,
                                     bool ignoreGammaAndColorProfile,
                                     Vector<uint8_t>& outputVector)
{
    if (!image)
        return false;
    OwnPtr<NativeImageSkia> pixels;
    NativeImageSkia* skiaImage = 0;
    AlphaOp neededAlphaOp = AlphaDoNothing;
    bool hasAlpha = image->isBitmapImage() ? static_cast<BitmapImage*>(image)->frameHasAlphaAtIndex(0) : true;
    if ((ignoreGammaAndColorProfile || (hasAlpha && !premultiplyAlpha)) && image->data()) {
        ImageSource decoder(ImageSource::AlphaNotPremultiplied,
                            ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied);
        // Attempt to get raw unpremultiplied image data 
        decoder.setData(image->data(), true);
        if (!decoder.frameCount() || !decoder.frameIsCompleteAtIndex(0))
            return false;
        hasAlpha = decoder.frameHasAlphaAtIndex(0);
        pixels = adoptPtr(decoder.createFrameAtIndex(0));
        if (!pixels.get() || !pixels->isDataComplete() || !pixels->width() || !pixels->height())
            return false;
        SkBitmap::Config skiaConfig = pixels->config();
        if (skiaConfig != SkBitmap::kARGB_8888_Config)
            return false;
        skiaImage = pixels.get();
        if (hasAlpha && premultiplyAlpha)
            neededAlphaOp = AlphaDoPremultiply;
    } else {
        skiaImage = image->nativeImageForCurrentFrame();
        if (!premultiplyAlpha && hasAlpha)
            neededAlphaOp = AlphaDoUnmultiply;
    }
    if (!skiaImage)
        return false;
    SkBitmap& skiaImageRef = *skiaImage;
    SkAutoLockPixels lock(skiaImageRef);
    ASSERT(skiaImage->rowBytes() == skiaImage->width() * 4);
    outputVector.resize(skiaImage->rowBytes() * skiaImage->height());
    return packPixels(reinterpret_cast<const uint8_t*>(skiaImage->getPixels()),
                      SourceFormatBGRA8, skiaImage->width(), skiaImage->height(), 0,
                      format, type, neededAlphaOp, outputVector.data());
}
Beispiel #3
0
bool GraphicsContext3D::getImageData(Image* image,
                                     unsigned int format,
                                     unsigned int type,
                                     bool premultiplyAlpha,
                                     bool ignoreGammaAndColorProfile,
                                     Vector<uint8_t>& outputVector)
{
    if (!image)
        return false;
    OwnPtr<NativeImageSkia> pixels;
    NativeImageSkia* skiaImage = 0;
    AlphaOp neededAlphaOp = AlphaDoNothing;
    if (image->data()) {
        ImageSource decoder(ImageSource::AlphaNotPremultiplied,
                            ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied);
        decoder.setData(image->data(), true);
        if (!decoder.frameCount() || !decoder.frameIsCompleteAtIndex(0))
            return false;
        bool hasAlpha = decoder.frameHasAlphaAtIndex(0);
        pixels = adoptPtr(decoder.createFrameAtIndex(0));
        if (!pixels.get() || !pixels->isDataComplete() || !pixels->width() || !pixels->height())
            return false;
        SkBitmap::Config skiaConfig = pixels->config();
        if (skiaConfig != SkBitmap::kARGB_8888_Config)
            return false;
        skiaImage = pixels.get();
        if (hasAlpha && premultiplyAlpha)
            neededAlphaOp = AlphaDoPremultiply;
    } else {
        // This is a special case for texImage2D with HTMLCanvasElement input.
        skiaImage = image->nativeImageForCurrentFrame();
        if (!premultiplyAlpha)
            neededAlphaOp = AlphaDoUnmultiply;
    }
    if (!skiaImage)
        return false;
    SkBitmap& skiaImageRef = *skiaImage;
    SkAutoLockPixels lock(skiaImageRef);
    ASSERT(skiaImage->rowBytes() == skiaImage->width() * 4);
    outputVector.resize(skiaImage->rowBytes() * skiaImage->height());
    return packPixels(reinterpret_cast<const uint8_t*>(skiaImage->getPixels()),
                      SourceFormatBGRA8, skiaImage->width(), skiaImage->height(), 0,
                      format, type, neededAlphaOp, outputVector.data());
}
bool GraphicsContext3D::getImageData(Image* image,
                                     Vector<uint8_t>& outputVector,
                                     bool premultiplyAlpha,
                                     bool* hasAlphaChannel,
                                     AlphaOp* neededAlphaOp,
                                     unsigned int* format)
{
    if (!image)
        return false;
    NativeImageSkia* skiaImage = image->nativeImageForCurrentFrame();
    if (!skiaImage)
        return false;
    SkBitmap::Config skiaConfig = skiaImage->config();
    // FIXME: must support more image configurations.
    if (skiaConfig != SkBitmap::kARGB_8888_Config)
        return false;
    SkBitmap& skiaImageRef = *skiaImage;
    SkAutoLockPixels lock(skiaImageRef);
    int height = skiaImage->height();
    int rowBytes = skiaImage->rowBytes();
    ASSERT(rowBytes == skiaImage->width() * 4);
    uint8_t* pixels = reinterpret_cast<uint8_t*>(skiaImage->getPixels());
    outputVector.resize(rowBytes * height);
    int size = rowBytes * height;
    memcpy(outputVector.data(), pixels, size);
    *hasAlphaChannel = true;
    if (!premultiplyAlpha)
        // FIXME: must fetch the image data before the premultiplication step
        *neededAlphaOp = kAlphaDoUnmultiply;
    // Convert from BGRA to RGBA. FIXME: add GL_BGRA extension support
    // to all underlying OpenGL implementations.
    for (int i = 0; i < size; i += 4)
        std::swap(outputVector[i], outputVector[i + 2]);
    *format = RGBA;
    return true;
}
Beispiel #5
0
// Draws the given bitmap to the given canvas. The subset of the source bitmap
// identified by src_rect is drawn to the given destination rect. The bitmap
// will be resampled to resample_width * resample_height (this is the size of
// the whole image, not the subset). See shouldResampleBitmap for more.
//
// This does a lot of computation to resample only the portion of the bitmap
// that will only be drawn. This is critical for performance since when we are
// scrolling, for example, we are only drawing a small strip of the image.
// Resampling the whole image every time is very slow, so this speeds up things
// dramatically.
static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeImageSkia& bitmap, const SkIRect& srcIRect, const SkRect& destRect)
{
    // First get the subset we need. This is efficient and does not copy pixels.
    SkBitmap subset;
    bitmap.extractSubset(&subset, srcIRect);
    SkRect srcRect;
    srcRect.set(srcIRect);

    // Whether we're doing a subset or using the full source image.
    bool srcIsFull = srcIRect.fLeft == 0 && srcIRect.fTop == 0
        && srcIRect.width() == bitmap.width()
        && srcIRect.height() == bitmap.height();

    // We will always draw in integer sizes, so round the destination rect.
    SkIRect destRectRounded;
    destRect.round(&destRectRounded);
    SkIRect resizedImageRect =  // Represents the size of the resized image.
        { 0, 0, destRectRounded.width(), destRectRounded.height() };

    if (srcIsFull && bitmap.hasResizedBitmap(destRectRounded.width(), destRectRounded.height())) {
        // Yay, this bitmap frame already has a resized version.
        SkBitmap resampled = bitmap.resizedBitmap(destRectRounded.width(), destRectRounded.height());
        canvas.drawBitmapRect(resampled, 0, destRect, &paint);
        return;
    }

    // Compute the visible portion of our rect.
    SkRect destBitmapSubsetSk;
    ClipRectToCanvas(canvas, destRect, &destBitmapSubsetSk);
    destBitmapSubsetSk.offset(-destRect.fLeft, -destRect.fTop);

    // The matrix inverting, etc. could have introduced rounding error which
    // causes the bounds to be outside of the resized bitmap. We round outward
    // so we always lean toward it being larger rather than smaller than we
    // need, and then clamp to the bitmap bounds so we don't get any invalid
    // data.
    SkIRect destBitmapSubsetSkI;
    destBitmapSubsetSk.roundOut(&destBitmapSubsetSkI);
    if (!destBitmapSubsetSkI.intersect(resizedImageRect))
        return;  // Resized image does not intersect.

    if (srcIsFull && bitmap.shouldCacheResampling(
            resizedImageRect.width(),
            resizedImageRect.height(),
            destBitmapSubsetSkI.width(),
            destBitmapSubsetSkI.height())) {
        // We're supposed to resize the entire image and cache it, even though
        // we don't need all of it.
        SkBitmap resampled = bitmap.resizedBitmap(destRectRounded.width(),
                                                  destRectRounded.height());
        canvas.drawBitmapRect(resampled, 0, destRect, &paint);
    } else {
        // We should only resize the exposed part of the bitmap to do the
        // minimal possible work.

        // Resample the needed part of the image.
        SkBitmap resampled = skia::ImageOperations::Resize(subset,
            skia::ImageOperations::RESIZE_LANCZOS3,
            destRectRounded.width(), destRectRounded.height(),
            destBitmapSubsetSkI);

        // Compute where the new bitmap should be drawn. Since our new bitmap
        // may be smaller than the original, we have to shift it over by the
        // same amount that we cut off the top and left.
        destBitmapSubsetSkI.offset(destRect.fLeft, destRect.fTop);
        SkRect offsetDestRect;
        offsetDestRect.set(destBitmapSubsetSkI);

        canvas.drawBitmapRect(resampled, 0, offsetDestRect, &paint);
    }
}
void Image::drawPattern(GraphicsContext* context,
                        const FloatRect& floatSrcRect,
                        const AffineTransform& patternTransform,
                        const FloatPoint& phase,
                        ColorSpace styleColorSpace,
                        CompositeOperator compositeOp,
                        const FloatRect& destRect)
{
    FloatRect normSrcRect = normalizeRect(floatSrcRect);
    if (destRect.isEmpty() || normSrcRect.isEmpty())
        return;  // nothing to draw

    NativeImageSkia* bitmap = nativeImageForCurrentFrame();
    if (!bitmap)
        return;

    // This is a very inexpensive operation. It will generate a new bitmap but
    // it will internally reference the old bitmap's pixels, adjusting the row
    // stride so the extra pixels appear as padding to the subsetted bitmap.
    SkBitmap srcSubset;
    SkIRect srcRect = enclosingIntRect(normSrcRect);
    bitmap->extractSubset(&srcSubset, srcRect);

    SkBitmap resampled;
    SkShader* shader;

    // Figure out what size the bitmap will be in the destination. The
    // destination rect is the bounds of the pattern, we need to use the
    // matrix to see how bit it will be.
    float destBitmapWidth, destBitmapHeight;
    TransformDimensions(patternTransform, srcRect.width(), srcRect.height(),
                        &destBitmapWidth, &destBitmapHeight);

    // Compute the resampling mode.
    ResamplingMode resampling;
    if (context->platformContext()->isPrinting())
      resampling = RESAMPLE_LINEAR;
    else {
      resampling = computeResamplingMode(context->platformContext(), *bitmap,
                                         srcRect.width(), srcRect.height(),
                                         destBitmapWidth, destBitmapHeight);
    }

    // Load the transform WebKit requested.
    SkMatrix matrix(patternTransform);

    if (resampling == RESAMPLE_AWESOME) {
        // Do nice resampling.
        SkBitmap resampled;
        int width = static_cast<int>(destBitmapWidth);
        int height = static_cast<int>(destBitmapHeight);
        if (!srcRect.fLeft && !srcRect.fTop
            && srcRect.fRight == bitmap->width() && srcRect.fBottom == bitmap->height()
            && (bitmap->hasResizedBitmap(width, height)
                || bitmap->shouldCacheResampling(width, height, width, height))) {
            // resizedBitmap() caches resized image.
            resampled = bitmap->resizedBitmap(width, height);
        } else {
            resampled = skia::ImageOperations::Resize(srcSubset,
                skia::ImageOperations::RESIZE_LANCZOS3, width, height);
        }
        shader = SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);

        // Since we just resized the bitmap, we need to undo the scale set in
        // the image transform.
        matrix.setScaleX(SkIntToScalar(1));
        matrix.setScaleY(SkIntToScalar(1));
    } else {
        // No need to do nice resampling.
        shader = SkShader::CreateBitmapShader(srcSubset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
    }

    // We also need to translate it such that the origin of the pattern is the
    // origin of the destination rect, which is what WebKit expects. Skia uses
    // the coordinate system origin as the base for the patter. If WebKit wants
    // a shifted image, it will shift it from there using the patternTransform.
    float adjustedX = phase.x() + normSrcRect.x() *
                      narrowPrecisionToFloat(patternTransform.a());
    float adjustedY = phase.y() + normSrcRect.y() *
                      narrowPrecisionToFloat(patternTransform.d());
    matrix.postTranslate(SkFloatToScalar(adjustedX),
                         SkFloatToScalar(adjustedY));
    shader->setLocalMatrix(matrix);

    SkPaint paint;
    paint.setShader(shader)->unref();
    paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp));
    paint.setFilterBitmap(resampling == RESAMPLE_LINEAR);

    context->platformContext()->paintSkPaint(destRect, paint);
}