ImageSkia.cpp revision 65f03d4f644ce73618e5f4f50dd694b26f55ae12
1635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project/* 2635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * Copyright (c) 2008, Google Inc. All rights reserved. 3635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * 4635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * Redistribution and use in source and binary forms, with or without 5635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * modification, are permitted provided that the following conditions are 6635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * met: 7635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * 8635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * * Redistributions of source code must retain the above copyright 9635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * notice, this list of conditions and the following disclaimer. 10635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * * Redistributions in binary form must reproduce the above 11635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * copyright notice, this list of conditions and the following disclaimer 12635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * in the documentation and/or other materials provided with the 13635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * distribution. 14635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * * Neither the name of Google Inc. nor the names of its 15635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * contributors may be used to endorse or promote products derived from 16635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * this software without specific prior written permission. 17635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * 18635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project */ 30635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 31635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "config.h" 32635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 338a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block#include "AffineTransform.h" 34635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "BitmapImage.h" 35635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "BitmapImageSingleFrameSkia.h" 36635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "FloatConversion.h" 37635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "FloatRect.h" 385ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen#include "GLES2Canvas.h" 39635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "GraphicsContext.h" 40635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "Logging.h" 41635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "NativeImageSkia.h" 42635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "PlatformContextSkia.h" 43635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "PlatformString.h" 445ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen#include "SkPixelRef.h" 45231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "SkRect.h" 46635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "SkShader.h" 475ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen#include "SkiaUtils.h" 485abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick#include "Texture.h" 49635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 50635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "skia/ext/image_operations.h" 51635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "skia/ext/platform_canvas.h" 52635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 53635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectnamespace WebCore { 54635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 55635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// Used by computeResamplingMode to tell how bitmaps should be resampled. 56635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectenum ResamplingMode { 57635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Nearest neighbor resampling. Used when we detect that the page is 58635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // trying to make a pattern by stretching a small bitmap very large. 59635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project RESAMPLE_NONE, 60635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 61635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Default skia resampling. Used for large growing of images where high 62635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // quality resampling doesn't get us very much except a slowdown. 63635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project RESAMPLE_LINEAR, 64635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 65635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // High quality resampling. 66635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project RESAMPLE_AWESOME, 67635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}; 68635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 695af96e2c7b73ebc627c6894727826a7576d31758Leon Clarkestatic ResamplingMode computeResamplingMode(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, int srcWidth, int srcHeight, float destWidth, float destHeight) 70635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 71545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch if (platformContext->hasImageResamplingHint()) { 72545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch IntSize srcSize; 73545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch FloatSize dstSize; 74545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch platformContext->getImageResamplingHint(&srcSize, &dstSize); 75545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch srcWidth = srcSize.width(); 76545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch srcHeight = srcSize.height(); 77545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch destWidth = dstSize.width(); 78545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch destHeight = dstSize.height(); 79545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch } 80545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch 81635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project int destIWidth = static_cast<int>(destWidth); 82635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project int destIHeight = static_cast<int>(destHeight); 83635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 84635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // The percent change below which we will not resample. This usually means 85635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // an off-by-one error on the web page, and just doing nearest neighbor 86635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // sampling is usually good enough. 87635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project const float kFractionalChangeThreshold = 0.025f; 88635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 89635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Images smaller than this in either direction are considered "small" and 90635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // are not resampled ever (see below). 91635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project const int kSmallImageSizeThreshold = 8; 92635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 93635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // The amount an image can be stretched in a single direction before we 94635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // say that it is being stretched so much that it must be a line or 95635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // background that doesn't need resampling. 96635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project const float kLargeStretch = 3.0f; 97635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 98635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Figure out if we should resample this image. We try to prune out some 99635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // common cases where resampling won't give us anything, since it is much 100635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // slower than drawing stretched. 101635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (srcWidth == destIWidth && srcHeight == destIHeight) { 102635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // We don't need to resample if the source and destination are the same. 103635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return RESAMPLE_NONE; 104635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 105635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 106635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (srcWidth <= kSmallImageSizeThreshold 107635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project || srcHeight <= kSmallImageSizeThreshold 108635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project || destWidth <= kSmallImageSizeThreshold 109635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project || destHeight <= kSmallImageSizeThreshold) { 110635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Never resample small images. These are often used for borders and 111635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // rules (think 1x1 images used to make lines). 112635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return RESAMPLE_NONE; 113635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 114635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 115635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (srcHeight * kLargeStretch <= destHeight || srcWidth * kLargeStretch <= destWidth) { 116635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Large image detected. 117635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 118635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Don't resample if it is being stretched a lot in only one direction. 119635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // This is trying to catch cases where somebody has created a border 120635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // (which might be large) and then is stretching it to fill some part 121635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // of the page. 122635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (srcWidth == destWidth || srcHeight == destHeight) 123635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return RESAMPLE_NONE; 124635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 125635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // The image is growing a lot and in more than one direction. Resampling 126635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // is slow and doesn't give us very much when growing a lot. 127635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return RESAMPLE_LINEAR; 128635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 129635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 130635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if ((fabs(destWidth - srcWidth) / srcWidth < kFractionalChangeThreshold) 131635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project && (fabs(destHeight - srcHeight) / srcHeight < kFractionalChangeThreshold)) { 132635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // It is disappointingly common on the web for image sizes to be off by 133635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // one or two pixels. We don't bother resampling if the size difference 134635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // is a small fraction of the original size. 135635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return RESAMPLE_NONE; 136635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 137635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 138635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // When the image is not yet done loading, use linear. We don't cache the 139635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // partially resampled images, and as they come in incrementally, it causes 140635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // us to have to resample the whole thing every time. 141635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (!bitmap.isDataComplete()) 142635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return RESAMPLE_LINEAR; 143635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 144635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Everything else gets resampled. 1455af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke // If the platform context permits high quality interpolation, use it. 146f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // High quality interpolation only enabled for scaling and translation. 147f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (platformContext->interpolationQuality() == InterpolationHigh 148f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch && !(platformContext->canvas()->getTotalMatrix().getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask))) 1495af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke return RESAMPLE_AWESOME; 1505af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke 1515af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke return RESAMPLE_LINEAR; 152635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 153635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 154635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// Draws the given bitmap to the given canvas. The subset of the source bitmap 155635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// identified by src_rect is drawn to the given destination rect. The bitmap 156635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// will be resampled to resample_width * resample_height (this is the size of 157635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// the whole image, not the subset). See shouldResampleBitmap for more. 158635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// 159635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// This does a lot of computation to resample only the portion of the bitmap 160635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// that will only be drawn. This is critical for performance since when we are 161635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// scrolling, for example, we are only drawing a small strip of the image. 162635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// Resampling the whole image every time is very slow, so this speeds up things 163635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// dramatically. 164635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeImageSkia& bitmap, const SkIRect& srcIRect, const SkRect& destRect) 165635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 166635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // First get the subset we need. This is efficient and does not copy pixels. 167635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkBitmap subset; 168635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project bitmap.extractSubset(&subset, srcIRect); 169635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkRect srcRect; 170635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project srcRect.set(srcIRect); 171635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 172635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Whether we're doing a subset or using the full source image. 173635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project bool srcIsFull = srcIRect.fLeft == 0 && srcIRect.fTop == 0 174635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project && srcIRect.width() == bitmap.width() 175635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project && srcIRect.height() == bitmap.height(); 176635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 177635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // We will always draw in integer sizes, so round the destination rect. 178635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkIRect destRectRounded; 179a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect.round(&destRectRounded); 180231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block SkIRect resizedImageRect = // Represents the size of the resized image. 181231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block { 0, 0, destRectRounded.width(), destRectRounded.height() }; 182635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 183f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // Apply forward transform to destRect to estimate required size of 184f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // re-sampled bitmap, and use only in calls required to resize, or that 185f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // check for the required size. 186f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch SkRect destRectTransformed; 187f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch canvas.getTotalMatrix().mapRect(&destRectTransformed, destRect); 188f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch SkIRect destRectTransformedRounded; 189f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch destRectTransformed.round(&destRectTransformedRounded); 190f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 191f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (srcIsFull && bitmap.hasResizedBitmap(destRectTransformedRounded.width(), destRectTransformedRounded.height())) { 192635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Yay, this bitmap frame already has a resized version. 193f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch SkBitmap resampled = bitmap.resizedBitmap(destRectTransformedRounded.width(), destRectTransformedRounded.height()); 194635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project canvas.drawBitmapRect(resampled, 0, destRect, &paint); 195635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return; 196635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 197635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 198635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Compute the visible portion of our rect. 199f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // We also need to compute the transformed portion of the 200f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // visible portion for use below. 201635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkRect destBitmapSubsetSk; 202635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project ClipRectToCanvas(canvas, destRect, &destBitmapSubsetSk); 203f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch SkRect destBitmapSubsetTransformed; 204f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch canvas.getTotalMatrix().mapRect(&destBitmapSubsetTransformed, destBitmapSubsetSk); 205a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destBitmapSubsetSk.offset(-destRect.fLeft, -destRect.fTop); 206f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch SkIRect destBitmapSubsetTransformedRounded; 207f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch destBitmapSubsetTransformed.round(&destBitmapSubsetTransformedRounded); 208f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch destBitmapSubsetTransformedRounded.offset(-destRectTransformedRounded.fLeft, -destRectTransformedRounded.fTop); 209635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 210635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // The matrix inverting, etc. could have introduced rounding error which 211635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // causes the bounds to be outside of the resized bitmap. We round outward 212635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // so we always lean toward it being larger rather than smaller than we 213635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // need, and then clamp to the bitmap bounds so we don't get any invalid 214635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // data. 215635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkIRect destBitmapSubsetSkI; 216a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destBitmapSubsetSk.roundOut(&destBitmapSubsetSkI); 217635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (!destBitmapSubsetSkI.intersect(resizedImageRect)) 218635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return; // Resized image does not intersect. 219635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 220545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch if (srcIsFull && bitmap.shouldCacheResampling( 221635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project resizedImageRect.width(), 222635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project resizedImageRect.height(), 223635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project destBitmapSubsetSkI.width(), 224635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project destBitmapSubsetSkI.height())) { 225635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // We're supposed to resize the entire image and cache it, even though 226635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // we don't need all of it. 227f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch SkBitmap resampled = bitmap.resizedBitmap(destRectTransformedRounded.width(), 228f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch destRectTransformedRounded.height()); 229635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project canvas.drawBitmapRect(resampled, 0, destRect, &paint); 230635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } else { 231635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // We should only resize the exposed part of the bitmap to do the 232635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // minimal possible work. 233635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 234635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Resample the needed part of the image. 235f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // Transforms above plus rounding may cause destBitmapSubsetTransformedRounded 236f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // to go outside the image, so need to clip to avoid problems. 237f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (destBitmapSubsetTransformedRounded.intersect(0, 0, 238f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch destRectTransformedRounded.width(), destRectTransformedRounded.height())) { 239f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 240f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch SkBitmap resampled = skia::ImageOperations::Resize(subset, 241f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch skia::ImageOperations::RESIZE_LANCZOS3, 242f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch destRectTransformedRounded.width(), destRectTransformedRounded.height(), 243f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch destBitmapSubsetTransformedRounded); 244f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 245f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // Compute where the new bitmap should be drawn. Since our new bitmap 246f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // may be smaller than the original, we have to shift it over by the 247f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // same amount that we cut off the top and left. 248f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch destBitmapSubsetSkI.offset(destRect.fLeft, destRect.fTop); 249f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch SkRect offsetDestRect; 250f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch offsetDestRect.set(destBitmapSubsetSkI); 251f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 252f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch canvas.drawBitmapRect(resampled, 0, offsetDestRect, &paint); 253f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch } 254635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 255635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 256635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 2570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochstatic void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, const SkIRect& srcRect, const SkRect& destRect, const SkXfermode::Mode& compOp) 258635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 259635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkPaint paint; 2600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch paint.setXfermodeMode(compOp); 2618f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian paint.setFilterBitmap(true); 262e14391e94c850b8bd03680c23b38978db68687a8John Reck paint.setAlpha(platformContext->getNormalizedAlpha()); 263635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 264635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project skia::PlatformCanvas* canvas = platformContext->canvas(); 265635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 266635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project ResamplingMode resampling = platformContext->isPrinting() ? RESAMPLE_NONE : 2675af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke computeResamplingMode(platformContext, bitmap, srcRect.width(), srcRect.height(), 268635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkScalarToFloat(destRect.width()), 269635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkScalarToFloat(destRect.height())); 270635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (resampling == RESAMPLE_AWESOME) { 271635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project drawResampledBitmap(*canvas, paint, bitmap, srcRect, destRect); 272635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } else { 273635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // No resampling necessary, we can just draw the bitmap. We want to 274635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // filter it if we decided to do linear interpolation above, or if there 275635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // is something interesting going on with the matrix (like a rotation). 276635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Note: for serialization, we will want to subset the bitmap first so 277635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // we don't send extra pixels. 278635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project canvas->drawBitmapRect(bitmap, &srcRect, destRect, &paint); 279635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 280635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 281635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 282635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// Transforms the given dimensions with the given matrix. Used to see how big 283635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// images will be once transformed. 284635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void TransformDimensions(const SkMatrix& matrix, float srcWidth, float srcHeight, float* destWidth, float* destHeight) { 285635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Transform 3 points to see how long each side of the bitmap will be. 286635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkPoint src_points[3]; // (0, 0), (width, 0), (0, height). 287635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project src_points[0].set(0, 0); 288635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project src_points[1].set(SkFloatToScalar(srcWidth), 0); 289635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project src_points[2].set(0, SkFloatToScalar(srcHeight)); 290635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 291635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Now measure the length of the two transformed vectors relative to the 292635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // transformed origin to see how big the bitmap will be. Note: for skews, 293635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // this isn't the best thing, but we don't have skews. 294635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkPoint dest_points[3]; 295635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project matrix.mapPoints(dest_points, src_points, 3); 296635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *destWidth = SkScalarToFloat((dest_points[1] - dest_points[0]).length()); 297635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *destHeight = SkScalarToFloat((dest_points[2] - dest_points[0]).length()); 298635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 299635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 300635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// A helper method for translating negative width and height values. 30165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben MurdochFloatRect normalizeRect(const FloatRect& rect) 302635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 303635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project FloatRect norm = rect; 304635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (norm.width() < 0) { 305635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project norm.setX(norm.x() + norm.width()); 306635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project norm.setWidth(-norm.width()); 307635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 308635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (norm.height() < 0) { 309635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project norm.setY(norm.y() + norm.height()); 310635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project norm.setHeight(-norm.height()); 311635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 312635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return norm; 313635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 314635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 315635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectbool FrameData::clear(bool clearMetadata) 316635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 317635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (clearMetadata) 318635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project m_haveMetadata = false; 319635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 320635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (m_frame) { 321635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // ImageSource::createFrameAtIndex() allocated |m_frame| and passed 322635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // ownership to BitmapImage; we must delete it here. 323635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project delete m_frame; 324635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project m_frame = 0; 325635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return true; 326635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 327635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return false; 328635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 329635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 330635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid Image::drawPattern(GraphicsContext* context, 331635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project const FloatRect& floatSrcRect, 3328a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block const AffineTransform& patternTransform, 333635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project const FloatPoint& phase, 334643ca7872b450ea4efacab6188849e5aac2ba161Steve Block ColorSpace styleColorSpace, 335635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project CompositeOperator compositeOp, 336635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project const FloatRect& destRect) 337635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 3385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian FloatRect normSrcRect = normalizeRect(floatSrcRect); 3395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (destRect.isEmpty() || normSrcRect.isEmpty()) 340635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return; // nothing to draw 341635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 342635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project NativeImageSkia* bitmap = nativeImageForCurrentFrame(); 343635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (!bitmap) 344635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return; 345635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 346635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // This is a very inexpensive operation. It will generate a new bitmap but 347635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // it will internally reference the old bitmap's pixels, adjusting the row 348635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // stride so the extra pixels appear as padding to the subsetted bitmap. 349635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkBitmap srcSubset; 3505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian SkIRect srcRect = enclosingIntRect(normSrcRect); 351635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project bitmap->extractSubset(&srcSubset, srcRect); 352635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 353635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkBitmap resampled; 354635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkShader* shader; 355635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 356635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Figure out what size the bitmap will be in the destination. The 357635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // destination rect is the bounds of the pattern, we need to use the 358635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // matrix to see how bit it will be. 359635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project float destBitmapWidth, destBitmapHeight; 360635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project TransformDimensions(patternTransform, srcRect.width(), srcRect.height(), 361635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project &destBitmapWidth, &destBitmapHeight); 362635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 363635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Compute the resampling mode. 364635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project ResamplingMode resampling; 365635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (context->platformContext()->isPrinting()) 366635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project resampling = RESAMPLE_LINEAR; 367635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project else { 3685af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke resampling = computeResamplingMode(context->platformContext(), *bitmap, 369635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project srcRect.width(), srcRect.height(), 370635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project destBitmapWidth, destBitmapHeight); 371635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 372635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 373635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Load the transform WebKit requested. 374635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkMatrix matrix(patternTransform); 375635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 376635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (resampling == RESAMPLE_AWESOME) { 377635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Do nice resampling. 3786c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen SkBitmap resampled; 3796c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen int width = static_cast<int>(destBitmapWidth); 3806c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen int height = static_cast<int>(destBitmapHeight); 3816c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen if (!srcRect.fLeft && !srcRect.fTop 3826c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen && srcRect.fRight == bitmap->width() && srcRect.fBottom == bitmap->height() 3836c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen && (bitmap->hasResizedBitmap(width, height) 3846c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen || bitmap->shouldCacheResampling(width, height, width, height))) { 3856c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen // resizedBitmap() caches resized image. 3866c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen resampled = bitmap->resizedBitmap(width, height); 3876c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen } else { 3886c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen resampled = skia::ImageOperations::Resize(srcSubset, 3896c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen skia::ImageOperations::RESIZE_LANCZOS3, width, height); 3906c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen } 391635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project shader = SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); 392635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 393635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Since we just resized the bitmap, we need to undo the scale set in 394635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // the image transform. 395635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project matrix.setScaleX(SkIntToScalar(1)); 396635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project matrix.setScaleY(SkIntToScalar(1)); 397635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } else { 398635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // No need to do nice resampling. 399635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project shader = SkShader::CreateBitmapShader(srcSubset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); 400635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 401635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 402635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // We also need to translate it such that the origin of the pattern is the 403635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // origin of the destination rect, which is what WebKit expects. Skia uses 404635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // the coordinate system origin as the base for the patter. If WebKit wants 405635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // a shifted image, it will shift it from there using the patternTransform. 4065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian float adjustedX = phase.x() + normSrcRect.x() * 407635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project narrowPrecisionToFloat(patternTransform.a()); 4085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian float adjustedY = phase.y() + normSrcRect.y() * 409635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project narrowPrecisionToFloat(patternTransform.d()); 410635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project matrix.postTranslate(SkFloatToScalar(adjustedX), 411635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkFloatToScalar(adjustedY)); 412635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project shader->setLocalMatrix(matrix); 413635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 414635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkPaint paint; 415635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project paint.setShader(shader)->unref(); 4160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp)); 417635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project paint.setFilterBitmap(resampling == RESAMPLE_LINEAR); 418635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 419635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project context->platformContext()->paintSkPaint(destRect, paint); 420635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 421635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 422db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Blockstatic void drawBitmapGLES2(GraphicsContext* ctxt, NativeImageSkia* bitmap, const FloatRect& srcRect, const FloatRect& dstRect, ColorSpace styleColorSpace, CompositeOperator compositeOp) 423db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block{ 424db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block ctxt->platformContext()->prepareForHardwareDraw(); 425db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block GLES2Canvas* gpuCanvas = ctxt->platformContext()->gpuCanvas(); 4265ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen Texture* texture = gpuCanvas->getTexture(bitmap); 427db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block if (!texture) { 428db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block ASSERT(bitmap->config() == SkBitmap::kARGB_8888_Config); 429db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block ASSERT(bitmap->rowBytes() == bitmap->width() * 4); 4305ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen texture = gpuCanvas->createTexture(bitmap, Texture::BGRA8, bitmap->width(), bitmap->height()); 431e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block SkAutoLockPixels lock(*bitmap); 432e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block ASSERT(bitmap->getPixels()); 433e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block texture->load(bitmap->getPixels()); 434db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block } 435db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block gpuCanvas->drawTexturedRect(texture, srcRect, dstRect, styleColorSpace, compositeOp); 436db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block} 437db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block 438635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// ================================================ 439635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// BitmapImage Class 440635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// ================================================ 441635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 442635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// FIXME: These should go to BitmapImageSkia.cpp 443635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 444635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid BitmapImage::initPlatformData() 445635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 446635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // This is not used. On Mac, the "platform" data is a cache of some OS 447635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // specific versions of the image that are created is some cases. These 448635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // aren't normally used, it is equivalent to getHBITMAP on Windows, and 449635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // the platform data is the cache. 450635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 451635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 452635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid BitmapImage::invalidatePlatformData() 453635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 454635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // See initPlatformData above. 455635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 456635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 457635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid BitmapImage::checkForSolidColor() 458635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 4598f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian m_checkedForSolidColor = true; 460635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 461635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 462635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, 463db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block const FloatRect& srcRect, ColorSpace colorSpace, CompositeOperator compositeOp) 464635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 465635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (!m_source.initialized()) 466635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return; 467635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 468635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Spin the animation to the correct frame before we try to draw it, so we 469635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // don't draw an old frame and then immediately need to draw a newer one, 470635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // causing flicker and wasting CPU. 471635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project startAnimation(); 472635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 473db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block NativeImageSkia* bm = nativeImageForCurrentFrame(); 474635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (!bm) 475635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return; // It's too early and we don't have an image yet. 476635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 477635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project FloatRect normDstRect = normalizeRect(dstRect); 478635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project FloatRect normSrcRect = normalizeRect(srcRect); 479635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 480635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (normSrcRect.isEmpty() || normDstRect.isEmpty()) 481635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return; // Nothing to draw. 482635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 4835abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick if (ctxt->platformContext()->useGPU() && ctxt->platformContext()->canAccelerate()) { 484f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick drawBitmapGLES2(ctxt, bm, normSrcRect, normDstRect, colorSpace, compositeOp); 485f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick return; 486f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick } 4875ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen 488db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block ctxt->platformContext()->prepareForSoftwareDraw(); 489db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block 490635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project paintSkBitmap(ctxt->platformContext(), 491635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *bm, 492635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project enclosingIntRect(normSrcRect), 4938f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian normDstRect, 494635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project WebCoreCompositeToSkiaComposite(compositeOp)); 495635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 496635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 497635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// FIXME: These should go into BitmapImageSingleFrameSkia.cpp 498635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 499635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt, 500635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project const FloatRect& dstRect, 501635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project const FloatRect& srcRect, 502643ca7872b450ea4efacab6188849e5aac2ba161Steve Block ColorSpace styleColorSpace, 503635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project CompositeOperator compositeOp) 504635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 505635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project FloatRect normDstRect = normalizeRect(dstRect); 506635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project FloatRect normSrcRect = normalizeRect(srcRect); 507635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 508635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (normSrcRect.isEmpty() || normDstRect.isEmpty()) 509635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return; // Nothing to draw. 510635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 5115abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick if (ctxt->platformContext()->useGPU() && ctxt->platformContext()->canAccelerate()) { 512db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block drawBitmapGLES2(ctxt, &m_nativeImage, srcRect, dstRect, styleColorSpace, compositeOp); 513db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block return; 514db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block } 515db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block 516db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block ctxt->platformContext()->prepareForSoftwareDraw(); 517db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block 518635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project paintSkBitmap(ctxt->platformContext(), 519635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project m_nativeImage, 520635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project enclosingIntRect(normSrcRect), 5218f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian normDstRect, 522635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project WebCoreCompositeToSkiaComposite(compositeOp)); 523635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 524635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 525e8b154fd68f9b33be40a3590e58347f353835f5cSteve BlockBitmapImageSingleFrameSkia::BitmapImageSingleFrameSkia(const SkBitmap& bitmap) 526e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block : m_nativeImage(bitmap) 527635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 528e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block} 529e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 530e8b154fd68f9b33be40a3590e58347f353835f5cSteve BlockPassRefPtr<BitmapImageSingleFrameSkia> BitmapImageSingleFrameSkia::create(const SkBitmap& bitmap, bool copyPixels) 531e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block{ 532e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block if (copyPixels) { 533e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block SkBitmap temp; 534e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block bitmap.copyTo(&temp, bitmap.config()); 535e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return adoptRef(new BitmapImageSingleFrameSkia(temp)); 536e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block } 537e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return adoptRef(new BitmapImageSingleFrameSkia(bitmap)); 538635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 539635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 540635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} // namespace WebCore 541