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