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

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: NineImagePainter draws using raw pixels 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
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 with using the current translation
sky 2014/05/05 14:08:16 nit: remove with.
ananta 2014/05/05 18:53:28 Done.
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. Ideally this should
sky 2014/05/05 14:08:16 I don't get the 'ideally this sould have been enou
ananta 2014/05/05 18:53:28 I assumed that setting the scale to 1.0 in the SkC
402 // have been enough. But is not the case.
403 // 5. Draw the image.
404 // 6. Restore the state of the canvas and the SkCanvas matrix stack.
405 float image_scale = image_scale_;
406 SkMatrix saved_matrix = canvas_->getTotalMatrix();
407 SkMatrix new_matrix = saved_matrix;
389 408
390 float user_scale_x = static_cast<float>(dest_w) / src_w; 409 SkRect destination_rect;
391 float user_scale_y = static_cast<float>(dest_h) / src_h; 410 destination_rect.set(dest_x, dest_y, dest_x + dest_w, dest_y + dest_h);
sky 2014/05/05 14:08:16 These should all be SkIntToScalar I bleieve.
ananta 2014/05/05 18:53:28 Done.
411 new_matrix.setScaleX(1.0f);
412 new_matrix.setScaleY(1.0f);
413 new_matrix.mapRect(&destination_rect, destination_rect);
392 414
393 const ImageSkiaRep& image_rep = GetImageRepToPaint(image, 415 Save();
394 user_scale_x, user_scale_y);
395 if (image_rep.is_null())
396 return;
397 416
398 SkRect dest_rect = { SkIntToScalar(dest_x), 417 // The destination is now in pixel values. No need for further translation.
399 SkIntToScalar(dest_y), 418 new_matrix.setTranslate(0, 0);
400 SkIntToScalar(dest_x + dest_w), 419 canvas_->setMatrix(new_matrix);
401 SkIntToScalar(dest_y + dest_h) };
402 420
403 if (src_w == dest_w && src_h == dest_h && 421 Scale(1.0f, 1.0f);
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 422
414 // Make a bitmap shader that contains the bitmap we want to draw. This is 423 DrawImageIntHelper(image, src_x, src_y, src_w, src_h, destination_rect.x(),
sky 2014/05/05 14:08:16 SkScalarToInt I believe.
ananta 2014/05/05 18:53:28 No function by that name. Replaced with SkScalarRo
415 // basically what SkCanvas.drawBitmap does internally, but it gives us 424 destination_rect.y(), destination_rect.width(),
416 // more control over quality and will use the mipmap in the source image if 425 destination_rect.height(), filter, paint, image_scale,
417 // it has one, whereas drawBitmap won't. 426 true);
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 427
424 skia::RefPtr<SkShader> shader = CreateImageRepShader( 428 // Restore the scale factor and the old state in the canvas.
425 image_rep, 429 Scale(image_scale, image_scale);
sky 2014/05/05 14:08:16 Doesn't the save save the matrix and scale so that
ananta 2014/05/05 18:53:28 Left the Restore call as is. Removed the rest.
426 SkShader::kRepeat_TileMode, 430 Restore();
427 shader_scale); 431 canvas_->setMatrix(saved_matrix);
428 432 image_scale_ = image_scale;
429 // Set up our paint to use the shader & release our reference (now just owned
430 // by the paint).
431 SkPaint p(paint);
432 p.setFilterBitmap(filter);
433 p.setShader(shader.get());
434
435 // The rect will be filled by the bitmap.
436 canvas_->drawRect(dest_rect, p);
437 } 433 }
438 434
439 void Canvas::DrawImageInPath(const ImageSkia& image, 435 void Canvas::DrawImageInPath(const ImageSkia& image,
440 int x, 436 int x,
441 int y, 437 int y,
442 const SkPath& path, 438 const SkPath& path,
443 const SkPaint& paint) { 439 const SkPaint& paint) {
444 const ImageSkiaRep& image_rep = GetImageRepToPaint(image); 440 const ImageSkiaRep& image_rep = GetImageRepToPaint(image);
445 if (image_rep.is_null()) 441 if (image_rep.is_null())
446 return; 442 return;
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
498 float tile_scale_x, 494 float tile_scale_x,
499 float tile_scale_y, 495 float tile_scale_y,
500 int dest_x, 496 int dest_x,
501 int dest_y, 497 int dest_y,
502 int w, 498 int w,
503 int h) { 499 int h) {
504 if (!IntersectsClipRectInt(dest_x, dest_y, w, h)) 500 if (!IntersectsClipRectInt(dest_x, dest_y, w, h))
505 return; 501 return;
506 502
507 const ImageSkiaRep& image_rep = GetImageRepToPaint( 503 const ImageSkiaRep& image_rep = GetImageRepToPaint(
508 image, tile_scale_x, tile_scale_y); 504 image, image_scale_, tile_scale_x, tile_scale_y);
509 if (image_rep.is_null()) 505 if (image_rep.is_null())
510 return; 506 return;
511 507
512 SkMatrix shader_scale; 508 SkMatrix shader_scale;
513 shader_scale.setScale(SkFloatToScalar(tile_scale_x), 509 shader_scale.setScale(SkFloatToScalar(tile_scale_x),
514 SkFloatToScalar(tile_scale_y)); 510 SkFloatToScalar(tile_scale_y));
515 shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y)); 511 shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y));
516 shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y)); 512 shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y));
517 513
518 skia::RefPtr<SkShader> shader = CreateImageRepShader( 514 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), 552 clip.intersect(SkIntToScalar(x), SkIntToScalar(y), SkIntToScalar(x + w),
557 SkIntToScalar(y + h)); 553 SkIntToScalar(y + h));
558 } 554 }
559 555
560 bool Canvas::IntersectsClipRect(const Rect& rect) { 556 bool Canvas::IntersectsClipRect(const Rect& rect) {
561 return IntersectsClipRectInt(rect.x(), rect.y(), 557 return IntersectsClipRectInt(rect.x(), rect.y(),
562 rect.width(), rect.height()); 558 rect.width(), rect.height());
563 } 559 }
564 560
565 const ImageSkiaRep& Canvas::GetImageRepToPaint(const ImageSkia& image) const { 561 const ImageSkiaRep& Canvas::GetImageRepToPaint(const ImageSkia& image) const {
566 return GetImageRepToPaint(image, 1.0f, 1.0f); 562 return GetImageRepToPaint(image, image_scale_, 1.0f, 1.0f);
567 } 563 }
568 564
569 const ImageSkiaRep& Canvas::GetImageRepToPaint( 565 const ImageSkiaRep& Canvas::GetImageRepToPaint(
570 const ImageSkia& image, 566 const ImageSkia& image,
567 float image_scale,
571 float user_additional_scale_x, 568 float user_additional_scale_x,
572 float user_additional_scale_y) const { 569 float user_additional_scale_y) const {
573 const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_); 570 const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale);
574 571
575 if (!image_rep.is_null()) { 572 if (!image_rep.is_null()) {
576 SkMatrix m = canvas_->getTotalMatrix(); 573 SkMatrix m = canvas_->getTotalMatrix();
577 float scale_x = SkScalarToFloat(SkScalarAbs(m.getScaleX())) * 574 float scale_x = SkScalarToFloat(SkScalarAbs(m.getScaleX())) *
578 user_additional_scale_x; 575 user_additional_scale_x;
579 float scale_y = SkScalarToFloat(SkScalarAbs(m.getScaleY())) * 576 float scale_y = SkScalarToFloat(SkScalarAbs(m.getScaleY())) *
580 user_additional_scale_y; 577 user_additional_scale_y;
581 578
582 float bitmap_scale = image_rep.scale(); 579 float bitmap_scale = image_rep.scale();
583 if (scale_x < bitmap_scale || scale_y < bitmap_scale) 580 if (scale_x < bitmap_scale || scale_y < bitmap_scale)
584 const_cast<SkBitmap&>(image_rep.sk_bitmap()).buildMipMap(); 581 const_cast<SkBitmap&>(image_rep.sk_bitmap()).buildMipMap();
585 } 582 }
586 583
587 return image_rep; 584 return image_rep;
588 } 585 }
589 586
587 void Canvas::DrawImageIntHelper(const ImageSkia& image,
588 int src_x,
589 int src_y,
590 int src_w,
591 int src_h,
592 int dest_x,
593 int dest_y,
594 int dest_w,
595 int dest_h,
596 bool filter,
597 const SkPaint& paint,
598 float image_scale,
599 bool pixel) {
600 DLOG_ASSERT(src_x + src_w < std::numeric_limits<int16_t>::max() &&
601 src_y + src_h < std::numeric_limits<int16_t>::max());
602 if (src_w <= 0 || src_h <= 0) {
603 NOTREACHED() << "Attempting to draw bitmap from an empty rect!";
604 return;
605 }
606
607 if (!IntersectsClipRectInt(dest_x, dest_y, dest_w, dest_h))
608 return;
609
610 float user_scale_x = static_cast<float>(dest_w) / src_w;
611 float user_scale_y = static_cast<float>(dest_h) / src_h;
612
613 const ImageSkiaRep& image_rep = GetImageRepToPaint(image,
614 image_scale, user_scale_x, user_scale_y);
615 if (image_rep.is_null())
616 return;
617
618 SkRect dest_rect = { SkIntToScalar(dest_x),
619 SkIntToScalar(dest_y),
620 SkIntToScalar(dest_x + dest_w),
621 SkIntToScalar(dest_y + dest_h) };
622
623 if (src_w == dest_w && src_h == dest_h &&
624 user_scale_x == 1.0f && user_scale_y == 1.0f &&
625 image_rep.scale() == 1.0f && !pixel) {
626 // Workaround for apparent bug in Skia that causes image to occasionally
627 // shift.
628 SkIRect src_rect = { src_x, src_y, src_x + src_w, src_y + src_h };
629 const SkBitmap& bitmap = image_rep.sk_bitmap();
630 canvas_->drawBitmapRect(bitmap, &src_rect, dest_rect, &paint);
631 return;
632 }
633
634 // Make a bitmap shader that contains the bitmap we want to draw. This is
635 // basically what SkCanvas.drawBitmap does internally, but it gives us
636 // more control over quality and will use the mipmap in the source image if
637 // it has one, whereas drawBitmap won't.
638 SkMatrix shader_scale;
639 shader_scale.setScale(SkFloatToScalar(user_scale_x),
640 SkFloatToScalar(user_scale_y));
641 shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y));
642 shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y));
643
644 skia::RefPtr<SkShader> shader = CreateImageRepShaderForScale(
645 image_rep,
646 SkShader::kRepeat_TileMode,
647 shader_scale,
648 pixel ? 1.0f : image_scale);
649
650 // Set up our paint to use the shader & release our reference (now just owned
651 // by the paint).
652 SkPaint p(paint);
653 p.setFilterBitmap(filter);
654 p.setShader(shader.get());
655
656 // The rect will be filled by the bitmap.
657 canvas_->drawRect(dest_rect, p);
658 }
659
590 } // namespace gfx 660 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/canvas.h ('k') | ui/gfx/nine_image_painter.cc » ('j') | ui/gfx/nine_image_painter.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698