Extend platform layer so it can pass blend modes to the compositing calls
[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 "SkBitmap.h"
44 #include "SkPixelRef.h"
45 #include "SkRect.h"
46 #include "SkShader.h"
47 #include "SkiaUtils.h"
48 #include "Texture.h"
49 #include <wtf/text/WTFString.h>
50
51 #include "skia/ext/image_operations.h"
52 #include "skia/ext/platform_canvas.h"
53
54 #include <limits>
55 #include <math.h>
56
57 #if PLATFORM(CHROMIUM)
58 #include "TraceEvent.h"
59 #endif
60
61 namespace WebCore {
62
63 // Used by computeResamplingMode to tell how bitmaps should be resampled.
64 enum ResamplingMode {
65     // Nearest neighbor resampling. Used when we detect that the page is
66     // trying to make a pattern by stretching a small bitmap very large.
67     RESAMPLE_NONE,
68
69     // Default skia resampling. Used for large growing of images where high
70     // quality resampling doesn't get us very much except a slowdown.
71     RESAMPLE_LINEAR,
72
73     // High quality resampling.
74     RESAMPLE_AWESOME,
75 };
76
77 static ResamplingMode computeResamplingMode(const SkMatrix& matrix, const NativeImageSkia& bitmap, float srcWidth, float srcHeight, float destWidth, float destHeight)
78 {
79     // The percent change below which we will not resample. This usually means
80     // an off-by-one error on the web page, and just doing nearest neighbor
81     // sampling is usually good enough.
82     const float kFractionalChangeThreshold = 0.025f;
83
84     // Images smaller than this in either direction are considered "small" and
85     // are not resampled ever (see below).
86     const int kSmallImageSizeThreshold = 8;
87
88     // The amount an image can be stretched in a single direction before we
89     // say that it is being stretched so much that it must be a line or
90     // background that doesn't need resampling.
91     const float kLargeStretch = 3.0f;
92
93     // Figure out if we should resample this image. We try to prune out some
94     // common cases where resampling won't give us anything, since it is much
95     // slower than drawing stretched.
96     float diffWidth = fabs(destWidth - srcWidth);
97     float diffHeight = fabs(destHeight - srcHeight);
98     bool widthNearlyEqual = diffWidth < std::numeric_limits<float>::epsilon();
99     bool heightNearlyEqual = diffHeight < std::numeric_limits<float>::epsilon();
100     // We don't need to resample if the source and destination are the same.
101     if (widthNearlyEqual && heightNearlyEqual)
102         return RESAMPLE_NONE;
103
104     if (srcWidth <= kSmallImageSizeThreshold
105         || srcHeight <= kSmallImageSizeThreshold
106         || destWidth <= kSmallImageSizeThreshold
107         || destHeight <= kSmallImageSizeThreshold) {
108         // Never resample small images. These are often used for borders and
109         // rules (think 1x1 images used to make lines).
110         return RESAMPLE_NONE;
111     }
112
113     if (srcHeight * kLargeStretch <= destHeight || srcWidth * kLargeStretch <= destWidth) {
114         // Large image detected.
115
116         // Don't resample if it is being stretched a lot in only one direction.
117         // This is trying to catch cases where somebody has created a border
118         // (which might be large) and then is stretching it to fill some part
119         // of the page.
120         if (widthNearlyEqual || heightNearlyEqual)
121             return RESAMPLE_NONE;
122
123         // The image is growing a lot and in more than one direction. Resampling
124         // is slow and doesn't give us very much when growing a lot.
125         return RESAMPLE_LINEAR;
126     }
127
128     if ((diffWidth / srcWidth < kFractionalChangeThreshold)
129         && (diffHeight / srcHeight < kFractionalChangeThreshold)) {
130         // It is disappointingly common on the web for image sizes to be off by
131         // one or two pixels. We don't bother resampling if the size difference
132         // is a small fraction of the original size.
133         return RESAMPLE_NONE;
134     }
135
136     // When the image is not yet done loading, use linear. We don't cache the
137     // partially resampled images, and as they come in incrementally, it causes
138     // us to have to resample the whole thing every time.
139     if (!bitmap.isDataComplete())
140         return RESAMPLE_LINEAR;
141
142     // Everything else gets resampled.
143     // High quality interpolation only enabled for scaling and translation.
144     if (!(matrix.getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)))
145         return RESAMPLE_AWESOME;
146     
147     return RESAMPLE_LINEAR;
148 }
149
150 static ResamplingMode limitResamplingMode(PlatformContextSkia* platformContext, ResamplingMode resampling)
151 {
152     switch (platformContext->interpolationQuality()) {
153     case InterpolationNone:
154         return RESAMPLE_NONE;
155     case InterpolationMedium:
156         // For now we treat InterpolationMedium and InterpolationLow the same.
157     case InterpolationLow:
158         if (resampling == RESAMPLE_AWESOME)
159             return RESAMPLE_LINEAR;
160         break;
161     case InterpolationHigh:
162     case InterpolationDefault:
163         break;
164     }
165
166     return resampling;
167 }
168
169 // Return true if the rectangle is aligned to integer boundaries.
170 // See comments for computeBitmapDrawRects() for how this is used.
171 static bool areBoundariesIntegerAligned(const SkRect& rect)
172 {
173     // Value is 1.19209e-007. This is the tolerance threshold.
174     const float epsilon = std::numeric_limits<float>::epsilon();
175     SkIRect roundedRect = roundedIntRect(rect);
176
177     return fabs(rect.x() - roundedRect.x()) < epsilon
178         && fabs(rect.y() - roundedRect.y()) < epsilon
179         && fabs(rect.right() - roundedRect.right()) < epsilon
180         && fabs(rect.bottom() - roundedRect.bottom()) < epsilon;
181 }
182
183 // FIXME: Remove this code when SkCanvas accepts SkRect as source rectangle.
184 // See crbug.com/117597 for background.
185 //
186 // WebKit wants to draw a sub-rectangle (FloatRect) in a bitmap and scale it to
187 // another FloatRect. However Skia only allows bitmap to be addressed by a
188 // IntRect. This function computes the appropriate IntRect that encloses the
189 // source rectangle and the corresponding enclosing destination rectangle,
190 // while maintaining the scale factor.
191 //
192 // |srcRect| is the source rectangle in the bitmap. Return true if fancy
193 // alignment is required. User of this function needs to clip to |dstRect|.
194 // Return false if clipping is not needed.
195 //
196 // |dstRect| is the input rectangle that |srcRect| is scaled to.
197 //
198 // |outSrcRect| and |outDstRect| are the corresponding output rectangles.
199 //
200 // ALGORITHM
201 //
202 // The objective is to (a) find an enclosing IntRect for the source rectangle
203 // and (b) the corresponding FloatRect in destination space.
204 //
205 // These are the steps performed:
206 //
207 // 1. IntRect enclosingSrcRect = enclosingIntRect(srcRect)
208 //
209 //    Compute the enclosing IntRect for |srcRect|. This ensures the bitmap
210 //    image is addressed with integer boundaries.
211 //
212 // 2. FloatRect enclosingDestRect = mapSrcToDest(enclosingSrcRect)
213 //
214 //    Map the enclosing source rectangle to destination coordinate space.
215 //
216 // The output will be enclosingSrcRect and enclosingDestRect from the
217 // algorithm above.
218 static bool computeBitmapDrawRects(const SkISize& bitmapSize, const SkRect& srcRect, const SkRect& dstRect, SkIRect* outSrcRect, SkRect* outDstRect)
219 {
220     if (areBoundariesIntegerAligned(srcRect)) {
221         *outSrcRect = roundedIntRect(srcRect);
222         *outDstRect = dstRect;
223         return false;
224     }
225
226     SkIRect bitmapRect = SkIRect::MakeSize(bitmapSize);
227     SkIRect enclosingSrcRect = enclosingIntRect(srcRect);
228     enclosingSrcRect.intersect(bitmapRect); // Clip to bitmap rectangle.
229     SkRect enclosingDstRect;
230     enclosingDstRect.set(enclosingSrcRect);
231     SkMatrix transform;
232     transform.setRectToRect(srcRect, dstRect, SkMatrix::kFill_ScaleToFit);
233     transform.mapRect(&enclosingDstRect);
234     *outSrcRect = enclosingSrcRect;
235     *outDstRect = enclosingDstRect;
236     return true;
237 }
238
239 // This function is used to scale an image and extract a scaled fragment.
240 //
241 // ALGORITHM
242 //
243 // Because the scaled image size has to be integers, we approximate the real
244 // scale with the following formula (only X direction is shown):
245 //
246 // scaledImageWidth = round(scaleX * imageRect.width())
247 // approximateScaleX = scaledImageWidth / imageRect.width()
248 //
249 // With this method we maintain a constant scale factor among fragments in
250 // the scaled image. This allows fragments to stitch together to form the
251 // full scaled image. The downside is there will be a small difference
252 // between |scaleX| and |approximateScaleX|.
253 //
254 // A scaled image fragment is identified by:
255 //
256 // - Scaled image size
257 // - Scaled image fragment rectangle (IntRect)
258 //
259 // Scaled image size has been determined and the next step is to compute the
260 // rectangle for the scaled image fragment which needs to be an IntRect.
261 //
262 // scaledSrcRect = srcRect * (approximateScaleX, approximateScaleY)
263 // enclosingScaledSrcRect = enclosingIntRect(scaledSrcRect)
264 //
265 // Finally we extract the scaled image fragment using
266 // (scaledImageSize, enclosingScaledSrcRect).
267 //
268 static SkBitmap extractScaledImageFragment(const NativeImageSkia& bitmap, const SkRect& srcRect, float scaleX, float scaleY, SkRect* scaledSrcRect, SkIRect* enclosingScaledSrcRect)
269 {
270     SkISize imageSize = SkISize::Make(bitmap.bitmap().width(), bitmap.bitmap().height());
271     SkISize scaledImageSize = SkISize::Make(clampToInteger(roundf(imageSize.width() * scaleX)),
272         clampToInteger(roundf(imageSize.height() * scaleY)));
273
274     SkRect imageRect = SkRect::MakeWH(imageSize.width(), imageSize.height());
275     SkRect scaledImageRect = SkRect::MakeWH(scaledImageSize.width(), scaledImageSize.height());
276
277     SkMatrix scaleTransform;
278     scaleTransform.setRectToRect(imageRect, scaledImageRect, SkMatrix::kFill_ScaleToFit);
279     scaleTransform.mapRect(scaledSrcRect, srcRect);
280
281     scaledSrcRect->intersect(scaledImageRect);
282     *enclosingScaledSrcRect = enclosingIntRect(*scaledSrcRect);
283
284     // |enclosingScaledSrcRect| can be larger than |scaledImageSize| because
285     // of float inaccuracy so clip to get inside.
286     enclosingScaledSrcRect->intersect(SkIRect::MakeSize(scaledImageSize));
287     return bitmap.resizedBitmap(scaledImageSize, *enclosingScaledSrcRect);
288 }
289
290 // This does a lot of computation to resample only the portion of the bitmap
291 // that will only be drawn. This is critical for performance since when we are
292 // scrolling, for example, we are only drawing a small strip of the image.
293 // Resampling the whole image every time is very slow, so this speeds up things
294 // dramatically.
295 //
296 // Note: this code is only used when the canvas transformation is limited to
297 // scaling or translation.
298 static void drawResampledBitmap(PlatformContextSkia* context, SkPaint& paint, const NativeImageSkia& bitmap, const SkRect& srcRect, const SkRect& destRect)
299 {
300 #if PLATFORM(CHROMIUM)
301     TRACE_EVENT0("skia", "drawResampledBitmap");
302 #endif
303     // We want to scale |destRect| with transformation in the canvas to obtain
304     // the final scale. The final scale is a combination of scale transform
305     // in canvas and explicit scaling (srcRect and destRect).
306     SkRect screenRect;
307     context->getTotalMatrix().mapRect(&screenRect, destRect);
308     float realScaleX = screenRect.width() / srcRect.width();
309     float realScaleY = screenRect.height() / srcRect.height();
310
311     // This part of code limits scaling only to visible portion in the
312     SkRect destRectVisibleSubset;
313     ClipRectToCanvas(context, destRect, &destRectVisibleSubset);
314
315     // ClipRectToCanvas often overshoots, resulting in a larger region than our
316     // original destRect. Intersecting gets us back inside.
317     if (!destRectVisibleSubset.intersect(destRect))
318         return; // Nothing visible in destRect.
319
320     // Find the corresponding rect in the source image.
321     SkMatrix destToSrcTransform;
322     SkRect srcRectVisibleSubset;
323     destToSrcTransform.setRectToRect(destRect, srcRect, SkMatrix::kFill_ScaleToFit);
324     destToSrcTransform.mapRect(&srcRectVisibleSubset, destRectVisibleSubset);
325
326     SkRect scaledSrcRect;
327     SkIRect enclosingScaledSrcRect;
328     SkBitmap scaledImageFragment = extractScaledImageFragment(bitmap, srcRectVisibleSubset, realScaleX, realScaleY, &scaledSrcRect, &enclosingScaledSrcRect);
329
330     // Expand the destination rectangle because the source rectangle was
331     // expanded to fit to integer boundaries.
332     SkMatrix scaledSrcToDestTransform;
333     scaledSrcToDestTransform.setRectToRect(scaledSrcRect, destRectVisibleSubset, SkMatrix::kFill_ScaleToFit);
334     SkRect enclosingDestRect;
335     enclosingDestRect.set(enclosingScaledSrcRect);
336     scaledSrcToDestTransform.mapRect(&enclosingDestRect);
337
338     // The reason we do clipping is because Skia doesn't support SkRect as
339     // source rect. See http://crbug.com/145540.
340     // When Skia supports then use this as the source rect to replace 0.
341     //
342     // scaledSrcRect.offset(-enclosingScaledSrcRect.x(), -enclosingScaledSrcRect.y());
343     context->save();
344     context->clipRect(destRectVisibleSubset);
345
346     // Because the image fragment is generated with an approxmiated scaling
347     // factor. This draw will perform a close to 1 scaling.
348     //
349     // NOTE: For future optimization. If the difference in scale is so small
350     // that Skia doesn't produce a difference then we can just blit it directly
351     // to enhance performance.
352     context->drawBitmapRect(scaledImageFragment, 0, enclosingDestRect, &paint);
353     context->restore();
354 }
355
356 static bool hasNon90rotation(PlatformContextSkia* context)
357 {
358     return !context->getTotalMatrix().rectStaysRect();
359 }
360
361 static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, const SkRect& srcRect, const SkRect& destRect, const SkXfermode::Mode& compOp)
362 {
363 #if PLATFORM(CHROMIUM)
364     TRACE_EVENT0("skia", "paintSkBitmap");
365 #endif
366     SkPaint paint;
367     paint.setXfermodeMode(compOp);
368     paint.setAlpha(platformContext->getNormalizedAlpha());
369     paint.setLooper(platformContext->getDrawLooper());
370     // only antialias if we're rotated or skewed
371     paint.setAntiAlias(hasNon90rotation(platformContext));
372
373     ResamplingMode resampling;
374     if (platformContext->isAccelerated())
375         resampling = RESAMPLE_LINEAR;
376     else if (platformContext->printing())
377         resampling = RESAMPLE_NONE;
378     else {
379         // Take into account scale applied to the canvas when computing sampling mode (e.g. CSS scale or page scale).
380         SkRect destRectTarget = destRect;
381         if (!(platformContext->getTotalMatrix().getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)))
382             platformContext->getTotalMatrix().mapRect(&destRectTarget, destRect);
383
384         resampling = computeResamplingMode(platformContext->getTotalMatrix(), bitmap,
385             SkScalarToFloat(srcRect.width()), SkScalarToFloat(srcRect.height()),
386             SkScalarToFloat(destRectTarget.width()), SkScalarToFloat(destRectTarget.height()));
387     }
388
389     if (resampling == RESAMPLE_NONE) {
390         // FIXME: This is to not break tests (it results in the filter bitmap flag
391         // being set to true). We need to decide if we respect RESAMPLE_NONE
392         // being returned from computeResamplingMode.
393         resampling = RESAMPLE_LINEAR;
394     }
395     resampling = limitResamplingMode(platformContext, resampling);
396     paint.setFilterBitmap(resampling == RESAMPLE_LINEAR);
397     if (resampling == RESAMPLE_AWESOME)
398         drawResampledBitmap(platformContext, paint, bitmap, srcRect, destRect);
399     else {
400         // No resampling necessary, we can just draw the bitmap. We want to
401         // filter it if we decided to do linear interpolation above, or if there
402         // is something interesting going on with the matrix (like a rotation).
403         // Note: for serialization, we will want to subset the bitmap first so
404         // we don't send extra pixels.
405         SkIRect enclosingSrcRect;
406         SkRect enclosingDestRect;
407         SkISize bitmapSize = SkISize::Make(bitmap.bitmap().width(), bitmap.bitmap().height());
408         bool needsClipping = computeBitmapDrawRects(bitmapSize, srcRect, destRect, &enclosingSrcRect, &enclosingDestRect);
409
410         if (enclosingSrcRect.isEmpty() || enclosingDestRect.isEmpty())
411             return;
412
413         // If destination is enlarged because source rectangle didn't align to
414         // integer boundaries then we draw a slightly larger rectangle and clip
415         // to the original destination rectangle.
416         // See http://crbug.com/145540.
417         if (needsClipping) {
418             platformContext->save();
419             platformContext->clipRect(destRect);
420         }
421
422         platformContext->drawBitmapRect(bitmap.bitmap(), &enclosingSrcRect, enclosingDestRect, &paint);
423
424         if (needsClipping)
425             platformContext->restore();
426     }
427     platformContext->didDrawRect(destRect, paint, &bitmap.bitmap());
428 }
429
430 // A helper method for translating negative width and height values.
431 FloatRect normalizeRect(const FloatRect& rect)
432 {
433     FloatRect norm = rect;
434     if (norm.width() < 0) {
435         norm.setX(norm.x() + norm.width());
436         norm.setWidth(-norm.width());
437     }
438     if (norm.height() < 0) {
439         norm.setY(norm.y() + norm.height());
440         norm.setHeight(-norm.height());
441     }
442     return norm;
443 }
444
445 bool FrameData::clear(bool clearMetadata)
446 {
447     if (clearMetadata)
448         m_haveMetadata = false;
449
450     m_orientation = DefaultImageOrientation;
451
452     if (m_frame) {
453         // ImageSource::createFrameAtIndex() allocated |m_frame| and passed
454         // ownership to BitmapImage; we must delete it here.
455         delete m_frame;
456         m_frame = 0;
457         return true;
458     }
459     return false;
460 }
461
462 void Image::drawPattern(GraphicsContext* context,
463                         const FloatRect& floatSrcRect,
464                         const AffineTransform& patternTransform,
465                         const FloatPoint& phase,
466                         ColorSpace styleColorSpace,
467                         CompositeOperator compositeOp,
468                         const FloatRect& destRect)
469 {
470 #if PLATFORM(CHROMIUM)
471     TRACE_EVENT0("skia", "Image::drawPattern");
472 #endif
473     NativeImageSkia* bitmap = nativeImageForCurrentFrame();
474     if (!bitmap)
475         return;
476
477     FloatRect normSrcRect = normalizeRect(floatSrcRect);
478     normSrcRect.intersect(FloatRect(0, 0, bitmap->bitmap().width(), bitmap->bitmap().height()));
479     if (destRect.isEmpty() || normSrcRect.isEmpty())
480         return; // nothing to draw
481
482     SkMatrix ctm = context->platformContext()->getTotalMatrix();
483     SkMatrix totalMatrix;
484     totalMatrix.setConcat(ctm, patternTransform);
485
486     // Figure out what size the bitmap will be in the destination. The
487     // destination rect is the bounds of the pattern, we need to use the
488     // matrix to see how big it will be.
489     SkRect destRectTarget;
490     totalMatrix.mapRect(&destRectTarget, normSrcRect);
491
492     float destBitmapWidth = SkScalarToFloat(destRectTarget.width());
493     float destBitmapHeight = SkScalarToFloat(destRectTarget.height());
494
495     // Compute the resampling mode.
496     ResamplingMode resampling;
497     if (context->platformContext()->isAccelerated() || context->platformContext()->printing())
498         resampling = RESAMPLE_LINEAR;
499     else
500         resampling = computeResamplingMode(totalMatrix, *bitmap, normSrcRect.width(), normSrcRect.height(), destBitmapWidth, destBitmapHeight);
501     resampling = limitResamplingMode(context->platformContext(), resampling);
502
503     // Load the transform WebKit requested.
504     SkMatrix matrix(patternTransform);
505
506     SkShader* shader;
507     if (resampling == RESAMPLE_AWESOME) {
508         // Do nice resampling.
509         float scaleX = destBitmapWidth / normSrcRect.width();
510         float scaleY = destBitmapHeight / normSrcRect.height();
511         SkRect scaledSrcRect;
512         SkIRect enclosingScaledSrcRect;
513
514         // The image fragment generated here is not exactly what is
515         // requested. The scale factor used is approximated and image
516         // fragment is slightly larger to align to integer
517         // boundaries.
518         SkBitmap resampled = extractScaledImageFragment(*bitmap, normSrcRect, scaleX, scaleY, &scaledSrcRect, &enclosingScaledSrcRect);
519         shader = SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
520
521         // Since we just resized the bitmap, we need to remove the scale
522         // applied to the pixels in the bitmap shader. This means we need
523         // CTM * patternTransform to have identity scale. Since we
524         // can't modify CTM (or the rectangle will be drawn in the wrong
525         // place), we must set patternTransform's scale to the inverse of
526         // CTM scale.
527         matrix.setScaleX(ctm.getScaleX() ? 1 / ctm.getScaleX() : 1);
528         matrix.setScaleY(ctm.getScaleY() ? 1 / ctm.getScaleY() : 1);
529     } else {
530         // No need to do nice resampling.
531         SkBitmap srcSubset;
532         bitmap->bitmap().extractSubset(&srcSubset, enclosingIntRect(normSrcRect));
533         shader = SkShader::CreateBitmapShader(srcSubset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
534     }
535
536     // We also need to translate it such that the origin of the pattern is the
537     // origin of the destination rect, which is what WebKit expects. Skia uses
538     // the coordinate system origin as the base for the patter. If WebKit wants
539     // a shifted image, it will shift it from there using the patternTransform.
540     float adjustedX = phase.x() + normSrcRect.x() *
541                       narrowPrecisionToFloat(patternTransform.a());
542     float adjustedY = phase.y() + normSrcRect.y() *
543                       narrowPrecisionToFloat(patternTransform.d());
544     matrix.postTranslate(SkFloatToScalar(adjustedX),
545                          SkFloatToScalar(adjustedY));
546     shader->setLocalMatrix(matrix);
547
548     SkPaint paint;
549     paint.setShader(shader)->unref();
550     paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp));
551     paint.setFilterBitmap(resampling == RESAMPLE_LINEAR);
552
553     context->platformContext()->drawRect(destRect, paint);
554 }
555
556 // ================================================
557 // BitmapImage Class
558 // ================================================
559
560 // FIXME: These should go to BitmapImageSkia.cpp
561
562 void BitmapImage::invalidatePlatformData()
563 {
564 }
565
566 void BitmapImage::checkForSolidColor()
567 {
568     m_isSolidColor = false;
569     m_checkedForSolidColor = true;
570
571     if (frameCount() > 1)
572         return;
573
574     WebCore::NativeImageSkia* frame = frameAtIndex(0);
575
576     if (frame && size().width() == 1 && size().height() == 1) {
577         SkAutoLockPixels lock(frame->bitmap());
578         if (!frame->bitmap().getPixels())
579             return;
580
581         m_isSolidColor = true;
582         m_solidColor = Color(frame->bitmap().getColor(0, 0));
583     }
584 }
585
586 void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace colorSpace, CompositeOperator compositeOp, BlendMode blendMode)
587 {
588     draw(ctxt, dstRect, srcRect, colorSpace, compositeOp, blendMode, DoNotRespectImageOrientation);
589 }
590
591 void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace colorSpace, CompositeOperator compositeOp, BlendMode, RespectImageOrientationEnum shouldRespectImageOrientation)
592 {
593     if (!m_source.initialized())
594         return;
595
596     // Spin the animation to the correct frame before we try to draw it, so we
597     // don't draw an old frame and then immediately need to draw a newer one,
598     // causing flicker and wasting CPU.
599     startAnimation();
600
601     NativeImageSkia* bm = nativeImageForCurrentFrame();
602     if (!bm)
603         return; // It's too early and we don't have an image yet.
604
605     FloatRect normDstRect = normalizeRect(dstRect);
606     FloatRect normSrcRect = normalizeRect(srcRect);
607     normSrcRect.intersect(FloatRect(0, 0, bm->bitmap().width(), bm->bitmap().height()));
608
609     if (normSrcRect.isEmpty() || normDstRect.isEmpty())
610         return; // Nothing to draw.
611
612     ImageOrientation orientation = DefaultImageOrientation;
613     if (shouldRespectImageOrientation == RespectImageOrientation)
614         orientation = frameOrientationAtIndex(m_currentFrame);
615
616     GraphicsContextStateSaver saveContext(*ctxt, false);
617     if (orientation != DefaultImageOrientation) {
618         saveContext.save();
619
620         // ImageOrientation expects the origin to be at (0, 0)
621         ctxt->translate(normDstRect.x(), normDstRect.y());
622         normDstRect.setLocation(FloatPoint());
623
624         ctxt->concatCTM(orientation.transformFromDefault(normDstRect.size()));
625
626         if (orientation.usesWidthAsHeight()) {
627             // The destination rect will have it's width and height already reversed for the orientation of
628             // the image, as it was needed for page layout, so we need to reverse it back here.
629             normDstRect = FloatRect(normDstRect.x(), normDstRect.y(), normDstRect.height(), normDstRect.width());
630         }
631     }
632
633     paintSkBitmap(ctxt->platformContext(),
634         *bm,
635         normSrcRect,
636         normDstRect,
637         WebCoreCompositeToSkiaComposite(compositeOp));
638
639     if (ImageObserver* observer = imageObserver())
640         observer->didDraw(this);
641 }
642
643 // FIXME: These should go into BitmapImageSingleFrameSkia.cpp
644
645 void BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt,
646     const FloatRect& dstRect,
647     const FloatRect& srcRect,
648     ColorSpace styleColorSpace,
649     CompositeOperator compositeOp, BlendMode)
650 {
651     FloatRect normDstRect = normalizeRect(dstRect);
652     FloatRect normSrcRect = normalizeRect(srcRect);
653     normSrcRect.intersect(FloatRect(0, 0, m_nativeImage.bitmap().width(), m_nativeImage.bitmap().height()));
654
655     if (normSrcRect.isEmpty() || normDstRect.isEmpty())
656         return; // Nothing to draw.
657
658     paintSkBitmap(ctxt->platformContext(),
659         m_nativeImage,
660         normSrcRect,
661         normDstRect,
662         WebCoreCompositeToSkiaComposite(compositeOp));
663
664     if (ImageObserver* observer = imageObserver())
665         observer->didDraw(this);
666 }
667
668 BitmapImageSingleFrameSkia::BitmapImageSingleFrameSkia(const SkBitmap& bitmap, float resolutionScale)
669     : m_nativeImage(bitmap, resolutionScale)
670 {
671 }
672
673 PassRefPtr<BitmapImageSingleFrameSkia> BitmapImageSingleFrameSkia::create(const SkBitmap& bitmap, bool copyPixels, float resolutionScale)
674 {
675     if (copyPixels) {
676         SkBitmap temp;
677         if (!bitmap.deepCopyTo(&temp, bitmap.config()))
678             bitmap.copyTo(&temp, bitmap.config());
679         return adoptRef(new BitmapImageSingleFrameSkia(temp, resolutionScale));
680     }
681     return adoptRef(new BitmapImageSingleFrameSkia(bitmap, resolutionScale));
682 }
683
684 } // namespace WebCore