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 692daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#if !ENABLE(SKIA_GPU) 705af96e2c7b73ebc627c6894727826a7576d31758Leon Clarkestatic ResamplingMode computeResamplingMode(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, int srcWidth, int srcHeight, float destWidth, float destHeight) 71635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 72545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch if (platformContext->hasImageResamplingHint()) { 73545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch IntSize srcSize; 74545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch FloatSize dstSize; 75545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch platformContext->getImageResamplingHint(&srcSize, &dstSize); 76545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch srcWidth = srcSize.width(); 77545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch srcHeight = srcSize.height(); 78545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch destWidth = dstSize.width(); 79545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch destHeight = dstSize.height(); 80545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch } 81545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch 82635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project int destIWidth = static_cast<int>(destWidth); 83635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project int destIHeight = static_cast<int>(destHeight); 84635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 85635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // The percent change below which we will not resample. This usually means 86635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // an off-by-one error on the web page, and just doing nearest neighbor 87635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // sampling is usually good enough. 88635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project const float kFractionalChangeThreshold = 0.025f; 89635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 90635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Images smaller than this in either direction are considered "small" and 91635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // are not resampled ever (see below). 92635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project const int kSmallImageSizeThreshold = 8; 93635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 94635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // The amount an image can be stretched in a single direction before we 95635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // say that it is being stretched so much that it must be a line or 96635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // background that doesn't need resampling. 97635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project const float kLargeStretch = 3.0f; 98635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 99635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Figure out if we should resample this image. We try to prune out some 100635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // common cases where resampling won't give us anything, since it is much 101635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // slower than drawing stretched. 102635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (srcWidth == destIWidth && srcHeight == destIHeight) { 103635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // We don't need to resample if the source and destination are the same. 104635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return RESAMPLE_NONE; 105635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 106635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 107635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (srcWidth <= kSmallImageSizeThreshold 108635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project || srcHeight <= kSmallImageSizeThreshold 109635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project || destWidth <= kSmallImageSizeThreshold 110635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project || destHeight <= kSmallImageSizeThreshold) { 111635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Never resample small images. These are often used for borders and 112635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // rules (think 1x1 images used to make lines). 113635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return RESAMPLE_NONE; 114635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 115635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 116635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (srcHeight * kLargeStretch <= destHeight || srcWidth * kLargeStretch <= destWidth) { 117635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Large image detected. 118635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 119635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Don't resample if it is being stretched a lot in only one direction. 120635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // This is trying to catch cases where somebody has created a border 121635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // (which might be large) and then is stretching it to fill some part 122635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // of the page. 123635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (srcWidth == destWidth || srcHeight == destHeight) 124635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return RESAMPLE_NONE; 125635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 126635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // The image is growing a lot and in more than one direction. Resampling 127635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // is slow and doesn't give us very much when growing a lot. 128635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return RESAMPLE_LINEAR; 129635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 130635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 131635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if ((fabs(destWidth - srcWidth) / srcWidth < kFractionalChangeThreshold) 132635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project && (fabs(destHeight - srcHeight) / srcHeight < kFractionalChangeThreshold)) { 133635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // It is disappointingly common on the web for image sizes to be off by 134635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // one or two pixels. We don't bother resampling if the size difference 135635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // is a small fraction of the original size. 136635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return RESAMPLE_NONE; 137635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 138635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 139635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // When the image is not yet done loading, use linear. We don't cache the 140635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // partially resampled images, and as they come in incrementally, it causes 141635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // us to have to resample the whole thing every time. 142635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (!bitmap.isDataComplete()) 143635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return RESAMPLE_LINEAR; 144635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 145635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Everything else gets resampled. 1465af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke // If the platform context permits high quality interpolation, use it. 147f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // High quality interpolation only enabled for scaling and translation. 148f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (platformContext->interpolationQuality() == InterpolationHigh 149f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch && !(platformContext->canvas()->getTotalMatrix().getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask))) 1505af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke return RESAMPLE_AWESOME; 1515af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke 1525af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke return RESAMPLE_LINEAR; 153635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 1542daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#endif 155635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 156635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// Draws the given bitmap to the given canvas. The subset of the source bitmap 157635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// identified by src_rect is drawn to the given destination rect. The bitmap 158635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// will be resampled to resample_width * resample_height (this is the size of 159635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// the whole image, not the subset). See shouldResampleBitmap for more. 160635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// 161635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// This does a lot of computation to resample only the portion of the bitmap 162635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// that will only be drawn. This is critical for performance since when we are 163635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// scrolling, for example, we are only drawing a small strip of the image. 164635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// Resampling the whole image every time is very slow, so this speeds up things 165635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// dramatically. 166635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeImageSkia& bitmap, const SkIRect& srcIRect, const SkRect& destRect) 167635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 168635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // First get the subset we need. This is efficient and does not copy pixels. 169635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkBitmap subset; 170635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project bitmap.extractSubset(&subset, srcIRect); 171635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkRect srcRect; 172635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project srcRect.set(srcIRect); 173635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 174635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Whether we're doing a subset or using the full source image. 175635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project bool srcIsFull = srcIRect.fLeft == 0 && srcIRect.fTop == 0 176635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project && srcIRect.width() == bitmap.width() 177635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project && srcIRect.height() == bitmap.height(); 178635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 179635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // We will always draw in integer sizes, so round the destination rect. 180635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkIRect destRectRounded; 181a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destRect.round(&destRectRounded); 182231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block SkIRect resizedImageRect = // Represents the size of the resized image. 183231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block { 0, 0, destRectRounded.width(), destRectRounded.height() }; 184635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 185f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // Apply forward transform to destRect to estimate required size of 186f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // re-sampled bitmap, and use only in calls required to resize, or that 187f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // check for the required size. 188f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch SkRect destRectTransformed; 189f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch canvas.getTotalMatrix().mapRect(&destRectTransformed, destRect); 190f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch SkIRect destRectTransformedRounded; 191f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch destRectTransformed.round(&destRectTransformedRounded); 192f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 193f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (srcIsFull && bitmap.hasResizedBitmap(destRectTransformedRounded.width(), destRectTransformedRounded.height())) { 194635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Yay, this bitmap frame already has a resized version. 195f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch SkBitmap resampled = bitmap.resizedBitmap(destRectTransformedRounded.width(), destRectTransformedRounded.height()); 196635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project canvas.drawBitmapRect(resampled, 0, destRect, &paint); 197635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return; 198635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 199635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 200635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Compute the visible portion of our rect. 201f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // We also need to compute the transformed portion of the 202f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // visible portion for use below. 203635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkRect destBitmapSubsetSk; 204635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project ClipRectToCanvas(canvas, destRect, &destBitmapSubsetSk); 205f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch SkRect destBitmapSubsetTransformed; 206f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch canvas.getTotalMatrix().mapRect(&destBitmapSubsetTransformed, destBitmapSubsetSk); 207a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destBitmapSubsetSk.offset(-destRect.fLeft, -destRect.fTop); 208f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch SkIRect destBitmapSubsetTransformedRounded; 209f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch destBitmapSubsetTransformed.round(&destBitmapSubsetTransformedRounded); 210f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch destBitmapSubsetTransformedRounded.offset(-destRectTransformedRounded.fLeft, -destRectTransformedRounded.fTop); 211635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 212635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // The matrix inverting, etc. could have introduced rounding error which 213635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // causes the bounds to be outside of the resized bitmap. We round outward 214635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // so we always lean toward it being larger rather than smaller than we 215635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // need, and then clamp to the bitmap bounds so we don't get any invalid 216635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // data. 217635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkIRect destBitmapSubsetSkI; 218a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch destBitmapSubsetSk.roundOut(&destBitmapSubsetSkI); 219635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (!destBitmapSubsetSkI.intersect(resizedImageRect)) 220635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return; // Resized image does not intersect. 221635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 222545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch if (srcIsFull && bitmap.shouldCacheResampling( 223635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project resizedImageRect.width(), 224635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project resizedImageRect.height(), 225635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project destBitmapSubsetSkI.width(), 226635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project destBitmapSubsetSkI.height())) { 227635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // We're supposed to resize the entire image and cache it, even though 228635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // we don't need all of it. 229f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch SkBitmap resampled = bitmap.resizedBitmap(destRectTransformedRounded.width(), 230f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch destRectTransformedRounded.height()); 231635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project canvas.drawBitmapRect(resampled, 0, destRect, &paint); 232635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } else { 233635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // We should only resize the exposed part of the bitmap to do the 234635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // minimal possible work. 235635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 236635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Resample the needed part of the image. 237f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // Transforms above plus rounding may cause destBitmapSubsetTransformedRounded 238f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // to go outside the image, so need to clip to avoid problems. 239f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (destBitmapSubsetTransformedRounded.intersect(0, 0, 240f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch destRectTransformedRounded.width(), destRectTransformedRounded.height())) { 241f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 242f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch SkBitmap resampled = skia::ImageOperations::Resize(subset, 243f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch skia::ImageOperations::RESIZE_LANCZOS3, 244f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch destRectTransformedRounded.width(), destRectTransformedRounded.height(), 245f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch destBitmapSubsetTransformedRounded); 246f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 247f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // Compute where the new bitmap should be drawn. Since our new bitmap 248f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // may be smaller than the original, we have to shift it over by the 249f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch // same amount that we cut off the top and left. 250f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch destBitmapSubsetSkI.offset(destRect.fLeft, destRect.fTop); 251f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch SkRect offsetDestRect; 252f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch offsetDestRect.set(destBitmapSubsetSkI); 253f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch 254f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch canvas.drawBitmapRect(resampled, 0, offsetDestRect, &paint); 255f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch } 256635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 257635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 258635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 2590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochstatic void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, const SkIRect& srcRect, const SkRect& destRect, const SkXfermode::Mode& compOp) 260635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 261635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkPaint paint; 2620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch paint.setXfermodeMode(compOp); 2638f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian paint.setFilterBitmap(true); 264e14391e94c850b8bd03680c23b38978db68687a8John Reck paint.setAlpha(platformContext->getNormalizedAlpha()); 2652bde8e466a4451c7319e3a072d118917957d6554Steve Block paint.setLooper(platformContext->getDrawLooper()); 266635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 2672daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch SkCanvas* canvas = platformContext->canvas(); 268635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 2692daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch ResamplingMode resampling; 2702daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#if ENABLE(SKIA_GPU) 2712daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch resampling = RESAMPLE_LINEAR; 2722daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#else 2732daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch resampling = platformContext->printing() ? RESAMPLE_NONE : 2745af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke computeResamplingMode(platformContext, bitmap, srcRect.width(), srcRect.height(), 275635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkScalarToFloat(destRect.width()), 276635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkScalarToFloat(destRect.height())); 2772daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#endif 278635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (resampling == RESAMPLE_AWESOME) { 279635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project drawResampledBitmap(*canvas, paint, bitmap, srcRect, destRect); 280635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } else { 281635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // No resampling necessary, we can just draw the bitmap. We want to 282635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // filter it if we decided to do linear interpolation above, or if there 283635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // is something interesting going on with the matrix (like a rotation). 284635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Note: for serialization, we will want to subset the bitmap first so 285635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // we don't send extra pixels. 286635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project canvas->drawBitmapRect(bitmap, &srcRect, destRect, &paint); 287635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 288635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 289635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 290635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// Transforms the given dimensions with the given matrix. Used to see how big 291635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// images will be once transformed. 292635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void TransformDimensions(const SkMatrix& matrix, float srcWidth, float srcHeight, float* destWidth, float* destHeight) { 293635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Transform 3 points to see how long each side of the bitmap will be. 294635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkPoint src_points[3]; // (0, 0), (width, 0), (0, height). 295635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project src_points[0].set(0, 0); 296635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project src_points[1].set(SkFloatToScalar(srcWidth), 0); 297635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project src_points[2].set(0, SkFloatToScalar(srcHeight)); 298635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 299635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Now measure the length of the two transformed vectors relative to the 300635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // transformed origin to see how big the bitmap will be. Note: for skews, 301635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // this isn't the best thing, but we don't have skews. 302635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkPoint dest_points[3]; 303635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project matrix.mapPoints(dest_points, src_points, 3); 304635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *destWidth = SkScalarToFloat((dest_points[1] - dest_points[0]).length()); 305635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *destHeight = SkScalarToFloat((dest_points[2] - dest_points[0]).length()); 306635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 307635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 308635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// A helper method for translating negative width and height values. 30965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben MurdochFloatRect normalizeRect(const FloatRect& rect) 310635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 311635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project FloatRect norm = rect; 312635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (norm.width() < 0) { 313635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project norm.setX(norm.x() + norm.width()); 314635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project norm.setWidth(-norm.width()); 315635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 316635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (norm.height() < 0) { 317635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project norm.setY(norm.y() + norm.height()); 318635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project norm.setHeight(-norm.height()); 319635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 320635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return norm; 321635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 322635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 323635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectbool FrameData::clear(bool clearMetadata) 324635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 325635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (clearMetadata) 326635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project m_haveMetadata = false; 327635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 328635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (m_frame) { 329635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // ImageSource::createFrameAtIndex() allocated |m_frame| and passed 330635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // ownership to BitmapImage; we must delete it here. 331635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project delete m_frame; 332635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project m_frame = 0; 333635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return true; 334635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 335635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return false; 336635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 337635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 338635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid Image::drawPattern(GraphicsContext* context, 339635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project const FloatRect& floatSrcRect, 3408a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block const AffineTransform& patternTransform, 341635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project const FloatPoint& phase, 342643ca7872b450ea4efacab6188849e5aac2ba161Steve Block ColorSpace styleColorSpace, 343635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project CompositeOperator compositeOp, 344635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project const FloatRect& destRect) 345635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 3465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian FloatRect normSrcRect = normalizeRect(floatSrcRect); 3475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (destRect.isEmpty() || normSrcRect.isEmpty()) 348635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return; // nothing to draw 349635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 350635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project NativeImageSkia* bitmap = nativeImageForCurrentFrame(); 351635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (!bitmap) 352635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return; 353635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 354635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // This is a very inexpensive operation. It will generate a new bitmap but 355635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // it will internally reference the old bitmap's pixels, adjusting the row 356635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // stride so the extra pixels appear as padding to the subsetted bitmap. 357635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkBitmap srcSubset; 3585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian SkIRect srcRect = enclosingIntRect(normSrcRect); 359635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project bitmap->extractSubset(&srcSubset, srcRect); 360635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 361635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkBitmap resampled; 362635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkShader* shader; 363635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 364635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Figure out what size the bitmap will be in the destination. The 365635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // destination rect is the bounds of the pattern, we need to use the 366635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // matrix to see how bit it will be. 367635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project float destBitmapWidth, destBitmapHeight; 368635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project TransformDimensions(patternTransform, srcRect.width(), srcRect.height(), 369635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project &destBitmapWidth, &destBitmapHeight); 370635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 371635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Compute the resampling mode. 372635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project ResamplingMode resampling; 3732daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#if ENABLE(SKIA_GPU) 3742daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch resampling = RESAMPLE_LINEAR; 3752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#else 3762daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (context->platformContext()->printing()) 377635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project resampling = RESAMPLE_LINEAR; 378635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project else { 3795af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke resampling = computeResamplingMode(context->platformContext(), *bitmap, 380635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project srcRect.width(), srcRect.height(), 381635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project destBitmapWidth, destBitmapHeight); 382635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 3832daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#endif 384635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 385635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Load the transform WebKit requested. 386635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkMatrix matrix(patternTransform); 387635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 388635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (resampling == RESAMPLE_AWESOME) { 389635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Do nice resampling. 3906c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen SkBitmap resampled; 3916c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen int width = static_cast<int>(destBitmapWidth); 3926c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen int height = static_cast<int>(destBitmapHeight); 3936c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen if (!srcRect.fLeft && !srcRect.fTop 3946c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen && srcRect.fRight == bitmap->width() && srcRect.fBottom == bitmap->height() 3956c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen && (bitmap->hasResizedBitmap(width, height) 3966c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen || bitmap->shouldCacheResampling(width, height, width, height))) { 3976c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen // resizedBitmap() caches resized image. 3986c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen resampled = bitmap->resizedBitmap(width, height); 3996c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen } else { 4006c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen resampled = skia::ImageOperations::Resize(srcSubset, 4016c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen skia::ImageOperations::RESIZE_LANCZOS3, width, height); 4026c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen } 403635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project shader = SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); 404635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 405635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Since we just resized the bitmap, we need to undo the scale set in 406635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // the image transform. 407635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project matrix.setScaleX(SkIntToScalar(1)); 408635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project matrix.setScaleY(SkIntToScalar(1)); 409635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } else { 410635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // No need to do nice resampling. 411635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project shader = SkShader::CreateBitmapShader(srcSubset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); 412635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project } 413635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 414635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // We also need to translate it such that the origin of the pattern is the 415635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // origin of the destination rect, which is what WebKit expects. Skia uses 416635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // the coordinate system origin as the base for the patter. If WebKit wants 417635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // a shifted image, it will shift it from there using the patternTransform. 4185f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian float adjustedX = phase.x() + normSrcRect.x() * 419635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project narrowPrecisionToFloat(patternTransform.a()); 4205f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian float adjustedY = phase.y() + normSrcRect.y() * 421635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project narrowPrecisionToFloat(patternTransform.d()); 422635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project matrix.postTranslate(SkFloatToScalar(adjustedX), 423635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkFloatToScalar(adjustedY)); 424635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project shader->setLocalMatrix(matrix); 425635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 426635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project SkPaint paint; 427635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project paint.setShader(shader)->unref(); 4280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp)); 429635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project paint.setFilterBitmap(resampling == RESAMPLE_LINEAR); 430635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 431635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project context->platformContext()->paintSkPaint(destRect, paint); 432635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 433635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 434db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Blockstatic void drawBitmapGLES2(GraphicsContext* ctxt, NativeImageSkia* bitmap, const FloatRect& srcRect, const FloatRect& dstRect, ColorSpace styleColorSpace, CompositeOperator compositeOp) 435db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block{ 436db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block ctxt->platformContext()->prepareForHardwareDraw(); 437db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block GLES2Canvas* gpuCanvas = ctxt->platformContext()->gpuCanvas(); 4385ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen Texture* texture = gpuCanvas->getTexture(bitmap); 439db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block if (!texture) { 440db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block ASSERT(bitmap->config() == SkBitmap::kARGB_8888_Config); 441db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block ASSERT(bitmap->rowBytes() == bitmap->width() * 4); 4425ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen texture = gpuCanvas->createTexture(bitmap, Texture::BGRA8, bitmap->width(), bitmap->height()); 443e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block SkAutoLockPixels lock(*bitmap); 444e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block ASSERT(bitmap->getPixels()); 445e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block texture->load(bitmap->getPixels()); 446db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block } 447db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block gpuCanvas->drawTexturedRect(texture, srcRect, dstRect, styleColorSpace, compositeOp); 448db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block} 449db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block 450635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// ================================================ 451635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// BitmapImage Class 452635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// ================================================ 453635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 454635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// FIXME: These should go to BitmapImageSkia.cpp 455635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 456635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid BitmapImage::initPlatformData() 457635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 458635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // This is not used. On Mac, the "platform" data is a cache of some OS 459635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // specific versions of the image that are created is some cases. These 460635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // aren't normally used, it is equivalent to getHBITMAP on Windows, and 461635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // the platform data is the cache. 462635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 463635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 464635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid BitmapImage::invalidatePlatformData() 465635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 466635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // See initPlatformData above. 467635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 468635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 469635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid BitmapImage::checkForSolidColor() 470635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 4718f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian m_checkedForSolidColor = true; 472635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 473635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 474635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, 475db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block const FloatRect& srcRect, ColorSpace colorSpace, CompositeOperator compositeOp) 476635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 477635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (!m_source.initialized()) 478635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return; 479635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 480635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // Spin the animation to the correct frame before we try to draw it, so we 481635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // don't draw an old frame and then immediately need to draw a newer one, 482635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // causing flicker and wasting CPU. 483635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project startAnimation(); 484635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 485db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block NativeImageSkia* bm = nativeImageForCurrentFrame(); 486635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (!bm) 487635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return; // It's too early and we don't have an image yet. 488635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 489635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project FloatRect normDstRect = normalizeRect(dstRect); 490635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project FloatRect normSrcRect = normalizeRect(srcRect); 491635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 492635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (normSrcRect.isEmpty() || normDstRect.isEmpty()) 493635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return; // Nothing to draw. 494635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 4955abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick if (ctxt->platformContext()->useGPU() && ctxt->platformContext()->canAccelerate()) { 496f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick drawBitmapGLES2(ctxt, bm, normSrcRect, normDstRect, colorSpace, compositeOp); 497f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick return; 498f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick } 4995ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen 500db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block ctxt->platformContext()->prepareForSoftwareDraw(); 501db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block 502635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project paintSkBitmap(ctxt->platformContext(), 503635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *bm, 504635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project enclosingIntRect(normSrcRect), 5058f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian normDstRect, 506635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project WebCoreCompositeToSkiaComposite(compositeOp)); 507635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 508635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 509635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// FIXME: These should go into BitmapImageSingleFrameSkia.cpp 510635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 511635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt, 512635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project const FloatRect& dstRect, 513635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project const FloatRect& srcRect, 514643ca7872b450ea4efacab6188849e5aac2ba161Steve Block ColorSpace styleColorSpace, 515635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project CompositeOperator compositeOp) 516635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 517635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project FloatRect normDstRect = normalizeRect(dstRect); 518635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project FloatRect normSrcRect = normalizeRect(srcRect); 519635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 520635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project if (normSrcRect.isEmpty() || normDstRect.isEmpty()) 521635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project return; // Nothing to draw. 522635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 5235abb8606fa57c3ebfc8b3c3dbc3fa4a25d2ae306Iain Merrick if (ctxt->platformContext()->useGPU() && ctxt->platformContext()->canAccelerate()) { 524db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block drawBitmapGLES2(ctxt, &m_nativeImage, srcRect, dstRect, styleColorSpace, compositeOp); 525db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block return; 526db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block } 527db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block 528db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block ctxt->platformContext()->prepareForSoftwareDraw(); 529db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block 530635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project paintSkBitmap(ctxt->platformContext(), 531635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project m_nativeImage, 532635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project enclosingIntRect(normSrcRect), 5338f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian normDstRect, 534635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project WebCoreCompositeToSkiaComposite(compositeOp)); 535635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 536635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 537e8b154fd68f9b33be40a3590e58347f353835f5cSteve BlockBitmapImageSingleFrameSkia::BitmapImageSingleFrameSkia(const SkBitmap& bitmap) 538e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block : m_nativeImage(bitmap) 539635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{ 540e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block} 541e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 542e8b154fd68f9b33be40a3590e58347f353835f5cSteve BlockPassRefPtr<BitmapImageSingleFrameSkia> BitmapImageSingleFrameSkia::create(const SkBitmap& bitmap, bool copyPixels) 543e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block{ 544e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block if (copyPixels) { 545e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block SkBitmap temp; 546e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block bitmap.copyTo(&temp, bitmap.config()); 547e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return adoptRef(new BitmapImageSingleFrameSkia(temp)); 548e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block } 549e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return adoptRef(new BitmapImageSingleFrameSkia(bitmap)); 550635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} 551635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project 552635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} // namespace WebCore 553