0a12af3a7b6980a5f767769b9db0e5d53b55a3f7
[WebKit-https.git] / WebCore / platform / graphics / skia / ImageSkia.cpp
1 /*
2  * Copyright (c) 2008, Google Inc. All rights reserved.
3  * 
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  * 
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  * 
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32
33 #include "BitmapImage.h"
34 #include "BitmapImageSingleFrameSkia.h"
35 #include "ChromiumBridge.h"
36 #include "FloatConversion.h"
37 #include "FloatRect.h"
38 #include "GraphicsContext.h"
39 #include "Logging.h"
40 #include "NativeImageSkia.h"
41 #include "NotImplemented.h"
42 #include "PlatformContextSkia.h"
43 #include "PlatformString.h"
44 #include "SkiaUtils.h"
45 #include "SkShader.h"
46 #include "TransformationMatrix.h"
47
48 #include "skia/ext/image_operations.h"
49 #include "skia/ext/platform_canvas.h"
50
51 namespace WebCore {
52
53 // Used by computeResamplingMode to tell how bitmaps should be resampled.
54 enum ResamplingMode {
55     // Nearest neighbor resampling. Used when we detect that the page is
56     // trying to make a pattern by stretching a small bitmap very large.
57     RESAMPLE_NONE,
58
59     // Default skia resampling. Used for large growing of images where high
60     // quality resampling doesn't get us very much except a slowdown.
61     RESAMPLE_LINEAR,
62
63     // High quality resampling.
64     RESAMPLE_AWESOME,
65 };
66
67 static ResamplingMode computeResamplingMode(const NativeImageSkia& bitmap, int srcWidth, int srcHeight, float destWidth, float destHeight)
68 {
69     int destIWidth = static_cast<int>(destWidth);
70     int destIHeight = static_cast<int>(destHeight);
71
72     // The percent change below which we will not resample. This usually means
73     // an off-by-one error on the web page, and just doing nearest neighbor
74     // sampling is usually good enough.
75     const float kFractionalChangeThreshold = 0.025f;
76
77     // Images smaller than this in either direction are considered "small" and
78     // are not resampled ever (see below).
79     const int kSmallImageSizeThreshold = 8;
80
81     // The amount an image can be stretched in a single direction before we
82     // say that it is being stretched so much that it must be a line or
83     // background that doesn't need resampling.
84     const float kLargeStretch = 3.0f;
85
86     // Figure out if we should resample this image. We try to prune out some
87     // common cases where resampling won't give us anything, since it is much
88     // slower than drawing stretched.
89     if (srcWidth == destIWidth && srcHeight == destIHeight) {
90         // We don't need to resample if the source and destination are the same.
91         return RESAMPLE_NONE;
92     }
93
94     if (srcWidth <= kSmallImageSizeThreshold
95         || srcHeight <= kSmallImageSizeThreshold
96         || destWidth <= kSmallImageSizeThreshold
97         || destHeight <= kSmallImageSizeThreshold) {
98         // Never resample small images. These are often used for borders and
99         // rules (think 1x1 images used to make lines).
100         return RESAMPLE_NONE;
101     }
102
103     if (srcHeight * kLargeStretch <= destHeight || srcWidth * kLargeStretch <= destWidth) {
104         // Large image detected.
105
106         // Don't resample if it is being stretched a lot in only one direction.
107         // This is trying to catch cases where somebody has created a border
108         // (which might be large) and then is stretching it to fill some part
109         // of the page.
110         if (srcWidth == destWidth || srcHeight == destHeight)
111             return RESAMPLE_NONE;
112
113         // The image is growing a lot and in more than one direction. Resampling
114         // is slow and doesn't give us very much when growing a lot.
115         return RESAMPLE_LINEAR;
116     }
117
118     if ((fabs(destWidth - srcWidth) / srcWidth < kFractionalChangeThreshold)
119         && (fabs(destHeight - srcHeight) / srcHeight < kFractionalChangeThreshold)) {
120         // It is disappointingly common on the web for image sizes to be off by
121         // one or two pixels. We don't bother resampling if the size difference
122         // is a small fraction of the original size.
123         return RESAMPLE_NONE;
124     }
125
126     // When the image is not yet done loading, use linear. We don't cache the
127     // partially resampled images, and as they come in incrementally, it causes
128     // us to have to resample the whole thing every time.
129     if (!bitmap.isDataComplete())
130         return RESAMPLE_LINEAR;
131
132     // Everything else gets resampled.
133     return RESAMPLE_AWESOME;
134 }
135
136 // Draws the given bitmap to the given canvas. The subset of the source bitmap
137 // identified by src_rect is drawn to the given destination rect. The bitmap
138 // will be resampled to resample_width * resample_height (this is the size of
139 // the whole image, not the subset). See shouldResampleBitmap for more.
140 //
141 // This does a lot of computation to resample only the portion of the bitmap
142 // that will only be drawn. This is critical for performance since when we are
143 // scrolling, for example, we are only drawing a small strip of the image.
144 // Resampling the whole image every time is very slow, so this speeds up things
145 // dramatically.
146 static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeImageSkia& bitmap, const SkIRect& srcIRect, const SkRect& destRect)
147 {
148     // First get the subset we need. This is efficient and does not copy pixels.
149     SkBitmap subset;
150     bitmap.extractSubset(&subset, srcIRect);
151     SkRect srcRect;
152     srcRect.set(srcIRect);
153
154     // Whether we're doing a subset or using the full source image.
155     bool srcIsFull = srcIRect.fLeft == 0 && srcIRect.fTop == 0
156         && srcIRect.width() == bitmap.width()
157         && srcIRect.height() == bitmap.height();
158
159     // We will always draw in integer sizes, so round the destination rect.
160     SkIRect destRectRounded;
161     destRect.round(&destRectRounded);
162     SkIRect resizedImageRect;  // Represents the size of the resized image.
163     resizedImageRect.set(0, 0, destRectRounded.width(), destRectRounded.height());
164
165     if (srcIsFull && bitmap.hasResizedBitmap(destRectRounded.width(), destRectRounded.height())) {
166         // Yay, this bitmap frame already has a resized version.
167         SkBitmap resampled = bitmap.resizedBitmap(destRectRounded.width(), destRectRounded.height());
168         canvas.drawBitmapRect(resampled, 0, destRect, &paint);
169         return;
170     }
171
172     // Compute the visible portion of our rect.
173     SkRect destBitmapSubsetSk;
174     ClipRectToCanvas(canvas, destRect, &destBitmapSubsetSk);
175     destBitmapSubsetSk.offset(-destRect.fLeft, -destRect.fTop);
176
177     // The matrix inverting, etc. could have introduced rounding error which
178     // causes the bounds to be outside of the resized bitmap. We round outward
179     // so we always lean toward it being larger rather than smaller than we
180     // need, and then clamp to the bitmap bounds so we don't get any invalid
181     // data.
182     SkIRect destBitmapSubsetSkI;
183     destBitmapSubsetSk.roundOut(&destBitmapSubsetSkI);
184     if (!destBitmapSubsetSkI.intersect(resizedImageRect))
185         return;  // Resized image does not intersect.
186
187     if (srcIsFull && bitmap.shouldCacheResampling(
188             resizedImageRect.width(),
189             resizedImageRect.height(),
190             destBitmapSubsetSkI.width(),
191             destBitmapSubsetSkI.height())) {
192         // We're supposed to resize the entire image and cache it, even though
193         // we don't need all of it.
194         SkBitmap resampled = bitmap.resizedBitmap(destRectRounded.width(),
195                                                   destRectRounded.height());
196         canvas.drawBitmapRect(resampled, 0, destRect, &paint);
197     } else {
198         // We should only resize the exposed part of the bitmap to do the
199         // minimal possible work.
200         gfx::Rect destBitmapSubset(destBitmapSubsetSkI.fLeft,
201                                    destBitmapSubsetSkI.fTop,
202                                    destBitmapSubsetSkI.width(),
203                                    destBitmapSubsetSkI.height());
204
205         // Resample the needed part of the image.
206         SkBitmap resampled = skia::ImageOperations::Resize(subset,
207             skia::ImageOperations::RESIZE_LANCZOS3,
208             destRectRounded.width(), destRectRounded.height(),
209             destBitmapSubset);
210
211         // Compute where the new bitmap should be drawn. Since our new bitmap
212         // may be smaller than the original, we have to shift it over by the
213         // same amount that we cut off the top and left.
214         SkRect offsetDestRect = {
215             destBitmapSubset.x() + destRect.fLeft,
216             destBitmapSubset.y() + destRect.fTop,
217             destBitmapSubset.right() + destRect.fLeft,
218             destBitmapSubset.bottom() + destRect.fTop };
219
220         canvas.drawBitmapRect(resampled, 0, offsetDestRect, &paint);
221     }
222 }
223
224 static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, const SkIRect& srcRect, const SkRect& destRect, const SkPorterDuff::Mode& compOp)
225 {
226     SkPaint paint;
227     paint.setPorterDuffXfermode(compOp);
228
229     skia::PlatformCanvas* canvas = platformContext->canvas();
230
231     ResamplingMode resampling = platformContext->IsPrinting() ? RESAMPLE_NONE :
232         computeResamplingMode(bitmap, srcRect.width(), srcRect.height(),
233                               SkScalarToFloat(destRect.width()),
234                               SkScalarToFloat(destRect.height()));
235     if (resampling == RESAMPLE_AWESOME) {
236         paint.setFilterBitmap(false);
237         drawResampledBitmap(*canvas, paint, bitmap, srcRect, destRect);
238     } else {
239         // No resampling necessary, we can just draw the bitmap. We want to
240         // filter it if we decided to do linear interpolation above, or if there
241         // is something interesting going on with the matrix (like a rotation).
242         // Note: for serialization, we will want to subset the bitmap first so
243         // we don't send extra pixels.
244         paint.setFilterBitmap(resampling == RESAMPLE_LINEAR);
245         canvas->drawBitmapRect(bitmap, &srcRect, destRect, &paint);
246     }
247 }
248
249 // Transforms the given dimensions with the given matrix. Used to see how big
250 // images will be once transformed.
251 static void TransformDimensions(const SkMatrix& matrix, float srcWidth, float srcHeight, float* destWidth, float* destHeight) {
252     // Transform 3 points to see how long each side of the bitmap will be.
253     SkPoint src_points[3];  // (0, 0), (width, 0), (0, height).
254     src_points[0].set(0, 0);
255     src_points[1].set(SkFloatToScalar(srcWidth), 0);
256     src_points[2].set(0, SkFloatToScalar(srcHeight));
257
258     // Now measure the length of the two transformed vectors relative to the
259     // transformed origin to see how big the bitmap will be. Note: for skews,
260     // this isn't the best thing, but we don't have skews.
261     SkPoint dest_points[3];
262     matrix.mapPoints(dest_points, src_points, 3);
263     *destWidth = SkScalarToFloat((dest_points[1] - dest_points[0]).length());
264     *destHeight = SkScalarToFloat((dest_points[2] - dest_points[0]).length());
265 }
266
267 // A helper method for translating negative width and height values.
268 static FloatRect normalizeRect(const FloatRect& rect)
269 {
270     FloatRect norm = rect;
271     if (norm.width() < 0) {
272         norm.setX(norm.x() + norm.width());
273         norm.setWidth(-norm.width());
274     }
275     if (norm.height() < 0) {
276         norm.setY(norm.y() + norm.height());
277         norm.setHeight(-norm.height());
278     }
279     return norm;
280 }
281
282 void FrameData::clear()
283 {
284     // ImageSource::createFrameAtIndex() allocated |m_frame| and passed
285     // ownership to BitmapImage; we must delete it here.
286     delete m_frame;
287     m_frame = 0;
288     // NOTE: We purposefully don't reset metadata here, so that even if we
289     // throw away previously-decoded data, animation loops can still access
290     // properties like frame durations without re-decoding.
291 }
292
293 PassRefPtr<Image> Image::loadPlatformResource(const char *name)
294 {
295     return ChromiumBridge::loadPlatformImageResource(name);
296 }
297
298 void Image::drawPattern(GraphicsContext* context,
299                         const FloatRect& floatSrcRect,
300                         const TransformationMatrix& patternTransform,
301                         const FloatPoint& phase,
302                         CompositeOperator compositeOp,
303                         const FloatRect& destRect)
304 {
305     if (destRect.isEmpty() || floatSrcRect.isEmpty())
306         return;  // nothing to draw
307
308     NativeImageSkia* bitmap = nativeImageForCurrentFrame();
309     if (!bitmap)
310         return;
311
312     // This is a very inexpensive operation. It will generate a new bitmap but
313     // it will internally reference the old bitmap's pixels, adjusting the row
314     // stride so the extra pixels appear as padding to the subsetted bitmap.
315     SkBitmap srcSubset;
316     SkIRect srcRect = enclosingIntRect(floatSrcRect);
317     bitmap->extractSubset(&srcSubset, srcRect);
318
319     SkBitmap resampled;
320     SkShader* shader;
321
322     // Figure out what size the bitmap will be in the destination. The
323     // destination rect is the bounds of the pattern, we need to use the
324     // matrix to see how bit it will be.
325     float destBitmapWidth, destBitmapHeight;
326     TransformDimensions(patternTransform, srcRect.width(), srcRect.height(),
327                         &destBitmapWidth, &destBitmapHeight);
328
329     // Compute the resampling mode.
330     ResamplingMode resampling;
331     if (context->platformContext()->IsPrinting())
332       resampling = RESAMPLE_LINEAR;
333     else {
334       resampling = computeResamplingMode(*bitmap,
335                                          srcRect.width(), srcRect.height(),
336                                          destBitmapWidth, destBitmapHeight);
337     }
338
339     // Load the transform WebKit requested.
340     SkMatrix matrix(patternTransform);
341
342     if (resampling == RESAMPLE_AWESOME) {
343         // Do nice resampling.
344         SkBitmap resampled = skia::ImageOperations::Resize(srcSubset,
345             skia::ImageOperations::RESIZE_LANCZOS3,
346             static_cast<int>(destBitmapWidth),
347             static_cast<int>(destBitmapHeight));
348         shader = SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
349
350         // Since we just resized the bitmap, we need to undo the scale set in
351         // the image transform.
352         matrix.setScaleX(SkIntToScalar(1));
353         matrix.setScaleY(SkIntToScalar(1));
354     } else {
355         // No need to do nice resampling.
356         shader = SkShader::CreateBitmapShader(srcSubset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
357     }
358
359     // We also need to translate it such that the origin of the pattern is the
360     // origin of the destination rect, which is what WebKit expects. Skia uses
361     // the coordinate system origin as the base for the patter. If WebKit wants
362     // a shifted image, it will shift it from there using the patternTransform.
363     float adjustedX = phase.x() + floatSrcRect.x() *
364                       narrowPrecisionToFloat(patternTransform.a());
365     float adjustedY = phase.y() + floatSrcRect.y() *
366                       narrowPrecisionToFloat(patternTransform.d());
367     matrix.postTranslate(SkFloatToScalar(adjustedX),
368                          SkFloatToScalar(adjustedY));
369     shader->setLocalMatrix(matrix);
370
371     SkPaint paint;
372     paint.setShader(shader)->unref();
373     paint.setPorterDuffXfermode(WebCoreCompositeToSkiaComposite(compositeOp));
374     paint.setFilterBitmap(resampling == RESAMPLE_LINEAR);
375
376     context->platformContext()->paintSkPaint(destRect, paint);
377 }
378
379 // ================================================
380 // BitmapImage Class
381 // ================================================
382
383 // FIXME: These should go to BitmapImageSkia.cpp
384
385 void BitmapImage::initPlatformData()
386 {
387     // This is not used. On Mac, the "platform" data is a cache of some OS
388     // specific versions of the image that are created is some cases. These
389     // aren't normally used, it is equivalent to getHBITMAP on Windows, and
390     // the platform data is the cache.
391 }
392
393 void BitmapImage::invalidatePlatformData()
394 {
395     // See initPlatformData above.
396 }
397
398 void BitmapImage::checkForSolidColor()
399 {
400 }
401
402 void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
403                        const FloatRect& srcRect, CompositeOperator compositeOp)
404 {
405     if (!m_source.initialized())
406         return;
407
408     // Spin the animation to the correct frame before we try to draw it, so we
409     // don't draw an old frame and then immediately need to draw a newer one,
410     // causing flicker and wasting CPU.
411     startAnimation();
412
413     const NativeImageSkia* bm = nativeImageForCurrentFrame();
414     if (!bm)
415         return;  // It's too early and we don't have an image yet.
416
417     FloatRect normDstRect = normalizeRect(dstRect);
418     FloatRect normSrcRect = normalizeRect(srcRect);
419
420     if (normSrcRect.isEmpty() || normDstRect.isEmpty())
421         return;  // Nothing to draw.
422
423     paintSkBitmap(ctxt->platformContext(),
424                   *bm,
425                   enclosingIntRect(normSrcRect),
426                   enclosingIntRect(normDstRect),
427                   WebCoreCompositeToSkiaComposite(compositeOp));
428 }
429
430 // FIXME: These should go into BitmapImageSingleFrameSkia.cpp
431
432 void BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt,
433                                       const FloatRect& dstRect,
434                                       const FloatRect& srcRect,
435                                       CompositeOperator compositeOp)
436 {
437     FloatRect normDstRect = normalizeRect(dstRect);
438     FloatRect normSrcRect = normalizeRect(srcRect);
439
440     if (normSrcRect.isEmpty() || normDstRect.isEmpty())
441         return;  // Nothing to draw.
442
443     paintSkBitmap(ctxt->platformContext(),
444                   m_nativeImage,
445                   enclosingIntRect(normSrcRect),
446                   enclosingIntRect(normDstRect),
447                   WebCoreCompositeToSkiaComposite(compositeOp));
448 }
449
450 PassRefPtr<BitmapImageSingleFrameSkia> BitmapImageSingleFrameSkia::create(const SkBitmap& bitmap)
451 {
452     RefPtr<BitmapImageSingleFrameSkia> image(adoptRef(new BitmapImageSingleFrameSkia()));
453     if (!bitmap.copyTo(&image->m_nativeImage, bitmap.config()))
454         return 0;
455     return image.release();
456 }
457
458 }  // namespace WebCore