| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/gfx/nine_image_painter.h" |
| |
| #include "base/base64.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/gfx/canvas.h" |
| #include "ui/gfx/codec/png_codec.h" |
| #include "ui/gfx/geometry/insets.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "ui/gfx/geometry/vector2d.h" |
| #include "ui/gfx/geometry/vector2d_conversions.h" |
| #include "ui/gfx/image/image_skia.h" |
| |
| namespace gfx { |
| |
| static std::string GetPNGDataUrl(const SkBitmap& bitmap) { |
| std::vector<unsigned char> png_data; |
| gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &png_data); |
| std::string data_url; |
| data_url.insert(data_url.end(), png_data.begin(), png_data.end()); |
| base::Base64Encode(data_url, &data_url); |
| data_url.insert(0, "data:image/png;base64,"); |
| |
| return data_url; |
| } |
| |
| void ExpectRedWithGreenRect(const SkBitmap& bitmap, |
| const Rect& outer_rect, |
| const Rect& green_rect) { |
| for (int y = outer_rect.y(); y < outer_rect.bottom(); y++) { |
| SCOPED_TRACE(y); |
| for (int x = outer_rect.x(); x < outer_rect.right(); x++) { |
| SCOPED_TRACE(x); |
| if (green_rect.Contains(x, y)) { |
| ASSERT_EQ(SK_ColorGREEN, bitmap.getColor(x, y)) |
| << "Output image:\n" << GetPNGDataUrl(bitmap); |
| } else { |
| ASSERT_EQ(SK_ColorRED, bitmap.getColor(x, y)) << "Output image:\n" |
| << GetPNGDataUrl(bitmap); |
| } |
| } |
| } |
| } |
| |
| TEST(NineImagePainterTest, GetSubsetRegions) { |
| SkBitmap src; |
| src.allocN32Pixels(40, 50); |
| const ImageSkia image_skia(ImageSkiaRep(src, 1.0)); |
| const Insets insets(1, 2, 3, 4); |
| std::vector<Rect> rects; |
| NineImagePainter::GetSubsetRegions(image_skia, insets, &rects); |
| ASSERT_EQ(9u, rects.size()); |
| EXPECT_EQ(gfx::Rect(0, 0, 2, 1), rects[0]); |
| EXPECT_EQ(gfx::Rect(2, 0, 34, 1), rects[1]); |
| EXPECT_EQ(gfx::Rect(36, 0, 4, 1), rects[2]); |
| EXPECT_EQ(gfx::Rect(0, 1, 2, 46), rects[3]); |
| EXPECT_EQ(gfx::Rect(2, 1, 34, 46), rects[4]); |
| EXPECT_EQ(gfx::Rect(36, 1, 4, 46), rects[5]); |
| EXPECT_EQ(gfx::Rect(0, 47, 2, 3), rects[6]); |
| EXPECT_EQ(gfx::Rect(2, 47, 34, 3), rects[7]); |
| EXPECT_EQ(gfx::Rect(36, 47, 4, 3), rects[8]); |
| } |
| |
| TEST(NineImagePainterTest, PaintHighDPI) { |
| SkBitmap src; |
| src.allocN32Pixels(100, 100); |
| src.eraseColor(SK_ColorRED); |
| src.eraseArea(SkIRect::MakeXYWH(10, 10, 80, 80), SK_ColorGREEN); |
| |
| float image_scale = 2.f; |
| |
| gfx::ImageSkia image = gfx::ImageSkia::CreateFromBitmap(src, image_scale); |
| gfx::Insets insets(10, 10, 10, 10); |
| gfx::NineImagePainter painter(image, insets); |
| |
| bool is_opaque = true; |
| gfx::Canvas canvas(gfx::Size(100, 100), image_scale, is_opaque); |
| |
| gfx::Vector2d offset(20, 10); |
| canvas.Translate(offset); |
| |
| gfx::Rect bounds(0, 0, 50, 50); |
| painter.Paint(&canvas, bounds); |
| |
| SkBitmap result = canvas.GetBitmap(); |
| |
| gfx::Vector2d paint_offset = |
| gfx::ToFlooredVector2d(gfx::ScaleVector2d(offset, image_scale)); |
| gfx::Rect green_rect = gfx::Rect(10, 10, 80, 80) + paint_offset; |
| gfx::Rect outer_rect = gfx::Rect(100, 100) + paint_offset; |
| ExpectRedWithGreenRect(result, outer_rect, green_rect); |
| } |
| |
| TEST(NineImagePainterTest, PaintStaysInBounds) { |
| // In this test the bounds rect is 1x1 but each image is 2x2. |
| // The NineImagePainter should not paint outside the bounds. |
| // The border images should be cropped, but still painted. |
| |
| SkBitmap src; |
| src.allocN32Pixels(6, 6); |
| src.eraseColor(SK_ColorGREEN); |
| src.erase(SK_ColorRED, SkIRect::MakeXYWH(2, 2, 2, 2)); |
| |
| gfx::ImageSkia image = gfx::ImageSkia::CreateFrom1xBitmap(src); |
| gfx::Insets insets(2, 2, 2, 2); |
| gfx::NineImagePainter painter(image, insets); |
| |
| int image_scale = 1; |
| bool is_opaque = true; |
| gfx::Canvas canvas(gfx::Size(3, 3), image_scale, is_opaque); |
| canvas.DrawColor(SK_ColorBLACK); |
| |
| gfx::Rect bounds(1, 1, 1, 1); |
| painter.Paint(&canvas, bounds); |
| |
| SkBitmap result = canvas.GetBitmap(); |
| |
| EXPECT_EQ(SK_ColorGREEN, result.getColor(1, 1)); |
| |
| EXPECT_EQ(SK_ColorBLACK, result.getColor(0, 0)); |
| EXPECT_EQ(SK_ColorBLACK, result.getColor(0, 1)); |
| EXPECT_EQ(SK_ColorBLACK, result.getColor(0, 2)); |
| EXPECT_EQ(SK_ColorBLACK, result.getColor(1, 0)); |
| EXPECT_EQ(SK_ColorBLACK, result.getColor(1, 2)); |
| EXPECT_EQ(SK_ColorBLACK, result.getColor(2, 0)); |
| EXPECT_EQ(SK_ColorBLACK, result.getColor(2, 1)); |
| EXPECT_EQ(SK_ColorBLACK, result.getColor(2, 2)); |
| } |
| |
| TEST(NineImagePainterTest, PaintWithBoundOffset) { |
| SkBitmap src; |
| src.allocN32Pixels(10, 10); |
| src.eraseColor(SK_ColorRED); |
| src.eraseArea(SkIRect::MakeXYWH(1, 1, 8, 8), SK_ColorGREEN); |
| |
| gfx::ImageSkia image = gfx::ImageSkia::CreateFrom1xBitmap(src); |
| gfx::Insets insets(1, 1, 1, 1); |
| gfx::NineImagePainter painter(image, insets); |
| |
| bool is_opaque = true; |
| gfx::Canvas canvas(gfx::Size(10, 10), 1, is_opaque); |
| |
| gfx::Rect bounds(1, 1, 10, 10); |
| painter.Paint(&canvas, bounds); |
| |
| SkBitmap result = canvas.GetBitmap(); |
| |
| SkIRect green_rect = SkIRect::MakeLTRB(2, 2, 10, 10); |
| for (int y = 1; y < 10; y++) { |
| for (int x = 1; x < 10; x++) { |
| if (green_rect.contains(x, y)) { |
| ASSERT_EQ(SK_ColorGREEN, result.getColor(x, y)); |
| } else { |
| ASSERT_EQ(SK_ColorRED, result.getColor(x, y)); |
| } |
| } |
| } |
| } |
| |
| TEST(NineImagePainterTest, PaintWithScale) { |
| SkBitmap src; |
| src.allocN32Pixels(100, 100); |
| src.eraseColor(SK_ColorRED); |
| src.eraseArea(SkIRect::MakeXYWH(10, 10, 80, 80), SK_ColorGREEN); |
| |
| float image_scale = 2.f; |
| |
| gfx::ImageSkia image = gfx::ImageSkia::CreateFromBitmap(src, image_scale); |
| gfx::Insets insets(10, 10, 10, 10); |
| gfx::NineImagePainter painter(image, insets); |
| |
| bool is_opaque = true; |
| gfx::Canvas canvas(gfx::Size(400, 400), image_scale, is_opaque); |
| |
| gfx::Vector2d offset(20, 10); |
| canvas.Translate(offset); |
| canvas.Scale(2, 1); |
| |
| gfx::Rect bounds(0, 0, 50, 50); |
| painter.Paint(&canvas, bounds); |
| |
| SkBitmap result = canvas.GetBitmap(); |
| |
| gfx::Vector2d paint_offset = |
| gfx::ToFlooredVector2d(gfx::ScaleVector2d(offset, image_scale)); |
| gfx::Rect green_rect = gfx::Rect(20, 10, 160, 80) + paint_offset; |
| gfx::Rect outer_rect = gfx::Rect(200, 100) + paint_offset; |
| ExpectRedWithGreenRect(result, outer_rect, green_rect); |
| } |
| |
| TEST(NineImagePainterTest, PaintWithNegativeScale) { |
| SkBitmap src; |
| src.allocN32Pixels(100, 100); |
| src.eraseColor(SK_ColorRED); |
| src.eraseArea(SkIRect::MakeXYWH(10, 10, 80, 80), SK_ColorGREEN); |
| |
| float image_scale = 2.f; |
| |
| gfx::ImageSkia image = gfx::ImageSkia::CreateFromBitmap(src, image_scale); |
| gfx::Insets insets(10, 10, 10, 10); |
| gfx::NineImagePainter painter(image, insets); |
| |
| bool is_opaque = true; |
| gfx::Canvas canvas(gfx::Size(400, 400), image_scale, is_opaque); |
| canvas.Translate(gfx::Vector2d(70, 60)); |
| canvas.Scale(-1, -1); |
| |
| gfx::Rect bounds(0, 0, 50, 50); |
| painter.Paint(&canvas, bounds); |
| |
| SkBitmap result = canvas.GetBitmap(); |
| |
| // The painting space is 50x50 and the scale of -1,-1 means an offset of 50,50 |
| // would put the output in the top left corner. Since the offset is 70,60 it |
| // moves by 20,10. Since the output is 2x DPI it will become offset by 40,20. |
| gfx::Vector2d paint_offset(40, 20); |
| gfx::Rect green_rect = gfx::Rect(10, 10, 80, 80) + paint_offset; |
| gfx::Rect outer_rect = gfx::Rect(100, 100) + paint_offset; |
| ExpectRedWithGreenRect(result, outer_rect, green_rect); |
| } |
| |
| } // namespace gfx |