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