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