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

Unified 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, 8 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 side-by-side diff with in-line comments
Download patch
Index: ui/gfx/canvas.cc
diff --git a/ui/gfx/canvas.cc b/ui/gfx/canvas.cc
index 0b7819582031a757b168523c1ca4ef0e42254813..458a0b261804e94a4dbf6a9d6e0969a43ca40492 100644
--- a/ui/gfx/canvas.cc
+++ b/ui/gfx/canvas.cc
@@ -377,63 +377,59 @@ void Canvas::DrawImageInt(const ImageSkia& image,
int dest_h,
bool filter,
const SkPaint& paint) {
- DLOG_ASSERT(src_x + src_w < std::numeric_limits<int16_t>::max() &&
- src_y + src_h < std::numeric_limits<int16_t>::max());
- if (src_w <= 0 || src_h <= 0) {
- NOTREACHED() << "Attempting to draw bitmap from an empty rect!";
- return;
- }
-
- if (!IntersectsClipRectInt(dest_x, dest_y, dest_w, dest_h))
- return;
-
- float user_scale_x = static_cast<float>(dest_w) / src_w;
- float user_scale_y = static_cast<float>(dest_h) / src_h;
-
- const ImageSkiaRep& image_rep = GetImageRepToPaint(image,
- user_scale_x, user_scale_y);
- if (image_rep.is_null())
- return;
-
- SkRect dest_rect = { SkIntToScalar(dest_x),
- SkIntToScalar(dest_y),
- SkIntToScalar(dest_x + dest_w),
- SkIntToScalar(dest_y + dest_h) };
-
- if (src_w == dest_w && src_h == dest_h &&
- user_scale_x == 1.0f && user_scale_y == 1.0f &&
- image_rep.scale() == 1.0f) {
- // Workaround for apparent bug in Skia that causes image to occasionally
- // shift.
- SkIRect src_rect = { src_x, src_y, src_x + src_w, src_y + src_h };
- const SkBitmap& bitmap = image_rep.sk_bitmap();
- canvas_->drawBitmapRect(bitmap, &src_rect, dest_rect, &paint);
- return;
- }
-
- // Make a bitmap shader that contains the bitmap we want to draw. This is
- // basically what SkCanvas.drawBitmap does internally, but it gives us
- // more control over quality and will use the mipmap in the source image if
- // it has one, whereas drawBitmap won't.
- SkMatrix shader_scale;
- shader_scale.setScale(SkFloatToScalar(user_scale_x),
- SkFloatToScalar(user_scale_y));
- shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y));
- shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y));
-
- skia::RefPtr<SkShader> shader = CreateImageRepShader(
- image_rep,
- SkShader::kRepeat_TileMode,
- shader_scale);
-
- // Set up our paint to use the shader & release our reference (now just owned
- // by the paint).
- SkPaint p(paint);
- p.setFilterBitmap(filter);
- p.setShader(shader.get());
-
- // The rect will be filled by the bitmap.
- canvas_->drawRect(dest_rect, p);
+ DrawImageIntHelper(image, src_x, src_y, src_w, src_h, dest_x, dest_y, dest_w,
+ dest_h, filter, paint, image_scale_, false);
+}
+
+void Canvas::DrawImageIntInPixel(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) {
+ // Logic as below:-
+ // 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.
+ // values from the SkCanvas matrix stack.
+ // 2. Save the current state of the canvas.
+ // 3. Reset the scales and the translation values in the SkCanvas matrix
+ // stack top.
+ // 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
+ // have been enough. But is not the case.
+ // 5. Draw the image.
+ // 6. Restore the state of the canvas and the SkCanvas matrix stack.
+ float image_scale = image_scale_;
+ SkMatrix saved_matrix = canvas_->getTotalMatrix();
+ SkMatrix new_matrix = saved_matrix;
+
+ SkRect destination_rect;
+ 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.
+ new_matrix.setScaleX(1.0f);
+ new_matrix.setScaleY(1.0f);
+ new_matrix.mapRect(&destination_rect, destination_rect);
+
+ Save();
+
+ // The destination is now in pixel values. No need for further translation.
+ new_matrix.setTranslate(0, 0);
+ canvas_->setMatrix(new_matrix);
+
+ Scale(1.0f, 1.0f);
+
+ 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
+ destination_rect.y(), destination_rect.width(),
+ destination_rect.height(), filter, paint, image_scale,
+ true);
+
+ // Restore the scale factor and the old state in the canvas.
+ 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.
+ Restore();
+ canvas_->setMatrix(saved_matrix);
+ image_scale_ = image_scale;
}
void Canvas::DrawImageInPath(const ImageSkia& image,
@@ -505,7 +501,7 @@ void Canvas::TileImageInt(const ImageSkia& image,
return;
const ImageSkiaRep& image_rep = GetImageRepToPaint(
- image, tile_scale_x, tile_scale_y);
+ image, image_scale_, tile_scale_x, tile_scale_y);
if (image_rep.is_null())
return;
@@ -563,14 +559,15 @@ bool Canvas::IntersectsClipRect(const Rect& rect) {
}
const ImageSkiaRep& Canvas::GetImageRepToPaint(const ImageSkia& image) const {
- return GetImageRepToPaint(image, 1.0f, 1.0f);
+ return GetImageRepToPaint(image, image_scale_, 1.0f, 1.0f);
}
const ImageSkiaRep& Canvas::GetImageRepToPaint(
const ImageSkia& image,
+ float image_scale,
float user_additional_scale_x,
float user_additional_scale_y) const {
- const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_);
+ const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale);
if (!image_rep.is_null()) {
SkMatrix m = canvas_->getTotalMatrix();
@@ -587,4 +584,77 @@ const ImageSkiaRep& Canvas::GetImageRepToPaint(
return image_rep;
}
+void Canvas::DrawImageIntHelper(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,
+ float image_scale,
+ bool pixel) {
+ DLOG_ASSERT(src_x + src_w < std::numeric_limits<int16_t>::max() &&
+ src_y + src_h < std::numeric_limits<int16_t>::max());
+ if (src_w <= 0 || src_h <= 0) {
+ NOTREACHED() << "Attempting to draw bitmap from an empty rect!";
+ return;
+ }
+
+ if (!IntersectsClipRectInt(dest_x, dest_y, dest_w, dest_h))
+ return;
+
+ float user_scale_x = static_cast<float>(dest_w) / src_w;
+ float user_scale_y = static_cast<float>(dest_h) / src_h;
+
+ const ImageSkiaRep& image_rep = GetImageRepToPaint(image,
+ image_scale, user_scale_x, user_scale_y);
+ if (image_rep.is_null())
+ return;
+
+ SkRect dest_rect = { SkIntToScalar(dest_x),
+ SkIntToScalar(dest_y),
+ SkIntToScalar(dest_x + dest_w),
+ SkIntToScalar(dest_y + dest_h) };
+
+ if (src_w == dest_w && src_h == dest_h &&
+ user_scale_x == 1.0f && user_scale_y == 1.0f &&
+ image_rep.scale() == 1.0f && !pixel) {
+ // Workaround for apparent bug in Skia that causes image to occasionally
+ // shift.
+ SkIRect src_rect = { src_x, src_y, src_x + src_w, src_y + src_h };
+ const SkBitmap& bitmap = image_rep.sk_bitmap();
+ canvas_->drawBitmapRect(bitmap, &src_rect, dest_rect, &paint);
+ return;
+ }
+
+ // Make a bitmap shader that contains the bitmap we want to draw. This is
+ // basically what SkCanvas.drawBitmap does internally, but it gives us
+ // more control over quality and will use the mipmap in the source image if
+ // it has one, whereas drawBitmap won't.
+ SkMatrix shader_scale;
+ shader_scale.setScale(SkFloatToScalar(user_scale_x),
+ SkFloatToScalar(user_scale_y));
+ shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y));
+ shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y));
+
+ skia::RefPtr<SkShader> shader = CreateImageRepShaderForScale(
+ image_rep,
+ SkShader::kRepeat_TileMode,
+ shader_scale,
+ pixel ? 1.0f : image_scale);
+
+ // Set up our paint to use the shader & release our reference (now just owned
+ // by the paint).
+ SkPaint p(paint);
+ p.setFilterBitmap(filter);
+ p.setShader(shader.get());
+
+ // The rect will be filled by the bitmap.
+ canvas_->drawRect(dest_rect, p);
+}
+
} // namespace gfx
« 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