Ownership of canvas's GraphicsContext3D should be moved to PlatformContextSkia
[WebKit-https.git] / Source / 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 "AffineTransform.h"
34 #include "BitmapImage.h"
35 #include "BitmapImageSingleFrameSkia.h"
36 #include "FloatConversion.h"
37 #include "FloatRect.h"
38 #include "GraphicsContext.h"
39 #include "ImageObserver.h"
40 #include "Logging.h"
41 #include "NativeImageSkia.h"
42 #include "PlatformContextSkia.h"
43 #include "PlatformString.h"
44 #include "SkPixelRef.h"
45 #include "SkRect.h"
46 #include "SkShader.h"
47 #include "SkiaUtils.h"
48 #include "Texture.h"
49
50 #include "skia/ext/image_operations.h"
51 #include "skia/ext/platform_canvas.h"
52
53 namespace WebCore {
54
55 // Used by computeResamplingMode to tell how bitmaps should be resampled.
56 enum ResamplingMode {
57     // Nearest neighbor resampling. Used when we detect that the page is
58     // trying to make a pattern by stretching a small bitmap very large.
59     RESAMPLE_NONE,
60
61     // Default skia resampling. Used for large growing of images where high
62     // quality resampling doesn't get us very much except a slowdown.
63     RESAMPLE_LINEAR,
64
65     // High quality resampling.
66     RESAMPLE_AWESOME,
67 };
68
69 static ResamplingMode computeResamplingMode(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, int srcWidth, int srcHeight, float destWidth, float destHeight)
70 {
71     if (platformContext->hasImageResamplingHint()) {
72         IntSize srcSize;
73         FloatSize dstSize;
74         platformContext->getImageResamplingHint(&srcSize, &dstSize);
75         srcWidth = srcSize.width();
76         srcHeight = srcSize.height();
77         destWidth = dstSize.width();
78         destHeight = dstSize.height();
79     }
80
81     int destIWidth = static_cast<int>(destWidth);
82     int destIHeight = static_cast<int>(destHeight);
83
84     // The percent change below which we will not resample. This usually means
85     // an off-by-one error on the web page, and just doing nearest neighbor
86     // sampling is usually good enough.
87     const float kFractionalChangeThreshold = 0.025f;
88
89     // Images smaller than this in either direction are considered "small" and
90     // are not resampled ever (see below).
91     const int kSmallImageSizeThreshold = 8;
92
93     // The amount an image can be stretched in a single direction before we
94     // say that it is being stretched so much that it must be a line or
95     // background that doesn't need resampling.
96     const float kLargeStretch = 3.0f;
97
98     // Figure out if we should resample this image. We try to prune out some
99     // common cases where resampling won't give us anything, since it is much
100     // slower than drawing stretched.
101     if (srcWidth == destIWidth && srcHeight == destIHeight) {
102         // We don't need to resample if the source and destination are the same.
103         return RESAMPLE_NONE;
104     }
105
106     if (srcWidth <= kSmallImageSizeThreshold
107         || srcHeight <= kSmallImageSizeThreshold
108         || destWidth <= kSmallImageSizeThreshold
109         || destHeight <= kSmallImageSizeThreshold) {
110         // Never resample small images. These are often used for borders and
111         // rules (think 1x1 images used to make lines).
112         return RESAMPLE_NONE;
113     }
114
115     if (srcHeight * kLargeStretch <= destHeight || srcWidth * kLargeStretch <= destWidth) {
116         // Large image detected.
117
118         // Don't resample if it is being stretched a lot in only one direction.
119         // This is trying to catch cases where somebody has created a border
120         // (which might be large) and then is stretching it to fill some part
121         // of the page.
122         if (srcWidth == destWidth || srcHeight == destHeight)
123             return RESAMPLE_NONE;
124
125         // The image is growing a lot and in more than one direction. Resampling
126         // is slow and doesn't give us very much when growing a lot.
127         return RESAMPLE_LINEAR;
128     }
129
130     if ((fabs(destWidth - srcWidth) / srcWidth < kFractionalChangeThreshold)
131         && (fabs(destHeight - srcHeight) / srcHeight < kFractionalChangeThreshold)) {
132         // It is disappointingly common on the web for image sizes to be off by
133         // one or two pixels. We don't bother resampling if the size difference
134         // is a small fraction of the original size.
135         return RESAMPLE_NONE;
136     }
137
138     // When the image is not yet done loading, use linear. We don't cache the
139     // partially resampled images, and as they come in incrementally, it causes
140     // us to have to resample the whole thing every time.
141     if (!bitmap.isDataComplete())
142         return RESAMPLE_LINEAR;
143
144     // Everything else gets resampled.
145     // If the platform context permits high quality interpolation, use it.
146     // High quality interpolation only enabled for scaling and translation.
147     if (platformContext->interpolationQuality() == InterpolationHigh
148         && !(platformContext->canvas()->getTotalMatrix().getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)))
149         return RESAMPLE_AWESOME;
150     
151     return RESAMPLE_LINEAR;
152 }
153
154 // Draws the given bitmap to the given canvas. The subset of the source bitmap
155 // identified by src_rect is drawn to the given destination rect. The bitmap
156 // will be resampled to resample_width * resample_height (this is the size of
157 // the whole image, not the subset). See shouldResampleBitmap for more.
158 //
159 // This does a lot of computation to resample only the portion of the bitmap
160 // that will only be drawn. This is critical for performance since when we are
161 // scrolling, for example, we are only drawing a small strip of the image.
162 // Resampling the whole image every time is very slow, so this speeds up things
163 // dramatically.
164 static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeImageSkia& bitmap, const SkIRect& srcIRect, const SkRect& destRect)
165 {
166     // First get the subset we need. This is efficient and does not copy pixels.
167     SkBitmap subset;
168     bitmap.extractSubset(&subset, srcIRect);
169     SkRect srcRect;
170     srcRect.set(srcIRect);
171
172     // Whether we're doing a subset or using the full source image.
173     bool srcIsFull = srcIRect.fLeft == 0 && srcIRect.fTop == 0
174         && srcIRect.width() == bitmap.width()
175         && srcIRect.height() == bitmap.height();
176
177     // We will always draw in integer sizes, so round the destination rect.
178     SkIRect destRectRounded;
179     destRect.round(&destRectRounded);
180     SkIRect resizedImageRect =  // Represents the size of the resized image.
181         { 0, 0, destRectRounded.width(), destRectRounded.height() };
182
183     // Apply forward transform to destRect to estimate required size of
184     // re-sampled bitmap, and use only in calls required to resize, or that
185     // check for the required size.
186     SkRect destRectTransformed;
187     canvas.getTotalMatrix().mapRect(&destRectTransformed, destRect);
188     SkIRect destRectTransformedRounded;
189     destRectTransformed.round(&destRectTransformedRounded);
190
191     if (srcIsFull && bitmap.hasResizedBitmap(destRectTransformedRounded.width(), destRectTransformedRounded.height())) {
192         // Yay, this bitmap frame already has a resized version.
193         SkBitmap resampled = bitmap.resizedBitmap(destRectTransformedRounded.width(), destRectTransformedRounded.height());
194         canvas.drawBitmapRect(resampled, 0, destRect, &paint);
195         return;
196     }
197
198     // Compute the visible portion of our rect.
199     // We also need to compute the transformed portion of the
200     // visible portion for use below.
201     SkRect destBitmapSubsetSk;
202     ClipRectToCanvas(canvas, destRect, &destBitmapSubsetSk);
203     SkRect destBitmapSubsetTransformed;
204     canvas.getTotalMatrix().mapRect(&destBitmapSubsetTransformed, destBitmapSubsetSk);
205     destBitmapSubsetSk.offset(-destRect.fLeft, -destRect.fTop);
206     SkIRect destBitmapSubsetTransformedRounded;
207     destBitmapSubsetTransformed.round(&destBitmapSubsetTransformedRounded);
208     destBitmapSubsetTransformedRounded.offset(-destRectTransformedRounded.fLeft, -destRectTransformedRounded.fTop);
209
210     // The matrix inverting, etc. could have introduced rounding error which
211     // causes the bounds to be outside of the resized bitmap. We round outward
212     // so we always lean toward it being larger rather than smaller than we
213     // need, and then clamp to the bitmap bounds so we don't get any invalid
214     // data.
215     SkIRect destBitmapSubsetSkI;
216     destBitmapSubsetSk.roundOut(&destBitmapSubsetSkI);
217     if (!destBitmapSubsetSkI.intersect(resizedImageRect))
218         return;  // Resized image does not intersect.
219
220     if (srcIsFull && bitmap.shouldCacheResampling(
221             resizedImageRect.width(),
222             resizedImageRect.height(),
223             destBitmapSubsetSkI.width(),
224             destBitmapSubsetSkI.height())) {
225         // We're supposed to resize the entire image and cache it, even though
226         // we don't need all of it.
227         SkBitmap resampled = bitmap.resizedBitmap(destRectTransformedRounded.width(),
228                                                   destRectTransformedRounded.height());
229         canvas.drawBitmapRect(resampled, 0, destRect, &paint);
230     } else {
231         // We should only resize the exposed part of the bitmap to do the
232         // minimal possible work.
233
234         // Resample the needed part of the image.
235         // Transforms above plus rounding may cause destBitmapSubsetTransformedRounded
236         // to go outside the image, so need to clip to avoid problems.
237         if (destBitmapSubsetTransformedRounded.intersect(0, 0,
238                 destRectTransformedRounded.width(), destRectTransformedRounded.height())) {
239
240             SkBitmap resampled = skia::ImageOperations::Resize(subset,
241                 skia::ImageOperations::RESIZE_LANCZOS3,
242                 destRectTransformedRounded.width(), destRectTransformedRounded.height(),
243                 destBitmapSubsetTransformedRounded);
244
245             // Compute where the new bitmap should be drawn. Since our new bitmap
246             // may be smaller than the original, we have to shift it over by the
247             // same amount that we cut off the top and left.
248             destBitmapSubsetSkI.offset(destRect.fLeft, destRect.fTop);
249             SkRect offsetDestRect;
250             offsetDestRect.set(destBitmapSubsetSkI);
251
252             canvas.drawBitmapRect(resampled, 0, offsetDestRect, &paint);
253         }
254     }
255 }
256
257 static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, const SkIRect& srcRect, const SkRect& destRect, const SkXfermode::Mode& compOp)
258 {
259     SkPaint paint;
260     paint.setXfermodeMode(compOp);
261     paint.setFilterBitmap(true);
262     paint.setAlpha(platformContext->getNormalizedAlpha());
263     paint.setLooper(platformContext->getDrawLooper());
264
265     SkCanvas* canvas = platformContext->canvas();
266
267     ResamplingMode resampling;
268     if (platformContext->isAccelerated())
269         resampling = RESAMPLE_LINEAR;
270     else
271         resampling = platformContext->printing() ? RESAMPLE_NONE :
272             computeResamplingMode(platformContext, bitmap, srcRect.width(), srcRect.height(), SkScalarToFloat(destRect.width()), SkScalarToFloat(destRect.height()));
273     if (resampling == RESAMPLE_AWESOME) {
274         drawResampledBitmap(*canvas, paint, bitmap, srcRect, destRect);
275     } else {
276         // No resampling necessary, we can just draw the bitmap. We want to
277         // filter it if we decided to do linear interpolation above, or if there
278         // is something interesting going on with the matrix (like a rotation).
279         // Note: for serialization, we will want to subset the bitmap first so
280         // we don't send extra pixels.
281         canvas->drawBitmapRect(bitmap, &srcRect, destRect, &paint);
282     }
283 }
284
285 // Transforms the given dimensions with the given matrix. Used to see how big
286 // images will be once transformed.
287 static void TransformDimensions(const SkMatrix& matrix, float srcWidth, float srcHeight, float* destWidth, float* destHeight) {
288     // Transform 3 points to see how long each side of the bitmap will be.
289     SkPoint src_points[3];  // (0, 0), (width, 0), (0, height).
290     src_points[0].set(0, 0);
291     src_points[1].set(SkFloatToScalar(srcWidth), 0);
292     src_points[2].set(0, SkFloatToScalar(srcHeight));
293
294     // Now measure the length of the two transformed vectors relative to the
295     // transformed origin to see how big the bitmap will be. Note: for skews,
296     // this isn't the best thing, but we don't have skews.
297     SkPoint dest_points[3];
298     matrix.mapPoints(dest_points, src_points, 3);
299     *destWidth = SkScalarToFloat((dest_points[1] - dest_points[0]).length());
300     *destHeight = SkScalarToFloat((dest_points[2] - dest_points[0]).length());
301 }
302
303 // A helper method for translating negative width and height values.
304 FloatRect normalizeRect(const FloatRect& rect)
305 {
306     FloatRect norm = rect;
307     if (norm.width() < 0) {
308         norm.setX(norm.x() + norm.width());
309         norm.setWidth(-norm.width());
310     }
311     if (norm.height() < 0) {
312         norm.setY(norm.y() + norm.height());
313         norm.setHeight(-norm.height());
314     }
315     return norm;
316 }
317
318 bool FrameData::clear(bool clearMetadata)
319 {
320     if (clearMetadata)
321         m_haveMetadata = false;
322
323     if (m_frame) {
324         // ImageSource::createFrameAtIndex() allocated |m_frame| and passed
325         // ownership to BitmapImage; we must delete it here.
326         delete m_frame;
327         m_frame = 0;
328         return true;
329     }
330     return false;
331 }
332
333 void Image::drawPattern(GraphicsContext* context,
334                         const FloatRect& floatSrcRect,
335                         const AffineTransform& patternTransform,
336                         const FloatPoint& phase,
337                         ColorSpace styleColorSpace,
338                         CompositeOperator compositeOp,
339                         const FloatRect& destRect)
340 {
341     FloatRect normSrcRect = normalizeRect(floatSrcRect);
342     if (destRect.isEmpty() || normSrcRect.isEmpty())
343         return;  // nothing to draw
344
345     NativeImageSkia* bitmap = nativeImageForCurrentFrame();
346     if (!bitmap)
347         return;
348
349     // This is a very inexpensive operation. It will generate a new bitmap but
350     // it will internally reference the old bitmap's pixels, adjusting the row
351     // stride so the extra pixels appear as padding to the subsetted bitmap.
352     SkBitmap srcSubset;
353     SkIRect srcRect = enclosingIntRect(normSrcRect);
354     bitmap->extractSubset(&srcSubset, srcRect);
355
356     SkBitmap resampled;
357     SkShader* shader;
358
359     // Figure out what size the bitmap will be in the destination. The
360     // destination rect is the bounds of the pattern, we need to use the
361     // matrix to see how bit it will be.
362     float destBitmapWidth, destBitmapHeight;
363     TransformDimensions(patternTransform, srcRect.width(), srcRect.height(),
364                         &destBitmapWidth, &destBitmapHeight);
365
366     // Compute the resampling mode.
367     ResamplingMode resampling;
368     if (context->platformContext()->isAccelerated())
369         resampling = RESAMPLE_LINEAR;
370     else {
371         if (context->platformContext()->printing())
372             resampling = RESAMPLE_LINEAR;
373         else
374             resampling = computeResamplingMode(context->platformContext(), *bitmap, srcRect.width(), srcRect.height(), destBitmapWidth, destBitmapHeight);
375     }
376
377     // Load the transform WebKit requested.
378     SkMatrix matrix(patternTransform);
379
380     if (resampling == RESAMPLE_AWESOME) {
381         // Do nice resampling.
382         SkBitmap resampled;
383         int width = static_cast<int>(destBitmapWidth);
384         int height = static_cast<int>(destBitmapHeight);
385         if (!srcRect.fLeft && !srcRect.fTop
386             && srcRect.fRight == bitmap->width() && srcRect.fBottom == bitmap->height()
387             && (bitmap->hasResizedBitmap(width, height)
388                 || bitmap->shouldCacheResampling(width, height, width, height))) {
389             // resizedBitmap() caches resized image.
390             resampled = bitmap->resizedBitmap(width, height);
391         } else {
392             resampled = skia::ImageOperations::Resize(srcSubset,
393                 skia::ImageOperations::RESIZE_LANCZOS3, width, height);
394         }
395         shader = SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
396
397         // Since we just resized the bitmap, we need to undo the scale set in
398         // the image transform.
399         matrix.setScaleX(SkIntToScalar(1));
400         matrix.setScaleY(SkIntToScalar(1));
401     } else {
402         // No need to do nice resampling.
403         shader = SkShader::CreateBitmapShader(srcSubset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
404     }
405
406     // We also need to translate it such that the origin of the pattern is the
407     // origin of the destination rect, which is what WebKit expects. Skia uses
408     // the coordinate system origin as the base for the patter. If WebKit wants
409     // a shifted image, it will shift it from there using the patternTransform.
410     float adjustedX = phase.x() + normSrcRect.x() *
411                       narrowPrecisionToFloat(patternTransform.a());
412     float adjustedY = phase.y() + normSrcRect.y() *
413                       narrowPrecisionToFloat(patternTransform.d());
414     matrix.postTranslate(SkFloatToScalar(adjustedX),
415                          SkFloatToScalar(adjustedY));
416     shader->setLocalMatrix(matrix);
417
418     SkPaint paint;
419     paint.setShader(shader)->unref();
420     paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp));
421     paint.setFilterBitmap(resampling == RESAMPLE_LINEAR);
422
423     context->platformContext()->paintSkPaint(destRect, paint);
424 }
425
426 // ================================================
427 // BitmapImage Class
428 // ================================================
429
430 // FIXME: These should go to BitmapImageSkia.cpp
431
432 void BitmapImage::initPlatformData()
433 {
434     // This is not used. On Mac, the "platform" data is a cache of some OS
435     // specific versions of the image that are created is some cases. These
436     // aren't normally used, it is equivalent to getHBITMAP on Windows, and
437     // the platform data is the cache.
438 }
439
440 void BitmapImage::invalidatePlatformData()
441 {
442     // See initPlatformData above.
443 }
444
445 void BitmapImage::checkForSolidColor()
446 {
447     m_isSolidColor = false;
448     m_checkedForSolidColor = true;
449
450     if (frameCount() > 1)
451         return;
452
453     WebCore::NativeImageSkia* frame = frameAtIndex(0);
454
455     if (frame && size().width() == 1 && size().height() == 1) {
456         SkAutoLockPixels lock(*frame);
457         if (!frame->getPixels())
458             return;
459
460         m_isSolidColor = true;
461         m_solidColor = Color(frame->getColor(0, 0));
462     }
463 }
464
465 void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
466                        const FloatRect& srcRect, ColorSpace colorSpace, CompositeOperator compositeOp)
467 {
468     if (!m_source.initialized())
469         return;
470
471     // Spin the animation to the correct frame before we try to draw it, so we
472     // don't draw an old frame and then immediately need to draw a newer one,
473     // causing flicker and wasting CPU.
474     startAnimation();
475
476     NativeImageSkia* bm = nativeImageForCurrentFrame();
477     if (!bm)
478         return;  // It's too early and we don't have an image yet.
479
480     FloatRect normDstRect = normalizeRect(dstRect);
481     FloatRect normSrcRect = normalizeRect(srcRect);
482
483     if (normSrcRect.isEmpty() || normDstRect.isEmpty())
484         return;  // Nothing to draw.
485
486     ctxt->platformContext()->makeGrContextCurrent();
487
488     paintSkBitmap(ctxt->platformContext(),
489                   *bm,
490                   enclosingIntRect(normSrcRect),
491                   normDstRect,
492                   WebCoreCompositeToSkiaComposite(compositeOp));
493
494     if (ImageObserver* observer = imageObserver())
495         observer->didDraw(this);
496 }
497
498 // FIXME: These should go into BitmapImageSingleFrameSkia.cpp
499
500 void BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt,
501                                       const FloatRect& dstRect,
502                                       const FloatRect& srcRect,
503                                       ColorSpace styleColorSpace,
504                                       CompositeOperator compositeOp)
505 {
506     FloatRect normDstRect = normalizeRect(dstRect);
507     FloatRect normSrcRect = normalizeRect(srcRect);
508
509     if (normSrcRect.isEmpty() || normDstRect.isEmpty())
510         return;  // Nothing to draw.
511
512     ctxt->platformContext()->makeGrContextCurrent();
513
514     paintSkBitmap(ctxt->platformContext(),
515                   m_nativeImage,
516                   enclosingIntRect(normSrcRect),
517                   normDstRect,
518                   WebCoreCompositeToSkiaComposite(compositeOp));
519
520     if (ImageObserver* observer = imageObserver())
521         observer->didDraw(this);
522 }
523
524 BitmapImageSingleFrameSkia::BitmapImageSingleFrameSkia(const SkBitmap& bitmap)
525     : m_nativeImage(bitmap)
526 {
527 }
528
529 PassRefPtr<BitmapImageSingleFrameSkia> BitmapImageSingleFrameSkia::create(const SkBitmap& bitmap, bool copyPixels)
530 {
531     if (copyPixels) {
532         SkBitmap temp;
533         bitmap.copyTo(&temp, bitmap.config());
534         return adoptRef(new BitmapImageSingleFrameSkia(temp));
535     }
536     return adoptRef(new BitmapImageSingleFrameSkia(bitmap));
537 }
538
539 }  // namespace WebCore