Home | History | Annotate | Download | only in gfx
      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 void Canvas::SaveLayerAlpha(uint8 alpha, const Rect& layer_bounds) {
    188   SkRect bounds(RectToSkRect(layer_bounds));
    189   canvas_->saveLayerAlpha(&bounds, alpha);
    190 }
    191 
    192 void Canvas::Restore() {
    193   canvas_->restore();
    194 }
    195 
    196 void Canvas::ClipRect(const Rect& rect) {
    197   canvas_->clipRect(RectToSkRect(rect));
    198 }
    199 
    200 void Canvas::ClipPath(const SkPath& path, bool do_anti_alias) {
    201   canvas_->clipPath(path, SkRegion::kIntersect_Op, do_anti_alias);
    202 }
    203 
    204 bool Canvas::IsClipEmpty() const {
    205   return canvas_->isClipEmpty();
    206 }
    207 
    208 bool Canvas::GetClipBounds(Rect* bounds) {
    209   SkRect out;
    210   bool has_non_empty_clip = canvas_->getClipBounds(&out);
    211   bounds->SetRect(out.left(), out.top(), out.width(), out.height());
    212   return has_non_empty_clip;
    213 }
    214 
    215 void Canvas::Translate(const Vector2d& offset) {
    216   canvas_->translate(SkIntToScalar(offset.x()), SkIntToScalar(offset.y()));
    217 }
    218 
    219 void Canvas::Scale(int x_scale, int y_scale) {
    220   canvas_->scale(SkIntToScalar(x_scale), SkIntToScalar(y_scale));
    221 }
    222 
    223 void Canvas::DrawColor(SkColor color) {
    224   DrawColor(color, SkXfermode::kSrcOver_Mode);
    225 }
    226 
    227 void Canvas::DrawColor(SkColor color, SkXfermode::Mode mode) {
    228   canvas_->drawColor(color, mode);
    229 }
    230 
    231 void Canvas::FillRect(const Rect& rect, SkColor color) {
    232   FillRect(rect, color, SkXfermode::kSrcOver_Mode);
    233 }
    234 
    235 void Canvas::FillRect(const Rect& rect,
    236                       SkColor color,
    237                       SkXfermode::Mode mode) {
    238   SkPaint paint;
    239   paint.setColor(color);
    240   paint.setStyle(SkPaint::kFill_Style);
    241   paint.setXfermodeMode(mode);
    242   DrawRect(rect, paint);
    243 }
    244 
    245 void Canvas::DrawRect(const Rect& rect, SkColor color) {
    246   DrawRect(rect, color, SkXfermode::kSrcOver_Mode);
    247 }
    248 
    249 void Canvas::DrawRect(const Rect& rect,
    250                       SkColor color,
    251                       SkXfermode::Mode mode) {
    252   SkPaint paint;
    253   paint.setColor(color);
    254   paint.setStyle(SkPaint::kStroke_Style);
    255   // Set a stroke width of 0, which will put us down the stroke rect path.  If
    256   // we set a stroke width of 1, for example, this will internally create a
    257   // path and fill it, which causes problems near the edge of the canvas.
    258   paint.setStrokeWidth(SkIntToScalar(0));
    259   paint.setXfermodeMode(mode);
    260 
    261   DrawRect(rect, paint);
    262 }
    263 
    264 void Canvas::DrawRect(const Rect& rect, const SkPaint& paint) {
    265   canvas_->drawIRect(RectToSkIRect(rect), paint);
    266 }
    267 
    268 void Canvas::DrawPoint(const Point& p1, const SkPaint& paint) {
    269   canvas_->drawPoint(SkIntToScalar(p1.x()), SkIntToScalar(p1.y()), paint);
    270 }
    271 
    272 void Canvas::DrawLine(const Point& p1, const Point& p2, SkColor color) {
    273   SkPaint paint;
    274   paint.setColor(color);
    275   paint.setStrokeWidth(SkIntToScalar(1));
    276   DrawLine(p1, p2, paint);
    277 }
    278 
    279 void Canvas::DrawLine(const Point& p1, const Point& p2, const SkPaint& paint) {
    280   canvas_->drawLine(SkIntToScalar(p1.x()), SkIntToScalar(p1.y()),
    281                     SkIntToScalar(p2.x()), SkIntToScalar(p2.y()), paint);
    282 }
    283 
    284 void Canvas::DrawCircle(const Point& center_point,
    285                         int radius,
    286                         const SkPaint& paint) {
    287   canvas_->drawCircle(SkIntToScalar(center_point.x()),
    288       SkIntToScalar(center_point.y()), SkIntToScalar(radius), paint);
    289 }
    290 
    291 void Canvas::DrawRoundRect(const Rect& rect,
    292                            int radius,
    293                            const SkPaint& paint) {
    294   canvas_->drawRoundRect(RectToSkRect(rect), SkIntToScalar(radius),
    295                          SkIntToScalar(radius), paint);
    296 }
    297 
    298 void Canvas::DrawPath(const SkPath& path, const SkPaint& paint) {
    299   canvas_->drawPath(path, paint);
    300 }
    301 
    302 void Canvas::DrawFocusRect(const Rect& rect) {
    303   DrawDashedRect(rect, SK_ColorGRAY);
    304 }
    305 
    306 void Canvas::DrawSolidFocusRect(const Rect& rect, SkColor color) {
    307   SkPaint paint;
    308   paint.setColor(color);
    309   paint.setStrokeWidth(SkIntToScalar(1));
    310   // Note: We cannot use DrawRect since it would create a path and fill it which
    311   // would cause problems near the edge of the canvas.
    312   int x1 = std::min(rect.x(), rect.right());
    313   int x2 = std::max(rect.x(), rect.right());
    314   int y1 = std::min(rect.y(), rect.bottom());
    315   int y2 = std::max(rect.y(), rect.bottom());
    316   DrawLine(Point(x1, y1), Point(x2, y1), paint);
    317   DrawLine(Point(x1, y2), Point(x2, y2), paint);
    318   DrawLine(Point(x1, y1), Point(x1, y2), paint);
    319   DrawLine(Point(x2, y1), Point(x2, y2 + 1), paint);
    320 }
    321 
    322 void Canvas::DrawImageInt(const ImageSkia& image, int x, int y) {
    323   SkPaint paint;
    324   DrawImageInt(image, x, y, paint);
    325 }
    326 
    327 void Canvas::DrawImageInt(const ImageSkia& image, int x, int y, uint8 a) {
    328   SkPaint paint;
    329   paint.setAlpha(a);
    330   DrawImageInt(image, x, y, paint);
    331 }
    332 
    333 void Canvas::DrawImageInt(const ImageSkia& image,
    334                           int x,
    335                           int y,
    336                           const SkPaint& paint) {
    337   const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_);
    338   if (image_rep.is_null())
    339     return;
    340   const SkBitmap& bitmap = image_rep.sk_bitmap();
    341   float bitmap_scale = image_rep.scale();
    342 
    343   canvas_->save();
    344   canvas_->scale(SkFloatToScalar(1.0f / bitmap_scale),
    345                  SkFloatToScalar(1.0f / bitmap_scale));
    346   canvas_->drawBitmap(bitmap,
    347                       SkFloatToScalar(x * bitmap_scale),
    348                       SkFloatToScalar(y * bitmap_scale),
    349                       &paint);
    350   canvas_->restore();
    351 }
    352 
    353 void Canvas::DrawImageInt(const ImageSkia& image,
    354                           int src_x,
    355                           int src_y,
    356                           int src_w,
    357                           int src_h,
    358                           int dest_x,
    359                           int dest_y,
    360                           int dest_w,
    361                           int dest_h,
    362                           bool filter) {
    363   SkPaint p;
    364   DrawImageInt(image, src_x, src_y, src_w, src_h, dest_x, dest_y,
    365                dest_w, dest_h, filter, p);
    366 }
    367 
    368 void Canvas::DrawImageInt(const ImageSkia& image,
    369                           int src_x,
    370                           int src_y,
    371                           int src_w,
    372                           int src_h,
    373                           int dest_x,
    374                           int dest_y,
    375                           int dest_w,
    376                           int dest_h,
    377                           bool filter,
    378                           const SkPaint& paint) {
    379   DrawImageIntHelper(image, src_x, src_y, src_w, src_h, dest_x, dest_y, dest_w,
    380                      dest_h, filter, paint, image_scale_, false);
    381 }
    382 
    383 void Canvas::DrawImageIntInPixel(const ImageSkia& image,
    384                                  int src_x,
    385                                  int src_y,
    386                                  int src_w,
    387                                  int src_h,
    388                                  int dest_x,
    389                                  int dest_y,
    390                                  int dest_w,
    391                                  int dest_h,
    392                                  bool filter,
    393                                  const SkPaint& paint) {
    394   // All values passed into this function are in pixels, i.e. no scaling needs
    395   // be done.
    396   // Logic as below:-
    397   // 1. Get the matrix transform from the canvas.
    398   // 2. Set the scale in the matrix to 1.0 while honoring the direction of the
    399   //    the scale (x/y). Example RTL layouts.
    400   // 3. Round off the X and Y translation components in the matrix. This is to
    401   //    reduce floating point errors during rect transformation. This is needed
    402   //    for fractional scale factors like 1.25/1.5, etc.
    403   // 4. Save the current state of the canvas.
    404   // 5. Set the modified matrix in the canvas. This ensures that no scaling
    405   //    will be done for draw operations on the canvas.
    406   // 6. Draw the image.
    407   // 7. Restore the state of the canvas and the SkCanvas matrix stack.
    408   SkMatrix matrix = canvas_->getTotalMatrix();
    409 
    410   // Ensure that the direction of the x and y scales is preserved. This is
    411   // important for RTL layouts.
    412   matrix.getScaleX() > 0 ? matrix.setScaleX(1.0f) : matrix.setScaleX(-1.0f);
    413   matrix.getScaleY() > 0 ? matrix.setScaleY(1.0f) : matrix.setScaleY(-1.0f);
    414 
    415   matrix.setTranslateX(SkScalarRoundToInt(matrix.getTranslateX()));
    416   matrix.setTranslateY(SkScalarRoundToInt(matrix.getTranslateY()));
    417 
    418   Save();
    419 
    420   canvas_->setMatrix(matrix);
    421 
    422   DrawImageIntHelper(image,
    423                      src_x,
    424                      src_y,
    425                      src_w,
    426                      src_h,
    427                      dest_x,
    428                      dest_y,
    429                      dest_w,
    430                      dest_h,
    431                      filter,
    432                      paint,
    433                      image_scale_,
    434                      true);
    435 
    436   // Restore the state of the canvas.
    437   Restore();
    438 }
    439 
    440 void Canvas::DrawImageInPath(const ImageSkia& image,
    441                              int x,
    442                              int y,
    443                              const SkPath& path,
    444                              const SkPaint& paint) {
    445   const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_);
    446   if (image_rep.is_null())
    447     return;
    448 
    449   SkMatrix matrix;
    450   matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
    451   skia::RefPtr<SkShader> shader = CreateImageRepShader(
    452       image_rep,
    453       SkShader::kRepeat_TileMode,
    454       matrix);
    455 
    456   SkPaint p(paint);
    457   p.setShader(shader.get());
    458   canvas_->drawPath(path, p);
    459 }
    460 
    461 void Canvas::DrawStringRect(const base::string16& text,
    462                             const FontList& font_list,
    463                             SkColor color,
    464                             const Rect& display_rect) {
    465   DrawStringRectWithFlags(text, font_list, color, display_rect,
    466                           DefaultCanvasTextAlignment());
    467 }
    468 
    469 void Canvas::DrawStringRectWithFlags(const base::string16& text,
    470                                      const FontList& font_list,
    471                                      SkColor color,
    472                                      const Rect& display_rect,
    473                                      int flags) {
    474   DrawStringRectWithShadows(text, font_list, color, display_rect, 0, flags,
    475                             ShadowValues());
    476 }
    477 
    478 void Canvas::TileImageInt(const ImageSkia& image,
    479                           int x,
    480                           int y,
    481                           int w,
    482                           int h) {
    483   TileImageInt(image, 0, 0, x, y, w, h);
    484 }
    485 
    486 void Canvas::TileImageInt(const ImageSkia& image,
    487                           int src_x,
    488                           int src_y,
    489                           int dest_x,
    490                           int dest_y,
    491                           int w,
    492                           int h) {
    493   TileImageInt(image, src_x, src_y, 1.0f, 1.0f, dest_x, dest_y, w, h);
    494 }
    495 
    496 void Canvas::TileImageInt(const ImageSkia& image,
    497                           int src_x,
    498                           int src_y,
    499                           float tile_scale_x,
    500                           float tile_scale_y,
    501                           int dest_x,
    502                           int dest_y,
    503                           int w,
    504                           int h) {
    505   if (!IntersectsClipRectInt(dest_x, dest_y, w, h))
    506     return;
    507 
    508   const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_);
    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 void Canvas::DrawImageIntHelper(const ImageSkia& image,
    566                                 int src_x,
    567                                 int src_y,
    568                                 int src_w,
    569                                 int src_h,
    570                                 int dest_x,
    571                                 int dest_y,
    572                                 int dest_w,
    573                                 int dest_h,
    574                                 bool filter,
    575                                 const SkPaint& paint,
    576                                 float image_scale,
    577                                 bool pixel) {
    578   DLOG_ASSERT(src_x + src_w < std::numeric_limits<int16_t>::max() &&
    579               src_y + src_h < std::numeric_limits<int16_t>::max());
    580   if (src_w <= 0 || src_h <= 0) {
    581     NOTREACHED() << "Attempting to draw bitmap from an empty rect!";
    582     return;
    583   }
    584 
    585   if (!IntersectsClipRectInt(dest_x, dest_y, dest_w, dest_h))
    586     return;
    587 
    588   float user_scale_x = static_cast<float>(dest_w) / src_w;
    589   float user_scale_y = static_cast<float>(dest_h) / src_h;
    590 
    591   const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale);
    592   if (image_rep.is_null())
    593     return;
    594 
    595   SkRect dest_rect = { SkIntToScalar(dest_x),
    596                        SkIntToScalar(dest_y),
    597                        SkIntToScalar(dest_x + dest_w),
    598                        SkIntToScalar(dest_y + dest_h) };
    599 
    600   if (src_w == dest_w && src_h == dest_h &&
    601       user_scale_x == 1.0f && user_scale_y == 1.0f &&
    602       image_rep.scale() == 1.0f && !pixel) {
    603     // Workaround for apparent bug in Skia that causes image to occasionally
    604     // shift.
    605     SkIRect src_rect = { src_x, src_y, src_x + src_w, src_y + src_h };
    606     const SkBitmap& bitmap = image_rep.sk_bitmap();
    607     canvas_->drawBitmapRect(bitmap, &src_rect, dest_rect, &paint);
    608     return;
    609   }
    610 
    611   // Make a bitmap shader that contains the bitmap we want to draw. This is
    612   // basically what SkCanvas.drawBitmap does internally, but it gives us
    613   // more control over quality and will use the mipmap in the source image if
    614   // it has one, whereas drawBitmap won't.
    615   SkMatrix shader_scale;
    616   shader_scale.setScale(SkFloatToScalar(user_scale_x),
    617                         SkFloatToScalar(user_scale_y));
    618   shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y));
    619   shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y));
    620 
    621   skia::RefPtr<SkShader> shader = CreateImageRepShaderForScale(
    622       image_rep,
    623       SkShader::kRepeat_TileMode,
    624       shader_scale,
    625       pixel ? 1.0f : image_rep.scale());
    626 
    627   // Set up our paint to use the shader & release our reference (now just owned
    628   // by the paint).
    629   SkPaint p(paint);
    630   p.setFilterLevel(filter ? SkPaint::kLow_FilterLevel
    631                           : SkPaint::kNone_FilterLevel);
    632   p.setShader(shader.get());
    633 
    634   // The rect will be filled by the bitmap.
    635   canvas_->drawRect(dest_rect, p);
    636 }
    637 
    638 }  // namespace gfx
    639