static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, const SkIRect& srcRect, const SkRect& destRect, const SkXfermode::Mode& compOp) { #if PLATFORM(CHROMIUM) TRACE_EVENT("paintSkBitmap", platformContext, 0); #endif SkPaint paint; paint.setXfermodeMode(compOp); paint.setFilterBitmap(true); paint.setAlpha(platformContext->getNormalizedAlpha()); paint.setLooper(platformContext->getDrawLooper()); // only antialias if we're rotated or skewed paint.setAntiAlias(hasNon90rotation(platformContext)); SkCanvas* canvas = platformContext->canvas(); ResamplingMode resampling; if (platformContext->isAccelerated()) resampling = RESAMPLE_LINEAR; else resampling = platformContext->printing() ? RESAMPLE_NONE : computeResamplingMode(platformContext, bitmap, srcRect.width(), srcRect.height(), SkScalarToFloat(destRect.width()), SkScalarToFloat(destRect.height())); if (resampling == RESAMPLE_AWESOME) { drawResampledBitmap(*canvas, paint, bitmap, srcRect, destRect); } else { // No resampling necessary, we can just draw the bitmap. We want to // filter it if we decided to do linear interpolation above, or if there // is something interesting going on with the matrix (like a rotation). // Note: for serialization, we will want to subset the bitmap first so // we don't send extra pixels. canvas->drawBitmapRect(bitmap.bitmap(), &srcRect, destRect, &paint); } platformContext->didDrawRect(destRect, paint, &bitmap.bitmap()); }
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace colorSpace, CompositeOperator compositeOp, RespectImageOrientationEnum shouldRespectImageOrientation) { if (!m_source.initialized()) return; // Spin the animation to the correct frame before we try to draw it, so we // don't draw an old frame and then immediately need to draw a newer one, // causing flicker and wasting CPU. startAnimation(); NativeImageSkia* bm = nativeImageForCurrentFrame(); if (!bm) return; // It's too early and we don't have an image yet. FloatRect normDstRect = normalizeRect(dstRect); FloatRect normSrcRect = normalizeRect(srcRect); normSrcRect.intersect(FloatRect(0, 0, bm->bitmap().width(), bm->bitmap().height())); if (normSrcRect.isEmpty() || normDstRect.isEmpty()) return; // Nothing to draw. ImageOrientation orientation = DefaultImageOrientation; if (shouldRespectImageOrientation == RespectImageOrientation) orientation = frameOrientationAtIndex(m_currentFrame); GraphicsContextStateSaver saveContext(*ctxt, false); if (orientation != DefaultImageOrientation) { saveContext.save(); // ImageOrientation expects the origin to be at (0, 0) ctxt->translate(normDstRect.x(), normDstRect.y()); normDstRect.setLocation(FloatPoint()); ctxt->concatCTM(orientation.transformFromDefault(normDstRect.size())); if (orientation.usesWidthAsHeight()) { // The destination rect will have it's width and height already reversed for the orientation of // the image, as it was needed for page layout, so we need to reverse it back here. normDstRect = FloatRect(normDstRect.x(), normDstRect.y(), normDstRect.height(), normDstRect.width()); } } paintSkBitmap(ctxt->platformContext(), *bm, normSrcRect, normDstRect, WebCoreCompositeToSkiaComposite(compositeOp)); if (ImageObserver* observer = imageObserver()) observer->didDraw(this); }
static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, const SkIRect& srcRect, const SkRect& destRect, const SkXfermode::Mode& compOp) { #if PLATFORM(CHROMIUM) TRACE_EVENT0("skia", "paintSkBitmap"); #endif SkPaint paint; paint.setXfermodeMode(compOp); paint.setAlpha(platformContext->getNormalizedAlpha()); paint.setLooper(platformContext->getDrawLooper()); // only antialias if we're rotated or skewed paint.setAntiAlias(hasNon90rotation(platformContext)); SkCanvas* canvas = platformContext->canvas(); ResamplingMode resampling; if (platformContext->isAccelerated()) resampling = RESAMPLE_LINEAR; else if (platformContext->printing()) resampling = RESAMPLE_NONE; else { // Take into account scale applied to the canvas when computing sampling mode (e.g. CSS scale or page scale). SkRect destRectTarget = destRect; if (!(canvas->getTotalMatrix().getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask))) canvas->getTotalMatrix().mapRect(&destRectTarget, destRect); resampling = computeResamplingMode(canvas->getTotalMatrix(), bitmap, srcRect.width(), srcRect.height(), SkScalarToFloat(destRectTarget.width()), SkScalarToFloat(destRectTarget.height())); } if (resampling == RESAMPLE_NONE) { // FIXME: This is to not break tests (it results in the filter bitmap flag // being set to true). We need to decide if we respect RESAMPLE_NONE // being returned from computeResamplingMode. resampling = RESAMPLE_LINEAR; } resampling = limitResamplingMode(platformContext, resampling); paint.setFilterBitmap(resampling == RESAMPLE_LINEAR); if (resampling == RESAMPLE_AWESOME) drawResampledBitmap(*canvas, paint, bitmap, srcRect, destRect); else { // No resampling necessary, we can just draw the bitmap. We want to // filter it if we decided to do linear interpolation above, or if there // is something interesting going on with the matrix (like a rotation). // Note: for serialization, we will want to subset the bitmap first so // we don't send extra pixels. canvas->drawBitmapRect(bitmap.bitmap(), &srcRect, destRect, &paint); } platformContext->didDrawRect(destRect, paint, &bitmap.bitmap()); }
void GraphicsLayerChromium::setContentsToImage(Image* image) { bool childrenChanged = false; NativeImageSkia* nativeImage = image ? image->nativeImageForCurrentFrame() : 0; if (nativeImage) { if (m_contentsLayerPurpose != ContentsLayerForImage) { m_imageLayer = adoptPtr(Platform::current()->compositorSupport()->createImageLayer()); registerContentsLayer(m_imageLayer->layer()); setupContentsLayer(m_imageLayer->layer()); m_contentsLayerPurpose = ContentsLayerForImage; childrenChanged = true; } m_imageLayer->setBitmap(nativeImage->bitmap()); m_imageLayer->layer()->setOpaque(image->isBitmapImage() && !image->currentFrameHasAlpha()); updateContentsRect(); } else { if (m_imageLayer) { childrenChanged = true; unregisterContentsLayer(m_imageLayer->layer()); m_imageLayer.clear(); } // The old contents layer will be removed via updateChildList. m_contentsLayer = 0; } if (childrenChanged) updateChildList(); }
void GraphicsLayerChromium::setContentsToImage(Image* image) { bool childrenChanged = false; if (image) { if (m_contentsLayer.isNull() || m_contentsLayerPurpose != ContentsLayerForImage) { WebKit::WebImageLayer imageLayer = WebKit::WebImageLayer::create(); setupContentsLayer(imageLayer); m_contentsLayerPurpose = ContentsLayerForImage; childrenChanged = true; } WebKit::WebImageLayer imageLayer = m_contentsLayer.to<WebKit::WebImageLayer>(); NativeImageSkia* nativeImage = image->nativeImageForCurrentFrame(); imageLayer.setBitmap(nativeImage->bitmap()); imageLayer.setOpaque(image->isBitmapImage() && !image->currentFrameHasAlpha()); updateContentsRect(); } else { if (!m_contentsLayer.isNull()) { childrenChanged = true; // The old contents layer will be removed via updateChildList. m_contentsLayer.reset(); } } if (childrenChanged) updateChildList(); }
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->bitmap().lockPixels(); int bufSize = nativeImage->bitmap().width() * nativeImage->bitmap().height() * 4; s_bufferingImageWidth = nativeImage->bitmap().width(); s_bufferingImageHeight = nativeImage->bitmap().height(); s_bufferingImageData = static_cast<char*>(malloc(bufSize)); memcpy(s_bufferingImageData, nativeImage->bitmap().getPixels(), bufSize); nativeImage->bitmap().unlockPixels(); bufferingIcon->deref(); } }
DragImageRef createDragImageFromImage(Image* image, RespectImageOrientationEnum shouldRespectImageOrientation) { if (!image) return 0; NativeImageSkia* bitmap = image->nativeImageForCurrentFrame(); if (!bitmap) return 0; DragImageChromium* dragImageChromium = new DragImageChromium; dragImageChromium->bitmap = new SkBitmap(); dragImageChromium->resolutionScale = bitmap->resolutionScale(); if (image->isBitmapImage()) { ImageOrientation orientation = DefaultImageOrientation; BitmapImage* bitmapImage = static_cast<BitmapImage*>(image); IntSize sizeRespectingOrientation = bitmapImage->sizeRespectingOrientation(); if (shouldRespectImageOrientation == RespectImageOrientation) orientation = bitmapImage->currentFrameOrientation(); if (orientation != DefaultImageOrientation) { // Construct a correctly-rotated copy of the image to use as the drag image. dragImageChromium->bitmap->setConfig( SkBitmap::kARGB_8888_Config, sizeRespectingOrientation.width(), sizeRespectingOrientation.height()); dragImageChromium->bitmap->allocPixels(); FloatRect destRect(FloatPoint(), sizeRespectingOrientation); SkCanvas canvas(*dragImageChromium->bitmap); canvas.concat(orientation.transformFromDefault(sizeRespectingOrientation)); if (orientation.usesWidthAsHeight()) destRect = FloatRect(destRect.x(), destRect.y(), destRect.height(), destRect.width()); canvas.drawBitmapRect(bitmap->bitmap(), 0, destRect); return dragImageChromium; } } bitmap->bitmap().copyTo(dragImageChromium->bitmap, SkBitmap::kARGB_8888_Config); return dragImageChromium; }
// This function is used to scale an image and extract a scaled fragment. // // ALGORITHM // // Because the scaled image size has to be integers, we approximate the real // scale with the following formula (only X direction is shown): // // scaledImageWidth = round(scaleX * imageRect.width()) // approximateScaleX = scaledImageWidth / imageRect.width() // // With this method we maintain a constant scale factor among fragments in // the scaled image. This allows fragments to stitch together to form the // full scaled image. The downside is there will be a small difference // between |scaleX| and |approximateScaleX|. // // A scaled image fragment is identified by: // // - Scaled image size // - Scaled image fragment rectangle (IntRect) // // Scaled image size has been determined and the next step is to compute the // rectangle for the scaled image fragment which needs to be an IntRect. // // scaledSrcRect = srcRect * (approximateScaleX, approximateScaleY) // enclosingScaledSrcRect = enclosingIntRect(scaledSrcRect) // // Finally we extract the scaled image fragment using // (scaledImageSize, enclosingScaledSrcRect). // static SkBitmap extractScaledImageFragment(const NativeImageSkia& bitmap, const SkRect& srcRect, float scaleX, float scaleY, SkRect* scaledSrcRect, SkIRect* enclosingScaledSrcRect) { SkISize imageSize = SkISize::Make(bitmap.bitmap().width(), bitmap.bitmap().height()); SkISize scaledImageSize = SkISize::Make(clampToInteger(roundf(imageSize.width() * scaleX)), clampToInteger(roundf(imageSize.height() * scaleY))); SkRect imageRect = SkRect::MakeWH(imageSize.width(), imageSize.height()); SkRect scaledImageRect = SkRect::MakeWH(scaledImageSize.width(), scaledImageSize.height()); SkMatrix scaleTransform; scaleTransform.setRectToRect(imageRect, scaledImageRect, SkMatrix::kFill_ScaleToFit); scaleTransform.mapRect(scaledSrcRect, srcRect); scaledSrcRect->intersect(scaledImageRect); *enclosingScaledSrcRect = enclosingIntRect(*scaledSrcRect); // |enclosingScaledSrcRect| can be larger than |scaledImageSize| because // of float inaccuracy so clip to get inside. enclosingScaledSrcRect->intersect(SkIRect::MakeSize(scaledImageSize)); return bitmap.resizedBitmap(scaledImageSize, *enclosingScaledSrcRect); }
DragImageRef createDragImageFromImage(Image* image) { if (!image) return 0; NativeImageSkia* bitmap = image->nativeImageForCurrentFrame(); if (!bitmap) return 0; SkBitmap* dragImage = new SkBitmap(); bitmap->bitmap().copyTo(dragImage, SkBitmap::kARGB_8888_Config); return dragImage; }
DragImageRef createDragImageFromImage(Image* image, RespectImageOrientationEnum) { if (!image) return 0; NativeImageSkia* bitmap = image->nativeImageForCurrentFrame(); if (!bitmap) return 0; SkBitmap* dragImage = new SkBitmap(); bitmap->bitmap().copyTo(dragImage, SkBitmap::kARGB_8888_Config); DragImageChromium* dragImageChromium = new DragImageChromium; dragImageChromium->bitmap = dragImage; dragImageChromium->resolutionScale = bitmap->resolutionScale(); return dragImageChromium; }
bool FEComponentTransfer::platformApplySkia() { FilterEffect* in = inputEffect(0); ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return false; RefPtr<Image> image = in->asImageBuffer()->copyImage(DontCopyBackingStore); NativeImageSkia* nativeImage = image->nativeImageForCurrentFrame(); if (!nativeImage) return false; unsigned char rValues[256], gValues[256], bValues[256], aValues[256]; getValues(rValues, gValues, bValues, aValues); SkPaint paint; paint.setColorFilter(SkTableColorFilter::CreateARGB(aValues, rValues, gValues, bValues))->unref(); paint.setXfermodeMode(SkXfermode::kSrc_Mode); resultImage->context()->platformContext()->drawBitmap(nativeImage->bitmap(), 0, 0, &paint); return true; }
void Image::drawPattern(GraphicsContext* context, const FloatRect& floatSrcRect, const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator compositeOp, const FloatRect& destRect) { #if PLATFORM(CHROMIUM) TRACE_EVENT0("skia", "Image::drawPattern"); #endif FloatRect normSrcRect = normalizeRect(floatSrcRect); if (destRect.isEmpty() || normSrcRect.isEmpty()) return; // nothing to draw NativeImageSkia* bitmap = nativeImageForCurrentFrame(); if (!bitmap) return; SkMatrix ctm = context->platformContext()->canvas()->getTotalMatrix(); SkMatrix totalMatrix; totalMatrix.setConcat(ctm, patternTransform); // 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 big it will be. SkRect destRectTarget; totalMatrix.mapRect(&destRectTarget, normSrcRect); float destBitmapWidth = SkScalarToFloat(destRectTarget.width()); float destBitmapHeight = SkScalarToFloat(destRectTarget.height()); // Compute the resampling mode. ResamplingMode resampling; if (context->platformContext()->isAccelerated() || context->platformContext()->printing()) resampling = RESAMPLE_LINEAR; else resampling = computeResamplingMode(totalMatrix, *bitmap, normSrcRect.width(), normSrcRect.height(), destBitmapWidth, destBitmapHeight); resampling = limitResamplingMode(context->platformContext(), resampling); // Load the transform WebKit requested. SkMatrix matrix(patternTransform); SkShader* shader; if (resampling == RESAMPLE_AWESOME) { // Do nice resampling. float scaleX = destBitmapWidth / normSrcRect.width(); float scaleY = destBitmapHeight / normSrcRect.height(); SkRect scaledSrcRect; SkIRect enclosingScaledSrcRect; // The image fragment generated here is not exactly what is // requested. The scale factor used is approximated and image // fragment is slightly larger to align to integer // boundaries. SkBitmap resampled = extractScaledImageFragment(*bitmap, normSrcRect, scaleX, scaleY, &scaledSrcRect, &enclosingScaledSrcRect); shader = SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); // Since we just resized the bitmap, we need to remove the scale // applied to the pixels in the bitmap shader. This means we need // CTM * patternTransform to have identity scale. Since we // can't modify CTM (or the rectangle will be drawn in the wrong // place), we must set patternTransform's scale to the inverse of // CTM scale. matrix.setScaleX(ctm.getScaleX() ? 1 / ctm.getScaleX() : 1); matrix.setScaleY(ctm.getScaleY() ? 1 / ctm.getScaleY() : 1); } else { // No need to do nice resampling. SkBitmap srcSubset; bitmap->bitmap().extractSubset(&srcSubset, enclosingIntRect(normSrcRect)); 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); }
static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, const SkRect& srcRect, const SkRect& destRect, const SkXfermode::Mode& compOp) { #if PLATFORM(CHROMIUM) TRACE_EVENT0("skia", "paintSkBitmap"); #endif SkPaint paint; paint.setXfermodeMode(compOp); paint.setAlpha(platformContext->getNormalizedAlpha()); paint.setLooper(platformContext->getDrawLooper()); // only antialias if we're rotated or skewed paint.setAntiAlias(hasNon90rotation(platformContext)); ResamplingMode resampling; if (platformContext->isAccelerated()) resampling = RESAMPLE_LINEAR; else if (platformContext->printing()) resampling = RESAMPLE_NONE; else { // Take into account scale applied to the canvas when computing sampling mode (e.g. CSS scale or page scale). SkRect destRectTarget = destRect; if (!(platformContext->getTotalMatrix().getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask))) platformContext->getTotalMatrix().mapRect(&destRectTarget, destRect); resampling = computeResamplingMode(platformContext->getTotalMatrix(), bitmap, SkScalarToFloat(srcRect.width()), SkScalarToFloat(srcRect.height()), SkScalarToFloat(destRectTarget.width()), SkScalarToFloat(destRectTarget.height())); } if (resampling == RESAMPLE_NONE) { // FIXME: This is to not break tests (it results in the filter bitmap flag // being set to true). We need to decide if we respect RESAMPLE_NONE // being returned from computeResamplingMode. resampling = RESAMPLE_LINEAR; } resampling = limitResamplingMode(platformContext, resampling); paint.setFilterBitmap(resampling == RESAMPLE_LINEAR); if (resampling == RESAMPLE_AWESOME) drawResampledBitmap(platformContext, paint, bitmap, srcRect, destRect); else { // No resampling necessary, we can just draw the bitmap. We want to // filter it if we decided to do linear interpolation above, or if there // is something interesting going on with the matrix (like a rotation). // Note: for serialization, we will want to subset the bitmap first so // we don't send extra pixels. SkIRect enclosingSrcRect; SkRect enclosingDestRect; SkISize bitmapSize = SkISize::Make(bitmap.bitmap().width(), bitmap.bitmap().height()); bool needsClipping = computeBitmapDrawRects(bitmapSize, srcRect, destRect, &enclosingSrcRect, &enclosingDestRect); if (enclosingSrcRect.isEmpty() || enclosingDestRect.isEmpty()) return; // If destination is enlarged because source rectangle didn't align to // integer boundaries then we draw a slightly larger rectangle and clip // to the original destination rectangle. // See http://crbug.com/145540. if (needsClipping) { platformContext->save(); platformContext->clipRect(destRect); } platformContext->drawBitmapRect(bitmap.bitmap(), &enclosingSrcRect, enclosingDestRect, &paint); if (needsClipping) platformContext->restore(); } platformContext->didDrawRect(destRect, paint, &bitmap.bitmap()); }
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; SkIRect srcRect = enclosingIntRect(normSrcRect); // 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 big it will be. float destBitmapWidth, destBitmapHeight; TransformDimensions(patternTransform, srcRect.width(), srcRect.height(), &destBitmapWidth, &destBitmapHeight); // Compute the resampling mode. ResamplingMode resampling; if (context->platformContext()->isAccelerated() || context->platformContext()->printing()) resampling = RESAMPLE_LINEAR; else resampling = computeResamplingMode(context->platformContext(), *bitmap, srcRect.width(), srcRect.height(), destBitmapWidth, destBitmapHeight); // Load the transform WebKit requested. SkMatrix matrix(patternTransform); SkShader* shader; if (resampling == RESAMPLE_AWESOME) { // Do nice resampling. int width = static_cast<int>(destBitmapWidth); int height = static_cast<int>(destBitmapHeight); SkBitmap resampled = bitmap->resizedBitmap(srcRect, 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. SkBitmap srcSubset; bitmap->bitmap().extractSubset(&srcSubset, srcRect); 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); }