Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / graphics / skia / NativeImageSkia.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 #include "platform/graphics/skia/NativeImageSkia.h"
33
34 #include "platform/PlatformInstrumentation.h"
35 #include "platform/TraceEvent.h"
36 #include "platform/geometry/FloatPoint.h"
37 #include "platform/geometry/FloatRect.h"
38 #include "platform/geometry/FloatSize.h"
39 #include "platform/graphics/GraphicsContext.h"
40 #include "platform/graphics/Image.h"
41 #include "platform/graphics/DeferredImageDecoder.h"
42 #include "platform/graphics/skia/SkiaUtils.h"
43 #include "skia/ext/image_operations.h"
44 #include "third_party/skia/include/core/SkMatrix.h"
45 #include "third_party/skia/include/core/SkPaint.h"
46 #include "third_party/skia/include/core/SkScalar.h"
47 #include "third_party/skia/include/core/SkShader.h"
48
49 #include <math.h>
50 #include <limits>
51
52 namespace WebCore {
53
54 static bool nearlyIntegral(float value)
55 {
56     return fabs(value - floorf(value)) < std::numeric_limits<float>::epsilon();
57 }
58
59 ResamplingMode NativeImageSkia::computeResamplingMode(const SkMatrix& matrix, float srcWidth, float srcHeight, float destWidth, float destHeight) const
60 {
61     // The percent change below which we will not resample. This usually means
62     // an off-by-one error on the web page, and just doing nearest neighbor
63     // sampling is usually good enough.
64     const float kFractionalChangeThreshold = 0.025f;
65
66     // Images smaller than this in either direction are considered "small" and
67     // are not resampled ever (see below).
68     const int kSmallImageSizeThreshold = 8;
69
70     // The amount an image can be stretched in a single direction before we
71     // say that it is being stretched so much that it must be a line or
72     // background that doesn't need resampling.
73     const float kLargeStretch = 3.0f;
74
75     // Figure out if we should resample this image. We try to prune out some
76     // common cases where resampling won't give us anything, since it is much
77     // slower than drawing stretched.
78     float diffWidth = fabs(destWidth - srcWidth);
79     float diffHeight = fabs(destHeight - srcHeight);
80     bool widthNearlyEqual = diffWidth < std::numeric_limits<float>::epsilon();
81     bool heightNearlyEqual = diffHeight < std::numeric_limits<float>::epsilon();
82     // We don't need to resample if the source and destination are the same.
83     if (widthNearlyEqual && heightNearlyEqual)
84         return NoResampling;
85
86     if (srcWidth <= kSmallImageSizeThreshold
87         || srcHeight <= kSmallImageSizeThreshold
88         || destWidth <= kSmallImageSizeThreshold
89         || destHeight <= kSmallImageSizeThreshold) {
90         // Small image detected.
91
92         // Resample in the case where the new size would be non-integral.
93         // This can cause noticeable breaks in repeating patterns, except
94         // when the source image is only one pixel wide in that dimension.
95         if ((!nearlyIntegral(destWidth) && srcWidth > 1 + std::numeric_limits<float>::epsilon())
96             || (!nearlyIntegral(destHeight) && srcHeight > 1 + std::numeric_limits<float>::epsilon()))
97             return LinearResampling;
98
99         // Otherwise, don't resample small images. These are often used for
100         // borders and rules (think 1x1 images used to make lines).
101         return NoResampling;
102     }
103
104     if (srcHeight * kLargeStretch <= destHeight || srcWidth * kLargeStretch <= destWidth) {
105         // Large image detected.
106
107         // Don't resample if it is being stretched a lot in only one direction.
108         // This is trying to catch cases where somebody has created a border
109         // (which might be large) and then is stretching it to fill some part
110         // of the page.
111         if (widthNearlyEqual || heightNearlyEqual)
112             return NoResampling;
113
114         // The image is growing a lot and in more than one direction. Resampling
115         // is slow and doesn't give us very much when growing a lot.
116         return LinearResampling;
117     }
118
119     if ((diffWidth / srcWidth < kFractionalChangeThreshold)
120         && (diffHeight / srcHeight < kFractionalChangeThreshold)) {
121         // It is disappointingly common on the web for image sizes to be off by
122         // one or two pixels. We don't bother resampling if the size difference
123         // is a small fraction of the original size.
124         return NoResampling;
125     }
126
127     // When the image is not yet done loading, use linear. We don't cache the
128     // partially resampled images, and as they come in incrementally, it causes
129     // us to have to resample the whole thing every time.
130     if (!isDataComplete())
131         return LinearResampling;
132
133     // Everything else gets resampled.
134     // High quality interpolation only enabled for scaling and translation.
135     if (!(matrix.getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)))
136         return AwesomeResampling;
137
138     return LinearResampling;
139 }
140
141 static ResamplingMode limitResamplingMode(GraphicsContext* context, ResamplingMode resampling)
142 {
143     switch (context->imageInterpolationQuality()) {
144     case InterpolationNone:
145         return NoResampling;
146     case InterpolationMedium:
147         if (resampling == AwesomeResampling)
148             return LinearWithMipmapsResampling;
149         break;
150     case InterpolationLow:
151         if (resampling == AwesomeResampling || resampling == LinearWithMipmapsResampling)
152             return LinearResampling;
153         break;
154     case InterpolationHigh:
155         break;
156     }
157
158     return resampling;
159 }
160
161 static SkPaint::FilterLevel convertToSkiaFilterLevel(bool useBicubicFilter, ResamplingMode resampling)
162 {
163     if (useBicubicFilter)
164         return SkPaint::kHigh_FilterLevel;
165
166     switch (resampling) {
167     case LinearWithMipmapsResampling:
168         return SkPaint::kMedium_FilterLevel;
169     case LinearResampling:
170         return SkPaint::kLow_FilterLevel;
171     // AwesomeResampling if useBicubicFilter is false means that we do
172     // a manual high quality resampling before drawing to Skia.
173     case AwesomeResampling:
174     default:
175         return SkPaint::kNone_FilterLevel;
176     }
177 }
178
179 // This function is used to scale an image and extract a scaled fragment.
180 //
181 // ALGORITHM
182 //
183 // Because the scaled image size has to be integers, we approximate the real
184 // scale with the following formula (only X direction is shown):
185 //
186 // scaledImageWidth = round(scaleX * imageRect.width())
187 // approximateScaleX = scaledImageWidth / imageRect.width()
188 //
189 // With this method we maintain a constant scale factor among fragments in
190 // the scaled image. This allows fragments to stitch together to form the
191 // full scaled image. The downside is there will be a small difference
192 // between |scaleX| and |approximateScaleX|.
193 //
194 // A scaled image fragment is identified by:
195 //
196 // - Scaled image size
197 // - Scaled image fragment rectangle (IntRect)
198 //
199 // Scaled image size has been determined and the next step is to compute the
200 // rectangle for the scaled image fragment which needs to be an IntRect.
201 //
202 // scaledSrcRect = srcRect * (approximateScaleX, approximateScaleY)
203 // enclosingScaledSrcRect = enclosingIntRect(scaledSrcRect)
204 //
205 // Finally we extract the scaled image fragment using
206 // (scaledImageSize, enclosingScaledSrcRect).
207 //
208 SkBitmap NativeImageSkia::extractScaledImageFragment(const SkRect& srcRect, float scaleX, float scaleY, SkRect* scaledSrcRect) const
209 {
210     SkISize imageSize = SkISize::Make(bitmap().width(), bitmap().height());
211     SkISize scaledImageSize = SkISize::Make(clampToInteger(roundf(imageSize.width() * scaleX)),
212         clampToInteger(roundf(imageSize.height() * scaleY)));
213
214     SkRect imageRect = SkRect::MakeWH(imageSize.width(), imageSize.height());
215     SkRect scaledImageRect = SkRect::MakeWH(scaledImageSize.width(), scaledImageSize.height());
216
217     SkMatrix scaleTransform;
218     scaleTransform.setRectToRect(imageRect, scaledImageRect, SkMatrix::kFill_ScaleToFit);
219     scaleTransform.mapRect(scaledSrcRect, srcRect);
220
221     scaledSrcRect->intersect(scaledImageRect);
222     SkIRect enclosingScaledSrcRect = enclosingIntRect(*scaledSrcRect);
223
224     // |enclosingScaledSrcRect| can be larger than |scaledImageSize| because
225     // of float inaccuracy so clip to get inside.
226     enclosingScaledSrcRect.intersect(SkIRect::MakeSize(scaledImageSize));
227
228     // scaledSrcRect is relative to the pixel snapped fragment we're extracting.
229     scaledSrcRect->offset(-enclosingScaledSrcRect.x(), -enclosingScaledSrcRect.y());
230
231     return resizedBitmap(scaledImageSize, enclosingScaledSrcRect);
232 }
233
234 // This does a lot of computation to resample only the portion of the bitmap
235 // that will only be drawn. This is critical for performance since when we are
236 // scrolling, for example, we are only drawing a small strip of the image.
237 // Resampling the whole image every time is very slow, so this speeds up things
238 // dramatically.
239 //
240 // Note: this code is only used when the canvas transformation is limited to
241 // scaling or translation.
242 void NativeImageSkia::drawResampledBitmap(GraphicsContext* context, SkPaint& paint, const SkRect& srcRect, const SkRect& destRect) const
243 {
244     TRACE_EVENT0("skia", "drawResampledBitmap");
245     if (context->paintingDisabled())
246         return;
247     // We want to scale |destRect| with transformation in the canvas to obtain
248     // the final scale. The final scale is a combination of scale transform
249     // in canvas and explicit scaling (srcRect and destRect).
250     SkRect screenRect;
251     context->getTotalMatrix().mapRect(&screenRect, destRect);
252     float realScaleX = screenRect.width() / srcRect.width();
253     float realScaleY = screenRect.height() / srcRect.height();
254
255     // This part of code limits scaling only to visible portion in the
256     SkRect destRectVisibleSubset;
257     if (!context->canvas()->getClipBounds(&destRectVisibleSubset))
258         return;
259
260     // ClipRectToCanvas often overshoots, resulting in a larger region than our
261     // original destRect. Intersecting gets us back inside.
262     if (!destRectVisibleSubset.intersect(destRect))
263         return; // Nothing visible in destRect.
264
265     // Find the corresponding rect in the source image.
266     SkMatrix destToSrcTransform;
267     SkRect srcRectVisibleSubset;
268     destToSrcTransform.setRectToRect(destRect, srcRect, SkMatrix::kFill_ScaleToFit);
269     destToSrcTransform.mapRect(&srcRectVisibleSubset, destRectVisibleSubset);
270
271     SkRect scaledSrcRect;
272     SkBitmap scaledImageFragment = extractScaledImageFragment(srcRectVisibleSubset, realScaleX, realScaleY, &scaledSrcRect);
273
274     context->drawBitmapRect(scaledImageFragment, &scaledSrcRect, destRectVisibleSubset, &paint);
275 }
276
277 NativeImageSkia::NativeImageSkia()
278     : m_resizeRequests(0)
279 {
280 }
281
282 NativeImageSkia::NativeImageSkia(const SkBitmap& other)
283     : m_image(other)
284     , m_resizeRequests(0)
285 {
286 }
287
288 NativeImageSkia::NativeImageSkia(const SkBitmap& image, const SkBitmap& resizedImage, const ImageResourceInfo& cachedImageInfo, int resizeRequests)
289     : m_image(image)
290     , m_resizedImage(resizedImage)
291     , m_cachedImageInfo(cachedImageInfo)
292     , m_resizeRequests(resizeRequests)
293 {
294 }
295
296 NativeImageSkia::~NativeImageSkia()
297 {
298 }
299
300 int NativeImageSkia::decodedSize() const
301 {
302     return m_image.getSize() + m_resizedImage.getSize();
303 }
304
305 bool NativeImageSkia::hasResizedBitmap(const SkISize& scaledImageSize, const SkIRect& scaledImageSubset) const
306 {
307     bool imageScaleEqual = m_cachedImageInfo.scaledImageSize == scaledImageSize;
308     bool scaledImageSubsetAvailable = m_cachedImageInfo.scaledImageSubset.contains(scaledImageSubset);
309     return imageScaleEqual && scaledImageSubsetAvailable && !m_resizedImage.empty();
310 }
311
312 SkBitmap NativeImageSkia::resizedBitmap(const SkISize& scaledImageSize, const SkIRect& scaledImageSubset) const
313 {
314     ASSERT(!DeferredImageDecoder::isLazyDecoded(m_image));
315
316     if (!hasResizedBitmap(scaledImageSize, scaledImageSubset)) {
317         bool shouldCache = isDataComplete()
318             && shouldCacheResampling(scaledImageSize, scaledImageSubset);
319
320         TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ResizeImage", "cached", shouldCache);
321         // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
322         PlatformInstrumentation::willResizeImage(shouldCache);
323         SkBitmap resizedImage = skia::ImageOperations::Resize(m_image, skia::ImageOperations::RESIZE_LANCZOS3, scaledImageSize.width(), scaledImageSize.height(), scaledImageSubset);
324         resizedImage.setImmutable();
325         PlatformInstrumentation::didResizeImage();
326
327         if (!shouldCache)
328             return resizedImage;
329
330         m_resizedImage = resizedImage;
331     }
332
333     SkBitmap resizedSubset;
334     SkIRect resizedSubsetRect = m_cachedImageInfo.rectInSubset(scaledImageSubset);
335     m_resizedImage.extractSubset(&resizedSubset, resizedSubsetRect);
336     return resizedSubset;
337 }
338
339 static bool shouldDrawAntiAliased(GraphicsContext* context, const SkRect& destRect)
340 {
341     if (!context->shouldAntialias())
342         return false;
343     const SkMatrix totalMatrix = context->getTotalMatrix();
344     // Don't disable anti-aliasing if we're rotated or skewed.
345     if (!totalMatrix.rectStaysRect())
346         return true;
347     // Disable anti-aliasing for scales or n*90 degree rotations.
348     // Allow to opt out of the optimization though for "hairline" geometry
349     // images - using the shouldAntialiasHairlineImages() GraphicsContext flag.
350     if (!context->shouldAntialiasHairlineImages())
351         return false;
352     // Check if the dimensions of the destination are "small" (less than one
353     // device pixel). To prevent sudden drop-outs. Since we know that
354     // kRectStaysRect_Mask is set, the matrix either has scale and no skew or
355     // vice versa. We can query the kAffine_Mask flag to determine which case
356     // it is.
357     // FIXME: This queries the CTM while drawing, which is generally
358     // discouraged. Always drawing with AA can negatively impact performance
359     // though - that's why it's not always on.
360     SkScalar widthExpansion, heightExpansion;
361     if (totalMatrix.getType() & SkMatrix::kAffine_Mask)
362         widthExpansion = totalMatrix[SkMatrix::kMSkewY], heightExpansion = totalMatrix[SkMatrix::kMSkewX];
363     else
364         widthExpansion = totalMatrix[SkMatrix::kMScaleX], heightExpansion = totalMatrix[SkMatrix::kMScaleY];
365     return destRect.width() * fabs(widthExpansion) < 1 || destRect.height() * fabs(heightExpansion) < 1;
366 }
367
368 void NativeImageSkia::draw(GraphicsContext* context, const SkRect& srcRect, const SkRect& destRect, PassRefPtr<SkXfermode> compOp) const
369 {
370     TRACE_EVENT0("skia", "NativeImageSkia::draw");
371     SkPaint paint;
372     paint.setXfermode(compOp.get());
373     paint.setColorFilter(context->colorFilter());
374     paint.setAlpha(context->getNormalizedAlpha());
375     paint.setLooper(context->drawLooper());
376     paint.setAntiAlias(shouldDrawAntiAliased(context, destRect));
377
378     bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap());
379
380     ResamplingMode resampling;
381     if (context->isAccelerated()) {
382         resampling = LinearResampling;
383     } else if (context->printing()) {
384         resampling = NoResampling;
385     } else if (isLazyDecoded) {
386         resampling = AwesomeResampling;
387     } else {
388         // Take into account scale applied to the canvas when computing sampling mode (e.g. CSS scale or page scale).
389         SkRect destRectTarget = destRect;
390         SkMatrix totalMatrix = context->getTotalMatrix();
391         if (!(totalMatrix.getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)))
392             totalMatrix.mapRect(&destRectTarget, destRect);
393
394         resampling = computeResamplingMode(totalMatrix,
395             SkScalarToFloat(srcRect.width()), SkScalarToFloat(srcRect.height()),
396             SkScalarToFloat(destRectTarget.width()), SkScalarToFloat(destRectTarget.height()));
397     }
398
399     if (resampling == NoResampling) {
400         // FIXME: This is to not break tests (it results in the filter bitmap flag
401         // being set to true). We need to decide if we respect NoResampling
402         // being returned from computeResamplingMode.
403         resampling = LinearResampling;
404     }
405     resampling = limitResamplingMode(context, resampling);
406
407     // FIXME: Bicubic filtering in Skia is only applied to defer-decoded images
408     // as an experiment. Once this filtering code path becomes stable we should
409     // turn this on for all cases, including non-defer-decoded images.
410     bool useBicubicFilter = resampling == AwesomeResampling && isLazyDecoded;
411
412     paint.setFilterLevel(convertToSkiaFilterLevel(useBicubicFilter, resampling));
413
414     if (resampling == AwesomeResampling && !useBicubicFilter) {
415         // Resample the image and then draw the result to canvas with bilinear
416         // filtering.
417         drawResampledBitmap(context, paint, srcRect, destRect);
418     } else {
419         // We want to filter it if we decided to do interpolation above, or if
420         // there is something interesting going on with the matrix (like a rotation).
421         // Note: for serialization, we will want to subset the bitmap first so we
422         // don't send extra pixels.
423         context->drawBitmapRect(bitmap(), &srcRect, destRect, &paint);
424     }
425     if (isLazyDecoded)
426         PlatformInstrumentation::didDrawLazyPixelRef(bitmap().getGenerationID());
427     context->didDrawRect(destRect, paint, &bitmap());
428 }
429
430 static SkBitmap createBitmapWithSpace(const SkBitmap& bitmap, int spaceWidth, int spaceHeight)
431 {
432     SkImageInfo info = bitmap.info();
433     info.fWidth += spaceWidth;
434     info.fHeight += spaceHeight;
435     info.fAlphaType = kPremul_SkAlphaType;
436
437     SkBitmap result;
438     result.allocPixels(info);
439     result.eraseColor(SK_ColorTRANSPARENT);
440     bitmap.copyPixelsTo(reinterpret_cast<uint8_t*>(result.getPixels()), result.rowBytes() * result.height(), result.rowBytes());
441
442     return result;
443 }
444
445 void NativeImageSkia::drawPattern(
446     GraphicsContext* context,
447     const FloatRect& floatSrcRect,
448     const FloatSize& scale,
449     const FloatPoint& phase,
450     CompositeOperator compositeOp,
451     const FloatRect& destRect,
452     blink::WebBlendMode blendMode,
453     const IntSize& repeatSpacing) const
454 {
455     FloatRect normSrcRect = floatSrcRect;
456     normSrcRect.intersect(FloatRect(0, 0, bitmap().width(), bitmap().height()));
457     if (destRect.isEmpty() || normSrcRect.isEmpty())
458         return; // nothing to draw
459
460     SkMatrix totalMatrix = context->getTotalMatrix();
461     AffineTransform ctm = context->getCTM();
462     SkScalar ctmScaleX = ctm.xScale();
463     SkScalar ctmScaleY = ctm.yScale();
464     totalMatrix.preScale(scale.width(), scale.height());
465
466     // Figure out what size the bitmap will be in the destination. The
467     // destination rect is the bounds of the pattern, we need to use the
468     // matrix to see how big it will be.
469     SkRect destRectTarget;
470     totalMatrix.mapRect(&destRectTarget, normSrcRect);
471
472     float destBitmapWidth = SkScalarToFloat(destRectTarget.width());
473     float destBitmapHeight = SkScalarToFloat(destRectTarget.height());
474
475     bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap());
476
477     // Compute the resampling mode.
478     ResamplingMode resampling;
479     if (context->isAccelerated() || context->printing())
480         resampling = LinearResampling;
481     else if (isLazyDecoded)
482         resampling = AwesomeResampling;
483     else
484         resampling = computeResamplingMode(totalMatrix, normSrcRect.width(), normSrcRect.height(), destBitmapWidth, destBitmapHeight);
485     resampling = limitResamplingMode(context, resampling);
486
487     SkMatrix shaderTransform;
488     RefPtr<SkShader> shader;
489
490     // Bicubic filter is only applied to defer-decoded images, see
491     // NativeImageSkia::draw for details.
492     bool useBicubicFilter = resampling == AwesomeResampling && isLazyDecoded;
493
494     if (resampling == AwesomeResampling && !useBicubicFilter) {
495         // Do nice resampling.
496         float scaleX = destBitmapWidth / normSrcRect.width();
497         float scaleY = destBitmapHeight / normSrcRect.height();
498         SkRect scaledSrcRect;
499
500         // The image fragment generated here is not exactly what is
501         // requested. The scale factor used is approximated and image
502         // fragment is slightly larger to align to integer
503         // boundaries.
504         SkBitmap resampled = extractScaledImageFragment(normSrcRect, scaleX, scaleY, &scaledSrcRect);
505         if (repeatSpacing.isZero()) {
506             shader = adoptRef(SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
507         } else {
508             shader = adoptRef(SkShader::CreateBitmapShader(
509                 createBitmapWithSpace(resampled, repeatSpacing.width() * ctmScaleX, repeatSpacing.height() * ctmScaleY),
510                 SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
511         }
512
513         // Since we just resized the bitmap, we need to remove the scale
514         // applied to the pixels in the bitmap shader. This means we need
515         // CTM * shaderTransform to have identity scale. Since we
516         // can't modify CTM (or the rectangle will be drawn in the wrong
517         // place), we must set shaderTransform's scale to the inverse of
518         // CTM scale.
519         shaderTransform.setScale(ctmScaleX ? 1 / ctmScaleX : 1, ctmScaleY ? 1 / ctmScaleY : 1);
520     } else {
521         // No need to resample before drawing.
522         SkBitmap srcSubset;
523         bitmap().extractSubset(&srcSubset, enclosingIntRect(normSrcRect));
524         if (repeatSpacing.isZero()) {
525             shader = adoptRef(SkShader::CreateBitmapShader(srcSubset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
526         } else {
527             shader = adoptRef(SkShader::CreateBitmapShader(
528                 createBitmapWithSpace(srcSubset, repeatSpacing.width() * ctmScaleX, repeatSpacing.height() * ctmScaleY),
529                 SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
530         }
531
532         // Because no resizing occurred, the shader transform should be
533         // set to the pattern's transform, which just includes scale.
534         shaderTransform.setScale(scale.width(), scale.height());
535     }
536
537     // We also need to translate it such that the origin of the pattern is the
538     // origin of the destination rect, which is what WebKit expects. Skia uses
539     // the coordinate system origin as the base for the pattern. If WebKit wants
540     // a shifted image, it will shift it from there using the shaderTransform.
541     float adjustedX = phase.x() + normSrcRect.x() * scale.width();
542     float adjustedY = phase.y() + normSrcRect.y() * scale.height();
543     shaderTransform.postTranslate(SkFloatToScalar(adjustedX), SkFloatToScalar(adjustedY));
544     shader->setLocalMatrix(shaderTransform);
545
546     SkPaint paint;
547     paint.setShader(shader.get());
548     paint.setXfermode(WebCoreCompositeToSkiaComposite(compositeOp, blendMode).get());
549     paint.setColorFilter(context->colorFilter());
550     paint.setFilterLevel(convertToSkiaFilterLevel(useBicubicFilter, resampling));
551
552     if (isLazyDecoded)
553         PlatformInstrumentation::didDrawLazyPixelRef(bitmap().getGenerationID());
554
555     context->drawRect(destRect, paint);
556 }
557
558 bool NativeImageSkia::shouldCacheResampling(const SkISize& scaledImageSize, const SkIRect& scaledImageSubset) const
559 {
560     // Check whether the requested dimensions match previous request.
561     bool matchesPreviousRequest = m_cachedImageInfo.isEqual(scaledImageSize, scaledImageSubset);
562     if (matchesPreviousRequest)
563         ++m_resizeRequests;
564     else {
565         m_cachedImageInfo.set(scaledImageSize, scaledImageSubset);
566         m_resizeRequests = 0;
567         // Reset m_resizedImage now, because we don't distinguish
568         // between the last requested resize info and m_resizedImage's
569         // resize info.
570         m_resizedImage.reset();
571     }
572
573     // We can not cache incomplete frames. This might be a good optimization in
574     // the future, were we know how much of the frame has been decoded, so when
575     // we incrementally draw more of the image, we only have to resample the
576     // parts that are changed.
577     if (!isDataComplete())
578         return false;
579
580     // If the destination bitmap is excessively large, we'll never allow caching.
581     static const unsigned long long kLargeBitmapSize = 4096ULL * 4096ULL;
582     unsigned long long fullSize = static_cast<unsigned long long>(scaledImageSize.width()) * static_cast<unsigned long long>(scaledImageSize.height());
583     unsigned long long fragmentSize = static_cast<unsigned long long>(scaledImageSubset.width()) * static_cast<unsigned long long>(scaledImageSubset.height());
584
585     if (fragmentSize > kLargeBitmapSize)
586         return false;
587
588     // If the destination bitmap is small, we'll always allow caching, since
589     // there is not very much penalty for computing it and it may come in handy.
590     static const unsigned kSmallBitmapSize = 4096;
591     if (fragmentSize <= kSmallBitmapSize)
592         return true;
593
594     // If "too many" requests have been made for this bitmap, we assume that
595     // many more will be made as well, and we'll go ahead and cache it.
596     static const int kManyRequestThreshold = 4;
597     if (m_resizeRequests >= kManyRequestThreshold)
598         return true;
599
600     // If more than 1/4 of the resized image is requested, it's worth caching.
601     return fragmentSize > fullSize / 4;
602 }
603
604 NativeImageSkia::ImageResourceInfo::ImageResourceInfo()
605 {
606     scaledImageSize.setEmpty();
607     scaledImageSubset.setEmpty();
608 }
609
610 bool NativeImageSkia::ImageResourceInfo::isEqual(const SkISize& otherScaledImageSize, const SkIRect& otherScaledImageSubset) const
611 {
612     return scaledImageSize == otherScaledImageSize && scaledImageSubset == otherScaledImageSubset;
613 }
614
615 void NativeImageSkia::ImageResourceInfo::set(const SkISize& otherScaledImageSize, const SkIRect& otherScaledImageSubset)
616 {
617     scaledImageSize = otherScaledImageSize;
618     scaledImageSubset = otherScaledImageSubset;
619 }
620
621 SkIRect NativeImageSkia::ImageResourceInfo::rectInSubset(const SkIRect& otherScaledImageSubset)
622 {
623     if (!scaledImageSubset.contains(otherScaledImageSubset))
624         return SkIRect::MakeEmpty();
625     SkIRect subsetRect = otherScaledImageSubset;
626     subsetRect.offset(-scaledImageSubset.x(), -scaledImageSubset.y());
627     return subsetRect;
628 }
629
630 } // namespace WebCore