OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/gfx/canvas.h" | 5 #include "ui/gfx/canvas.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 #include <limits> | 8 #include <limits> |
9 | 9 |
10 #include "base/i18n/rtl.h" | 10 #include "base/i18n/rtl.h" |
(...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
370 int src_x, | 370 int src_x, |
371 int src_y, | 371 int src_y, |
372 int src_w, | 372 int src_w, |
373 int src_h, | 373 int src_h, |
374 int dest_x, | 374 int dest_x, |
375 int dest_y, | 375 int dest_y, |
376 int dest_w, | 376 int dest_w, |
377 int dest_h, | 377 int dest_h, |
378 bool filter, | 378 bool filter, |
379 const SkPaint& paint) { | 379 const SkPaint& paint) { |
380 DLOG_ASSERT(src_x + src_w < std::numeric_limits<int16_t>::max() && | 380 DrawImageIntHelper(image, src_x, src_y, src_w, src_h, dest_x, dest_y, dest_w, |
381 src_y + src_h < std::numeric_limits<int16_t>::max()); | 381 dest_h, filter, paint, image_scale_, false); |
382 if (src_w <= 0 || src_h <= 0) { | 382 } |
383 NOTREACHED() << "Attempting to draw bitmap from an empty rect!"; | |
384 return; | |
385 } | |
386 | 383 |
387 if (!IntersectsClipRectInt(dest_x, dest_y, dest_w, dest_h)) | 384 void Canvas::DrawImageIntInPixel(const ImageSkia& image, |
388 return; | 385 int src_x, |
386 int src_y, | |
387 int src_w, | |
388 int src_h, | |
389 int dest_x, | |
390 int dest_y, | |
391 int dest_w, | |
392 int dest_h, | |
393 bool filter, | |
394 const SkPaint& paint) { | |
395 // Logic as below:- | |
396 // 1. Translate the destination rectangle using the current translation | |
397 // values from the SkCanvas matrix stack. | |
398 // 2. Save the current state of the canvas. | |
399 // 3. Reset the scales and the translation values in the SkCanvas matrix | |
400 // stack top. | |
401 // 4. Set the scale in gfx::Canvas instance to 1.0, 1.0. | |
402 // 5. Draw the image. | |
403 // 6. Restore the state of the canvas and the SkCanvas matrix stack. | |
404 float image_scale = image_scale_; | |
405 SkMatrix matrix = canvas_->getTotalMatrix(); | |
389 | 406 |
390 float user_scale_x = static_cast<float>(dest_w) / src_w; | 407 SkRect destination_rect; |
391 float user_scale_y = static_cast<float>(dest_h) / src_h; | 408 destination_rect.set(SkIntToScalar(dest_x), |
392 | |
393 const ImageSkiaRep& image_rep = GetImageRepToPaint(image, | |
394 user_scale_x, user_scale_y); | |
395 if (image_rep.is_null()) | |
396 return; | |
397 | |
398 SkRect dest_rect = { SkIntToScalar(dest_x), | |
399 SkIntToScalar(dest_y), | 409 SkIntToScalar(dest_y), |
400 SkIntToScalar(dest_x + dest_w), | 410 SkIntToScalar(dest_x + dest_w), |
401 SkIntToScalar(dest_y + dest_h) }; | 411 SkIntToScalar(dest_y + dest_h)); |
412 matrix.setScaleX(1.0f); | |
413 matrix.setScaleY(1.0f); | |
414 matrix.mapRect(&destination_rect, destination_rect); | |
402 | 415 |
403 if (src_w == dest_w && src_h == dest_h && | 416 Save(); |
404 user_scale_x == 1.0f && user_scale_y == 1.0f && | |
405 image_rep.scale() == 1.0f) { | |
406 // Workaround for apparent bug in Skia that causes image to occasionally | |
407 // shift. | |
408 SkIRect src_rect = { src_x, src_y, src_x + src_w, src_y + src_h }; | |
409 const SkBitmap& bitmap = image_rep.sk_bitmap(); | |
410 canvas_->drawBitmapRect(bitmap, &src_rect, dest_rect, &paint); | |
411 return; | |
412 } | |
413 | 417 |
414 // Make a bitmap shader that contains the bitmap we want to draw. This is | 418 // The destination is now in pixel values. No need for further translation. |
415 // basically what SkCanvas.drawBitmap does internally, but it gives us | 419 matrix.setTranslate(0, 0); |
416 // more control over quality and will use the mipmap in the source image if | 420 canvas_->setMatrix(matrix); |
417 // it has one, whereas drawBitmap won't. | |
418 SkMatrix shader_scale; | |
419 shader_scale.setScale(SkFloatToScalar(user_scale_x), | |
420 SkFloatToScalar(user_scale_y)); | |
421 shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y)); | |
422 shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y)); | |
423 | 421 |
424 skia::RefPtr<SkShader> shader = CreateImageRepShader( | 422 Scale(1.0f, 1.0f); |
sky
2014/05/05 20:51:14
Is this needed? Haven't you effectively reset the
ananta
2014/05/05 21:36:20
Yeah. Not needed.
| |
425 image_rep, | |
426 SkShader::kRepeat_TileMode, | |
427 shader_scale); | |
428 | 423 |
429 // Set up our paint to use the shader & release our reference (now just owned | 424 DrawImageIntHelper(image, |
430 // by the paint). | 425 src_x, |
431 SkPaint p(paint); | 426 src_y, |
432 p.setFilterBitmap(filter); | 427 src_w, |
433 p.setShader(shader.get()); | 428 src_h, |
429 SkScalarRoundToInt(destination_rect.x()), | |
430 SkScalarRoundToInt(destination_rect.y()), | |
431 SkScalarRoundToInt(destination_rect.width()), | |
432 SkScalarRoundToInt(destination_rect.height()), | |
433 filter, | |
434 paint, | |
435 image_scale, | |
436 true); | |
434 | 437 |
435 // The rect will be filled by the bitmap. | 438 // Restore the state of the canvas. |
436 canvas_->drawRect(dest_rect, p); | 439 Restore(); |
440 image_scale_ = image_scale; | |
sky
2014/05/05 20:51:14
Is this needed?
ananta
2014/05/05 21:36:20
Have that for correctness in case the canvas is us
sky
2014/05/06 00:24:10
Where are you actually changing image_scale_ thoug
| |
437 } | 441 } |
438 | 442 |
439 void Canvas::DrawImageInPath(const ImageSkia& image, | 443 void Canvas::DrawImageInPath(const ImageSkia& image, |
440 int x, | 444 int x, |
441 int y, | 445 int y, |
442 const SkPath& path, | 446 const SkPath& path, |
443 const SkPaint& paint) { | 447 const SkPaint& paint) { |
444 const ImageSkiaRep& image_rep = GetImageRepToPaint(image); | 448 const ImageSkiaRep& image_rep = GetImageRepToPaint(image); |
445 if (image_rep.is_null()) | 449 if (image_rep.is_null()) |
446 return; | 450 return; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
498 float tile_scale_x, | 502 float tile_scale_x, |
499 float tile_scale_y, | 503 float tile_scale_y, |
500 int dest_x, | 504 int dest_x, |
501 int dest_y, | 505 int dest_y, |
502 int w, | 506 int w, |
503 int h) { | 507 int h) { |
504 if (!IntersectsClipRectInt(dest_x, dest_y, w, h)) | 508 if (!IntersectsClipRectInt(dest_x, dest_y, w, h)) |
505 return; | 509 return; |
506 | 510 |
507 const ImageSkiaRep& image_rep = GetImageRepToPaint( | 511 const ImageSkiaRep& image_rep = GetImageRepToPaint( |
508 image, tile_scale_x, tile_scale_y); | 512 image, image_scale_, tile_scale_x, tile_scale_y); |
509 if (image_rep.is_null()) | 513 if (image_rep.is_null()) |
510 return; | 514 return; |
511 | 515 |
512 SkMatrix shader_scale; | 516 SkMatrix shader_scale; |
513 shader_scale.setScale(SkFloatToScalar(tile_scale_x), | 517 shader_scale.setScale(SkFloatToScalar(tile_scale_x), |
514 SkFloatToScalar(tile_scale_y)); | 518 SkFloatToScalar(tile_scale_y)); |
515 shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y)); | 519 shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y)); |
516 shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y)); | 520 shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y)); |
517 | 521 |
518 skia::RefPtr<SkShader> shader = CreateImageRepShader( | 522 skia::RefPtr<SkShader> shader = CreateImageRepShader( |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
556 clip.intersect(SkIntToScalar(x), SkIntToScalar(y), SkIntToScalar(x + w), | 560 clip.intersect(SkIntToScalar(x), SkIntToScalar(y), SkIntToScalar(x + w), |
557 SkIntToScalar(y + h)); | 561 SkIntToScalar(y + h)); |
558 } | 562 } |
559 | 563 |
560 bool Canvas::IntersectsClipRect(const Rect& rect) { | 564 bool Canvas::IntersectsClipRect(const Rect& rect) { |
561 return IntersectsClipRectInt(rect.x(), rect.y(), | 565 return IntersectsClipRectInt(rect.x(), rect.y(), |
562 rect.width(), rect.height()); | 566 rect.width(), rect.height()); |
563 } | 567 } |
564 | 568 |
565 const ImageSkiaRep& Canvas::GetImageRepToPaint(const ImageSkia& image) const { | 569 const ImageSkiaRep& Canvas::GetImageRepToPaint(const ImageSkia& image) const { |
566 return GetImageRepToPaint(image, 1.0f, 1.0f); | 570 return GetImageRepToPaint(image, image_scale_, 1.0f, 1.0f); |
567 } | 571 } |
568 | 572 |
569 const ImageSkiaRep& Canvas::GetImageRepToPaint( | 573 const ImageSkiaRep& Canvas::GetImageRepToPaint( |
570 const ImageSkia& image, | 574 const ImageSkia& image, |
575 float image_scale, | |
571 float user_additional_scale_x, | 576 float user_additional_scale_x, |
572 float user_additional_scale_y) const { | 577 float user_additional_scale_y) const { |
573 const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_); | 578 const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale); |
574 | 579 |
575 if (!image_rep.is_null()) { | 580 if (!image_rep.is_null()) { |
576 SkMatrix m = canvas_->getTotalMatrix(); | 581 SkMatrix m = canvas_->getTotalMatrix(); |
577 float scale_x = SkScalarToFloat(SkScalarAbs(m.getScaleX())) * | 582 float scale_x = SkScalarToFloat(SkScalarAbs(m.getScaleX())) * |
578 user_additional_scale_x; | 583 user_additional_scale_x; |
579 float scale_y = SkScalarToFloat(SkScalarAbs(m.getScaleY())) * | 584 float scale_y = SkScalarToFloat(SkScalarAbs(m.getScaleY())) * |
580 user_additional_scale_y; | 585 user_additional_scale_y; |
581 | 586 |
582 float bitmap_scale = image_rep.scale(); | 587 float bitmap_scale = image_rep.scale(); |
583 if (scale_x < bitmap_scale || scale_y < bitmap_scale) | 588 if (scale_x < bitmap_scale || scale_y < bitmap_scale) |
584 const_cast<SkBitmap&>(image_rep.sk_bitmap()).buildMipMap(); | 589 const_cast<SkBitmap&>(image_rep.sk_bitmap()).buildMipMap(); |
585 } | 590 } |
586 | 591 |
587 return image_rep; | 592 return image_rep; |
588 } | 593 } |
589 | 594 |
595 void Canvas::DrawImageIntHelper(const ImageSkia& image, | |
596 int src_x, | |
597 int src_y, | |
598 int src_w, | |
599 int src_h, | |
600 int dest_x, | |
601 int dest_y, | |
602 int dest_w, | |
603 int dest_h, | |
604 bool filter, | |
605 const SkPaint& paint, | |
606 float image_scale, | |
607 bool pixel) { | |
608 DLOG_ASSERT(src_x + src_w < std::numeric_limits<int16_t>::max() && | |
609 src_y + src_h < std::numeric_limits<int16_t>::max()); | |
610 if (src_w <= 0 || src_h <= 0) { | |
611 NOTREACHED() << "Attempting to draw bitmap from an empty rect!"; | |
612 return; | |
613 } | |
614 | |
615 if (!IntersectsClipRectInt(dest_x, dest_y, dest_w, dest_h)) | |
616 return; | |
617 | |
618 float user_scale_x = static_cast<float>(dest_w) / src_w; | |
619 float user_scale_y = static_cast<float>(dest_h) / src_h; | |
620 | |
621 const ImageSkiaRep& image_rep = GetImageRepToPaint(image, | |
622 image_scale, user_scale_x, user_scale_y); | |
623 if (image_rep.is_null()) | |
624 return; | |
625 | |
626 SkRect dest_rect = { SkIntToScalar(dest_x), | |
627 SkIntToScalar(dest_y), | |
628 SkIntToScalar(dest_x + dest_w), | |
629 SkIntToScalar(dest_y + dest_h) }; | |
630 | |
631 if (src_w == dest_w && src_h == dest_h && | |
632 user_scale_x == 1.0f && user_scale_y == 1.0f && | |
633 image_rep.scale() == 1.0f && !pixel) { | |
634 // Workaround for apparent bug in Skia that causes image to occasionally | |
635 // shift. | |
636 SkIRect src_rect = { src_x, src_y, src_x + src_w, src_y + src_h }; | |
637 const SkBitmap& bitmap = image_rep.sk_bitmap(); | |
638 canvas_->drawBitmapRect(bitmap, &src_rect, dest_rect, &paint); | |
639 return; | |
640 } | |
641 | |
642 // Make a bitmap shader that contains the bitmap we want to draw. This is | |
643 // basically what SkCanvas.drawBitmap does internally, but it gives us | |
644 // more control over quality and will use the mipmap in the source image if | |
645 // it has one, whereas drawBitmap won't. | |
646 SkMatrix shader_scale; | |
647 shader_scale.setScale(SkFloatToScalar(user_scale_x), | |
648 SkFloatToScalar(user_scale_y)); | |
649 shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y)); | |
650 shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y)); | |
651 | |
652 skia::RefPtr<SkShader> shader = CreateImageRepShaderForScale( | |
653 image_rep, | |
654 SkShader::kRepeat_TileMode, | |
655 shader_scale, | |
656 pixel ? 1.0f : image_scale); | |
657 | |
658 // Set up our paint to use the shader & release our reference (now just owned | |
659 // by the paint). | |
660 SkPaint p(paint); | |
661 p.setFilterBitmap(filter); | |
662 p.setShader(shader.get()); | |
663 | |
664 // The rect will be filled by the bitmap. | |
665 canvas_->drawRect(dest_rect, p); | |
666 } | |
667 | |
590 } // namespace gfx | 668 } // namespace gfx |
OLD | NEW |