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