Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(155)

Side by Side Diff: ui/gfx/canvas.cc

Issue 262773010: Fix images drawn with the NineImagePainter class in high DPI. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Renamed variables Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/gfx/canvas.h ('k') | ui/gfx/nine_image_painter.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « ui/gfx/canvas.h ('k') | ui/gfx/nine_image_painter.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698