Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / ui / gfx / canvas.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/gfx/canvas.h"
6
7 #include <cmath>
8 #include <limits>
9
10 #include "base/i18n/rtl.h"
11 #include "base/logging.h"
12 #include "third_party/skia/include/core/SkBitmap.h"
13 #include "third_party/skia/include/effects/SkGradientShader.h"
14 #include "ui/gfx/font_list.h"
15 #include "ui/gfx/rect.h"
16 #include "ui/gfx/size_conversions.h"
17 #include "ui/gfx/skia_util.h"
18 #include "ui/gfx/transform.h"
19
20 #if defined(OS_WIN)
21 #include "ui/gfx/canvas_skia_paint.h"
22 #endif
23
24 namespace gfx {
25
26 Canvas::Canvas(const Size& size, float image_scale, bool is_opaque)
27     : image_scale_(image_scale),
28       canvas_(NULL) {
29   Size pixel_size = ToCeiledSize(ScaleSize(size, image_scale));
30   owned_canvas_ = skia::AdoptRef(skia::CreatePlatformCanvas(pixel_size.width(),
31                                                             pixel_size.height(),
32                                                             is_opaque));
33   canvas_ = owned_canvas_.get();
34 #if defined(OS_WIN) || defined(OS_MACOSX)
35   // skia::PlatformCanvas instances are initialized to 0 by Cairo on Linux, but
36   // uninitialized on Win and Mac.
37   if (!is_opaque)
38     owned_canvas_->clear(SkColorSetARGB(0, 0, 0, 0));
39 #endif
40
41   SkScalar scale_scalar = SkFloatToScalar(image_scale);
42   canvas_->scale(scale_scalar, scale_scalar);
43 }
44
45 Canvas::Canvas(const ImageSkiaRep& image_rep, bool is_opaque)
46     : image_scale_(image_rep.scale()),
47       owned_canvas_(skia::AdoptRef(
48           skia::CreatePlatformCanvas(image_rep.pixel_width(),
49                                      image_rep.pixel_height(),
50                                      is_opaque))),
51       canvas_(owned_canvas_.get()) {
52   SkScalar scale_scalar = SkFloatToScalar(image_scale_);
53   canvas_->scale(scale_scalar, scale_scalar);
54   DrawImageInt(ImageSkia(image_rep), 0, 0);
55 }
56
57 Canvas::Canvas()
58     : image_scale_(1.0),
59       owned_canvas_(skia::AdoptRef(skia::CreatePlatformCanvas(0, 0, false))),
60       canvas_(owned_canvas_.get()) {
61 }
62
63 Canvas::~Canvas() {
64 }
65
66 // static
67 Canvas* Canvas::CreateCanvasWithoutScaling(SkCanvas* canvas,
68                                            float image_scale) {
69   return new Canvas(canvas, image_scale);
70 }
71
72 void Canvas::RecreateBackingCanvas(const Size& size,
73                                    float image_scale,
74                                    bool is_opaque) {
75   image_scale_ = image_scale;
76   Size pixel_size = ToFlooredSize(ScaleSize(size, image_scale));
77   owned_canvas_ = skia::AdoptRef(skia::CreatePlatformCanvas(pixel_size.width(),
78                                                             pixel_size.height(),
79                                                             is_opaque));
80   canvas_ = owned_canvas_.get();
81   SkScalar scale_scalar = SkFloatToScalar(image_scale);
82   canvas_->scale(scale_scalar, scale_scalar);
83 }
84
85 // static
86 void Canvas::SizeStringInt(const base::string16& text,
87                            const FontList& font_list,
88                            int* width,
89                            int* height,
90                            int line_height,
91                            int flags) {
92   float fractional_width = *width;
93   float factional_height = *height;
94   SizeStringFloat(text, font_list, &fractional_width,
95                   &factional_height, line_height, flags);
96   *width = std::ceil(fractional_width);
97   *height = std::ceil(factional_height);
98 }
99
100 // static
101 int Canvas::GetStringWidth(const base::string16& text,
102                            const FontList& font_list) {
103   int width = 0, height = 0;
104   SizeStringInt(text, font_list, &width, &height, 0, NO_ELLIPSIS);
105   return width;
106 }
107
108 // static
109 float Canvas::GetStringWidthF(const base::string16& text,
110                               const FontList& font_list) {
111   float width = 0, height = 0;
112   SizeStringFloat(text, font_list, &width, &height, 0, NO_ELLIPSIS);
113   return width;
114 }
115
116 // static
117 int Canvas::DefaultCanvasTextAlignment() {
118   return base::i18n::IsRTL() ? TEXT_ALIGN_RIGHT : TEXT_ALIGN_LEFT;
119 }
120
121 ImageSkiaRep Canvas::ExtractImageRep() const {
122   // Make a bitmap to return, and a canvas to draw into it. We don't just want
123   // to call extractSubset or the copy constructor, since we want an actual copy
124   // of the bitmap.
125   const SkISize size = canvas_->getDeviceSize();
126   SkBitmap result;
127   result.allocN32Pixels(size.width(), size.height());
128
129   canvas_->readPixels(&result, 0, 0);
130   return ImageSkiaRep(result, image_scale_);
131 }
132
133 void Canvas::DrawDashedRect(const Rect& rect, SkColor color) {
134   // Create a 2D bitmap containing alternating on/off pixels - we do this
135   // so that you never get two pixels of the same color around the edges
136   // of the focus rect (this may mean that opposing edges of the rect may
137   // have a dot pattern out of phase to each other).
138   static SkColor last_color;
139   static SkBitmap* dots = NULL;
140   if (!dots || last_color != color) {
141     int col_pixels = 32;
142     int row_pixels = 32;
143
144     delete dots;
145     last_color = color;
146     dots = new SkBitmap;
147     dots->allocN32Pixels(col_pixels, row_pixels);
148     dots->eraseARGB(0, 0, 0, 0);
149
150     uint32_t* dot = dots->getAddr32(0, 0);
151     for (int i = 0; i < row_pixels; i++) {
152       for (int u = 0; u < col_pixels; u++) {
153         if ((u % 2 + i % 2) % 2 != 0) {
154           dot[i * row_pixels + u] = color;
155         }
156       }
157     }
158   }
159
160   // Make a shader for the bitmap with an origin of the box we'll draw. This
161   // shader is refcounted and will have an initial refcount of 1.
162   skia::RefPtr<SkShader> shader = skia::AdoptRef(
163       SkShader::CreateBitmapShader(
164           *dots, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
165   // Assign the shader to the paint & release our reference. The paint will
166   // now own the shader and the shader will be destroyed when the paint goes
167   // out of scope.
168   SkPaint paint;
169   paint.setShader(shader.get());
170
171   DrawRect(Rect(rect.x(), rect.y(), rect.width(), 1), paint);
172   DrawRect(Rect(rect.x(), rect.y() + rect.height() - 1, rect.width(), 1),
173            paint);
174   DrawRect(Rect(rect.x(), rect.y(), 1, rect.height()), paint);
175   DrawRect(Rect(rect.x() + rect.width() - 1, rect.y(), 1, rect.height()),
176            paint);
177 }
178
179 void Canvas::Save() {
180   canvas_->save();
181 }
182
183 void Canvas::SaveLayerAlpha(uint8 alpha) {
184   canvas_->saveLayerAlpha(NULL, alpha);
185 }
186
187
188 void Canvas::SaveLayerAlpha(uint8 alpha, const Rect& layer_bounds) {
189   SkRect bounds(RectToSkRect(layer_bounds));
190   canvas_->saveLayerAlpha(&bounds, alpha);
191 }
192
193 void Canvas::Restore() {
194   canvas_->restore();
195 }
196
197 void Canvas::ClipRect(const Rect& rect) {
198   canvas_->clipRect(RectToSkRect(rect));
199 }
200
201 void Canvas::ClipPath(const SkPath& path) {
202   canvas_->clipPath(path);
203 }
204
205 bool Canvas::IsClipEmpty() const {
206   return canvas_->isClipEmpty();
207 }
208
209 bool Canvas::GetClipBounds(Rect* bounds) {
210   SkRect out;
211   bool has_non_empty_clip = canvas_->getClipBounds(&out);
212   bounds->SetRect(out.left(), out.top(), out.width(), out.height());
213   return has_non_empty_clip;
214 }
215
216 void Canvas::Translate(const Vector2d& offset) {
217   canvas_->translate(SkIntToScalar(offset.x()), SkIntToScalar(offset.y()));
218 }
219
220 void Canvas::Scale(int x_scale, int y_scale) {
221   canvas_->scale(SkIntToScalar(x_scale), SkIntToScalar(y_scale));
222 }
223
224 void Canvas::DrawColor(SkColor color) {
225   DrawColor(color, SkXfermode::kSrcOver_Mode);
226 }
227
228 void Canvas::DrawColor(SkColor color, SkXfermode::Mode mode) {
229   canvas_->drawColor(color, mode);
230 }
231
232 void Canvas::FillRect(const Rect& rect, SkColor color) {
233   FillRect(rect, color, SkXfermode::kSrcOver_Mode);
234 }
235
236 void Canvas::FillRect(const Rect& rect,
237                       SkColor color,
238                       SkXfermode::Mode mode) {
239   SkPaint paint;
240   paint.setColor(color);
241   paint.setStyle(SkPaint::kFill_Style);
242   paint.setXfermodeMode(mode);
243   DrawRect(rect, paint);
244 }
245
246 void Canvas::DrawRect(const Rect& rect, SkColor color) {
247   DrawRect(rect, color, SkXfermode::kSrcOver_Mode);
248 }
249
250 void Canvas::DrawRect(const Rect& rect,
251                       SkColor color,
252                       SkXfermode::Mode mode) {
253   SkPaint paint;
254   paint.setColor(color);
255   paint.setStyle(SkPaint::kStroke_Style);
256   // Set a stroke width of 0, which will put us down the stroke rect path.  If
257   // we set a stroke width of 1, for example, this will internally create a
258   // path and fill it, which causes problems near the edge of the canvas.
259   paint.setStrokeWidth(SkIntToScalar(0));
260   paint.setXfermodeMode(mode);
261
262   DrawRect(rect, paint);
263 }
264
265 void Canvas::DrawRect(const Rect& rect, const SkPaint& paint) {
266   canvas_->drawIRect(RectToSkIRect(rect), paint);
267 }
268
269 void Canvas::DrawPoint(const Point& p1, const SkPaint& paint) {
270   canvas_->drawPoint(SkIntToScalar(p1.x()), SkIntToScalar(p1.y()), paint);
271 }
272
273 void Canvas::DrawLine(const Point& p1, const Point& p2, SkColor color) {
274   SkPaint paint;
275   paint.setColor(color);
276   paint.setStrokeWidth(SkIntToScalar(1));
277   DrawLine(p1, p2, paint);
278 }
279
280 void Canvas::DrawLine(const Point& p1, const Point& p2, const SkPaint& paint) {
281   canvas_->drawLine(SkIntToScalar(p1.x()), SkIntToScalar(p1.y()),
282                     SkIntToScalar(p2.x()), SkIntToScalar(p2.y()), paint);
283 }
284
285 void Canvas::DrawCircle(const Point& center_point,
286                         int radius,
287                         const SkPaint& paint) {
288   canvas_->drawCircle(SkIntToScalar(center_point.x()),
289       SkIntToScalar(center_point.y()), SkIntToScalar(radius), paint);
290 }
291
292 void Canvas::DrawRoundRect(const Rect& rect,
293                            int radius,
294                            const SkPaint& paint) {
295   canvas_->drawRoundRect(RectToSkRect(rect), SkIntToScalar(radius),
296                          SkIntToScalar(radius), paint);
297 }
298
299 void Canvas::DrawPath(const SkPath& path, const SkPaint& paint) {
300   canvas_->drawPath(path, paint);
301 }
302
303 void Canvas::DrawFocusRect(const Rect& rect) {
304   DrawDashedRect(rect, SK_ColorGRAY);
305 }
306
307 void Canvas::DrawSolidFocusRect(const Rect& rect, SkColor color) {
308   SkPaint paint;
309   paint.setColor(color);
310   paint.setStrokeWidth(SkIntToScalar(1));
311   // Note: We cannot use DrawRect since it would create a path and fill it which
312   // would cause problems near the edge of the canvas.
313   int x1 = std::min(rect.x(), rect.right());
314   int x2 = std::max(rect.x(), rect.right());
315   int y1 = std::min(rect.y(), rect.bottom());
316   int y2 = std::max(rect.y(), rect.bottom());
317   DrawLine(Point(x1, y1), Point(x2, y1), paint);
318   DrawLine(Point(x1, y2), Point(x2, y2), paint);
319   DrawLine(Point(x1, y1), Point(x1, y2), paint);
320   DrawLine(Point(x2, y1), Point(x2, y2 + 1), paint);
321 }
322
323 void Canvas::DrawImageInt(const ImageSkia& image, int x, int y) {
324   SkPaint paint;
325   DrawImageInt(image, x, y, paint);
326 }
327
328 void Canvas::DrawImageInt(const ImageSkia& image, int x, int y, uint8 a) {
329   SkPaint paint;
330   paint.setAlpha(a);
331   DrawImageInt(image, x, y, paint);
332 }
333
334 void Canvas::DrawImageInt(const ImageSkia& image,
335                           int x,
336                           int y,
337                           const SkPaint& paint) {
338   const ImageSkiaRep& image_rep = GetImageRepToPaint(image);
339   if (image_rep.is_null())
340     return;
341   const SkBitmap& bitmap = image_rep.sk_bitmap();
342   float bitmap_scale = image_rep.scale();
343
344   canvas_->save();
345   canvas_->scale(SkFloatToScalar(1.0f / bitmap_scale),
346                  SkFloatToScalar(1.0f / bitmap_scale));
347   canvas_->drawBitmap(bitmap,
348                       SkFloatToScalar(x * bitmap_scale),
349                       SkFloatToScalar(y * bitmap_scale),
350                       &paint);
351   canvas_->restore();
352 }
353
354 void Canvas::DrawImageInt(const ImageSkia& image,
355                           int src_x,
356                           int src_y,
357                           int src_w,
358                           int src_h,
359                           int dest_x,
360                           int dest_y,
361                           int dest_w,
362                           int dest_h,
363                           bool filter) {
364   SkPaint p;
365   DrawImageInt(image, src_x, src_y, src_w, src_h, dest_x, dest_y,
366                dest_w, dest_h, filter, p);
367 }
368
369 void Canvas::DrawImageInt(const ImageSkia& image,
370                           int src_x,
371                           int src_y,
372                           int src_w,
373                           int src_h,
374                           int dest_x,
375                           int dest_y,
376                           int dest_w,
377                           int dest_h,
378                           bool filter,
379                           const SkPaint& paint) {
380   DrawImageIntHelper(image, src_x, src_y, src_w, src_h, dest_x, dest_y, dest_w,
381                      dest_h, filter, paint, image_scale_, false);
382 }
383
384 void Canvas::DrawImageIntInPixel(const ImageSkia& image,
385                                  int src_x,
386                                  int src_y,
387                                  int src_w,
388                                  int src_h,
389                                  int dest_x,
390                                  int dest_y,
391                                  int dest_w,
392                                  int dest_h,
393                                  bool filter,
394                                  const SkPaint& paint) {
395   // Logic as below:-
396   // 1. Translate the destination rectangle using the current translation
397   //    values from the SkCanvas matrix stack.
398   // 2. Save the current state of the canvas.
399   // 3. Reset the scales and the translation values in the SkCanvas matrix
400   //    stack top.
401   // 4. Set the scale in gfx::Canvas instance to 1.0, 1.0.
402   // 5. Draw the image.
403   // 6. Restore the state of the canvas and the SkCanvas matrix stack.
404   SkMatrix matrix = canvas_->getTotalMatrix();
405
406   SkRect destination_rect;
407   destination_rect.set(SkIntToScalar(dest_x),
408                        SkIntToScalar(dest_y),
409                        SkIntToScalar(dest_x + dest_w),
410                        SkIntToScalar(dest_y + dest_h));
411   matrix.setScaleX(1.0f);
412   matrix.setScaleY(1.0f);
413   matrix.mapRect(&destination_rect, destination_rect);
414
415   Save();
416
417   // The destination is now in pixel values. No need for further translation.
418   matrix.setTranslate(0, 0);
419   canvas_->setMatrix(matrix);
420
421   DrawImageIntHelper(image,
422                      src_x,
423                      src_y,
424                      src_w,
425                      src_h,
426                      SkScalarRoundToInt(destination_rect.x()),
427                      SkScalarRoundToInt(destination_rect.y()),
428                      SkScalarRoundToInt(destination_rect.width()),
429                      SkScalarRoundToInt(destination_rect.height()),
430                      filter,
431                      paint,
432                      image_scale_,
433                      true);
434
435   // Restore the state of the canvas.
436   Restore();
437 }
438
439 void Canvas::DrawImageInPath(const ImageSkia& image,
440                              int x,
441                              int y,
442                              const SkPath& path,
443                              const SkPaint& paint) {
444   const ImageSkiaRep& image_rep = GetImageRepToPaint(image);
445   if (image_rep.is_null())
446     return;
447
448   SkMatrix matrix;
449   matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
450   skia::RefPtr<SkShader> shader = CreateImageRepShader(
451       image_rep,
452       SkShader::kRepeat_TileMode,
453       matrix);
454
455   SkPaint p(paint);
456   p.setShader(shader.get());
457   canvas_->drawPath(path, p);
458 }
459
460 void Canvas::DrawStringRect(const base::string16& text,
461                             const FontList& font_list,
462                             SkColor color,
463                             const Rect& display_rect) {
464   DrawStringRectWithFlags(text, font_list, color, display_rect,
465                           DefaultCanvasTextAlignment());
466 }
467
468 void Canvas::DrawStringRectWithFlags(const base::string16& text,
469                                      const FontList& font_list,
470                                      SkColor color,
471                                      const Rect& display_rect,
472                                      int flags) {
473   DrawStringRectWithShadows(text, font_list, color, display_rect, 0, flags,
474                             ShadowValues());
475 }
476
477 void Canvas::TileImageInt(const ImageSkia& image,
478                           int x,
479                           int y,
480                           int w,
481                           int h) {
482   TileImageInt(image, 0, 0, x, y, w, h);
483 }
484
485 void Canvas::TileImageInt(const ImageSkia& image,
486                           int src_x,
487                           int src_y,
488                           int dest_x,
489                           int dest_y,
490                           int w,
491                           int h) {
492   TileImageInt(image, src_x, src_y, 1.0f, 1.0f, dest_x, dest_y, w, h);
493 }
494
495 void Canvas::TileImageInt(const ImageSkia& image,
496                           int src_x,
497                           int src_y,
498                           float tile_scale_x,
499                           float tile_scale_y,
500                           int dest_x,
501                           int dest_y,
502                           int w,
503                           int h) {
504   if (!IntersectsClipRectInt(dest_x, dest_y, w, h))
505     return;
506
507   const ImageSkiaRep& image_rep = GetImageRepToPaint(
508       image, image_scale_, tile_scale_x, tile_scale_y);
509   if (image_rep.is_null())
510     return;
511
512   SkMatrix shader_scale;
513   shader_scale.setScale(SkFloatToScalar(tile_scale_x),
514                         SkFloatToScalar(tile_scale_y));
515   shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y));
516   shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y));
517
518   skia::RefPtr<SkShader> shader = CreateImageRepShader(
519       image_rep,
520       SkShader::kRepeat_TileMode,
521       shader_scale);
522
523   SkPaint paint;
524   paint.setShader(shader.get());
525   paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
526
527   SkRect dest_rect = { SkIntToScalar(dest_x),
528                        SkIntToScalar(dest_y),
529                        SkIntToScalar(dest_x + w),
530                        SkIntToScalar(dest_y + h) };
531   canvas_->drawRect(dest_rect, paint);
532 }
533
534 NativeDrawingContext Canvas::BeginPlatformPaint() {
535   return skia::BeginPlatformPaint(canvas_);
536 }
537
538 void Canvas::EndPlatformPaint() {
539   skia::EndPlatformPaint(canvas_);
540 }
541
542 void Canvas::Transform(const gfx::Transform& transform) {
543   canvas_->concat(transform.matrix());
544 }
545
546 Canvas::Canvas(SkCanvas* canvas, float image_scale)
547     : image_scale_(image_scale),
548       owned_canvas_(),
549       canvas_(canvas) {
550   DCHECK(canvas);
551 }
552
553 bool Canvas::IntersectsClipRectInt(int x, int y, int w, int h) {
554   SkRect clip;
555   return canvas_->getClipBounds(&clip) &&
556       clip.intersect(SkIntToScalar(x), SkIntToScalar(y), SkIntToScalar(x + w),
557                      SkIntToScalar(y + h));
558 }
559
560 bool Canvas::IntersectsClipRect(const Rect& rect) {
561   return IntersectsClipRectInt(rect.x(), rect.y(),
562                                rect.width(), rect.height());
563 }
564
565 const ImageSkiaRep& Canvas::GetImageRepToPaint(const ImageSkia& image) const {
566   return GetImageRepToPaint(image, image_scale_, 1.0f, 1.0f);
567 }
568
569 const ImageSkiaRep& Canvas::GetImageRepToPaint(
570     const ImageSkia& image,
571     float image_scale,
572     float user_additional_scale_x,
573     float user_additional_scale_y) const {
574   const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale);
575
576   if (!image_rep.is_null()) {
577     SkMatrix m = canvas_->getTotalMatrix();
578     float scale_x = SkScalarToFloat(SkScalarAbs(m.getScaleX())) *
579         user_additional_scale_x;
580     float scale_y = SkScalarToFloat(SkScalarAbs(m.getScaleY())) *
581         user_additional_scale_y;
582
583     float bitmap_scale = image_rep.scale();
584     if (scale_x < bitmap_scale || scale_y < bitmap_scale)
585       const_cast<SkBitmap&>(image_rep.sk_bitmap()).buildMipMap();
586   }
587
588   return image_rep;
589 }
590
591 void Canvas::DrawImageIntHelper(const ImageSkia& image,
592                                 int src_x,
593                                 int src_y,
594                                 int src_w,
595                                 int src_h,
596                                 int dest_x,
597                                 int dest_y,
598                                 int dest_w,
599                                 int dest_h,
600                                 bool filter,
601                                 const SkPaint& paint,
602                                 float image_scale,
603                                 bool pixel) {
604   DLOG_ASSERT(src_x + src_w < std::numeric_limits<int16_t>::max() &&
605               src_y + src_h < std::numeric_limits<int16_t>::max());
606   if (src_w <= 0 || src_h <= 0) {
607     NOTREACHED() << "Attempting to draw bitmap from an empty rect!";
608     return;
609   }
610
611   if (!IntersectsClipRectInt(dest_x, dest_y, dest_w, dest_h))
612     return;
613
614   float user_scale_x = static_cast<float>(dest_w) / src_w;
615   float user_scale_y = static_cast<float>(dest_h) / src_h;
616
617   const ImageSkiaRep& image_rep = GetImageRepToPaint(image,
618       image_scale, user_scale_x, user_scale_y);
619   if (image_rep.is_null())
620     return;
621
622   SkRect dest_rect = { SkIntToScalar(dest_x),
623                        SkIntToScalar(dest_y),
624                        SkIntToScalar(dest_x + dest_w),
625                        SkIntToScalar(dest_y + dest_h) };
626
627   if (src_w == dest_w && src_h == dest_h &&
628       user_scale_x == 1.0f && user_scale_y == 1.0f &&
629       image_rep.scale() == 1.0f && !pixel) {
630     // Workaround for apparent bug in Skia that causes image to occasionally
631     // shift.
632     SkIRect src_rect = { src_x, src_y, src_x + src_w, src_y + src_h };
633     const SkBitmap& bitmap = image_rep.sk_bitmap();
634     canvas_->drawBitmapRect(bitmap, &src_rect, dest_rect, &paint);
635     return;
636   }
637
638   // Make a bitmap shader that contains the bitmap we want to draw. This is
639   // basically what SkCanvas.drawBitmap does internally, but it gives us
640   // more control over quality and will use the mipmap in the source image if
641   // it has one, whereas drawBitmap won't.
642   SkMatrix shader_scale;
643   shader_scale.setScale(SkFloatToScalar(user_scale_x),
644                         SkFloatToScalar(user_scale_y));
645   shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y));
646   shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y));
647
648   skia::RefPtr<SkShader> shader = CreateImageRepShaderForScale(
649       image_rep,
650       SkShader::kRepeat_TileMode,
651       shader_scale,
652       pixel ? 1.0f : image_rep.scale());
653
654   // Set up our paint to use the shader & release our reference (now just owned
655   // by the paint).
656   SkPaint p(paint);
657   p.setFilterBitmap(filter);
658   p.setShader(shader.get());
659
660   // The rect will be filled by the bitmap.
661   canvas_->drawRect(dest_rect, p);
662 }
663
664 }  // namespace gfx