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