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