| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "build/build_config.h" | |
| 6 | |
| 7 #if !defined(OS_WIN) | |
| 8 #include <unistd.h> | |
| 9 #endif | |
| 10 | |
| 11 #include "base/command_line.h" | |
| 12 #include "base/files/file_util.h" | |
| 13 #include "base/path_service.h" | |
| 14 #include "base/strings/string_util.h" | |
| 15 #include "base/strings/stringprintf.h" | |
| 16 #include "base/strings/utf_string_conversions.h" | |
| 17 #include "skia/ext/vector_canvas.h" | |
| 18 #include "skia/ext/vector_platform_device_emf_win.h" | |
| 19 #include "testing/gtest/include/gtest/gtest.h" | |
| 20 #include "third_party/skia/include/effects/SkDashPathEffect.h" | |
| 21 #include "ui/gfx/codec/png_codec.h" | |
| 22 #include "ui/gfx/geometry/size.h" | |
| 23 | |
| 24 namespace skia { | |
| 25 | |
| 26 namespace { | |
| 27 | |
| 28 const char kGenerateSwitch[] = "vector-canvas-generate"; | |
| 29 | |
| 30 // Lightweight HDC management. | |
| 31 class Context { | |
| 32 public: | |
| 33 Context() : context_(CreateCompatibleDC(NULL)) { | |
| 34 EXPECT_TRUE(context_); | |
| 35 } | |
| 36 ~Context() { | |
| 37 DeleteDC(context_); | |
| 38 } | |
| 39 | |
| 40 HDC context() const { return context_; } | |
| 41 | |
| 42 private: | |
| 43 HDC context_; | |
| 44 | |
| 45 DISALLOW_COPY_AND_ASSIGN(Context); | |
| 46 }; | |
| 47 | |
| 48 // Lightweight HBITMAP management. | |
| 49 class Bitmap { | |
| 50 public: | |
| 51 Bitmap(const Context& context, int x, int y) { | |
| 52 BITMAPINFOHEADER hdr; | |
| 53 hdr.biSize = sizeof(BITMAPINFOHEADER); | |
| 54 hdr.biWidth = x; | |
| 55 hdr.biHeight = -y; // Minus means top-down bitmap. | |
| 56 hdr.biPlanes = 1; | |
| 57 hdr.biBitCount = 32; | |
| 58 hdr.biCompression = BI_RGB; // No compression. | |
| 59 hdr.biSizeImage = 0; | |
| 60 hdr.biXPelsPerMeter = 1; | |
| 61 hdr.biYPelsPerMeter = 1; | |
| 62 hdr.biClrUsed = 0; | |
| 63 hdr.biClrImportant = 0; | |
| 64 bitmap_ = CreateDIBSection(context.context(), | |
| 65 reinterpret_cast<BITMAPINFO*>(&hdr), 0, | |
| 66 &data_, NULL, 0); | |
| 67 EXPECT_TRUE(bitmap_); | |
| 68 EXPECT_TRUE(SelectObject(context.context(), bitmap_)); | |
| 69 } | |
| 70 ~Bitmap() { | |
| 71 EXPECT_TRUE(DeleteObject(bitmap_)); | |
| 72 } | |
| 73 | |
| 74 private: | |
| 75 HBITMAP bitmap_; | |
| 76 | |
| 77 void* data_; | |
| 78 | |
| 79 DISALLOW_COPY_AND_ASSIGN(Bitmap); | |
| 80 }; | |
| 81 | |
| 82 // Lightweight raw-bitmap management. The image, once initialized, is immuable. | |
| 83 // It is mainly used for comparison. | |
| 84 class Image { | |
| 85 public: | |
| 86 // Creates the image from the given filename on disk. | |
| 87 explicit Image(const base::FilePath& filename) : ignore_alpha_(true) { | |
| 88 std::string compressed; | |
| 89 base::ReadFileToString(filename, &compressed); | |
| 90 EXPECT_TRUE(compressed.size()); | |
| 91 | |
| 92 SkBitmap bitmap; | |
| 93 EXPECT_TRUE(gfx::PNGCodec::Decode( | |
| 94 reinterpret_cast<const unsigned char*>(compressed.data()), | |
| 95 compressed.size(), &bitmap)); | |
| 96 SetSkBitmap(bitmap); | |
| 97 } | |
| 98 | |
| 99 // Loads the image from a canvas. | |
| 100 Image(skia::PlatformCanvas& canvas) : ignore_alpha_(true) { | |
| 101 // Use a different way to access the bitmap. The normal way would be to | |
| 102 // query the SkBitmap. | |
| 103 skia::ScopedPlatformPaint scoped_platform_paint(&canvas); | |
| 104 HDC context = scoped_platform_paint.GetPlatformSurface(); | |
| 105 HGDIOBJ bitmap = GetCurrentObject(context, OBJ_BITMAP); | |
| 106 EXPECT_TRUE(bitmap != NULL); | |
| 107 // Initialize the clip region to the entire bitmap. | |
| 108 BITMAP bitmap_data; | |
| 109 EXPECT_EQ(GetObject(bitmap, sizeof(BITMAP), &bitmap_data), sizeof(BITMAP)); | |
| 110 width_ = bitmap_data.bmWidth; | |
| 111 height_ = bitmap_data.bmHeight; | |
| 112 row_length_ = bitmap_data.bmWidthBytes; | |
| 113 size_t size = row_length_ * height_; | |
| 114 data_.resize(size); | |
| 115 memcpy(&*data_.begin(), bitmap_data.bmBits, size); | |
| 116 } | |
| 117 | |
| 118 // Loads the image from a canvas. | |
| 119 Image(const SkBitmap& bitmap) : ignore_alpha_(true) { | |
| 120 SetSkBitmap(bitmap); | |
| 121 } | |
| 122 | |
| 123 int width() const { return width_; } | |
| 124 int height() const { return height_; } | |
| 125 int row_length() const { return row_length_; } | |
| 126 | |
| 127 // Save the image to a png file. Used to create the initial test files. | |
| 128 void SaveToFile(const base::FilePath& filename) { | |
| 129 std::vector<unsigned char> compressed; | |
| 130 ASSERT_TRUE(gfx::PNGCodec::Encode(&*data_.begin(), | |
| 131 gfx::PNGCodec::FORMAT_BGRA, | |
| 132 gfx::Size(width_, height_), | |
| 133 row_length_, | |
| 134 true, | |
| 135 std::vector<gfx::PNGCodec::Comment>(), | |
| 136 &compressed)); | |
| 137 ASSERT_TRUE(compressed.size()); | |
| 138 FILE* f = base::OpenFile(filename, "wb"); | |
| 139 ASSERT_TRUE(f); | |
| 140 ASSERT_EQ(fwrite(&*compressed.begin(), 1, compressed.size(), f), | |
| 141 compressed.size()); | |
| 142 base::CloseFile(f); | |
| 143 } | |
| 144 | |
| 145 // Returns the percentage of the image that is different from the other, | |
| 146 // between 0 and 100. | |
| 147 double PercentageDifferent(const Image& rhs) const { | |
| 148 if (width_ != rhs.width_ || | |
| 149 height_ != rhs.height_ || | |
| 150 row_length_ != rhs.row_length_ || | |
| 151 width_ == 0 || | |
| 152 height_ == 0) { | |
| 153 return 100.; // When of different size or empty, they are 100% different. | |
| 154 } | |
| 155 // Compute pixels different in the overlap | |
| 156 int pixels_different = 0; | |
| 157 for (int y = 0; y < height_; ++y) { | |
| 158 for (int x = 0; x < width_; ++x) { | |
| 159 uint32_t lhs_pixel = pixel_at(x, y); | |
| 160 uint32_t rhs_pixel = rhs.pixel_at(x, y); | |
| 161 if (lhs_pixel != rhs_pixel) | |
| 162 ++pixels_different; | |
| 163 } | |
| 164 } | |
| 165 | |
| 166 // Like the WebKit ImageDiff tool, we define percentage different in terms | |
| 167 // of the size of the 'actual' bitmap. | |
| 168 double total_pixels = static_cast<double>(width_) * | |
| 169 static_cast<double>(height_); | |
| 170 return static_cast<double>(pixels_different) / total_pixels * 100.; | |
| 171 } | |
| 172 | |
| 173 // Returns the 0x0RGB or 0xARGB value of the pixel at the given location, | |
| 174 // depending on ignore_alpha_. | |
| 175 uint32 pixel_at(int x, int y) const { | |
| 176 EXPECT_TRUE(x >= 0 && x < width_); | |
| 177 EXPECT_TRUE(y >= 0 && y < height_); | |
| 178 const uint32* data = reinterpret_cast<const uint32*>(&*data_.begin()); | |
| 179 const uint32* data_row = data + y * row_length_ / sizeof(uint32); | |
| 180 if (ignore_alpha_) | |
| 181 return data_row[x] & 0xFFFFFF; // Strip out A. | |
| 182 else | |
| 183 return data_row[x]; | |
| 184 } | |
| 185 | |
| 186 protected: | |
| 187 void SetSkBitmap(const SkBitmap& bitmap) { | |
| 188 SkAutoLockPixels lock(bitmap); | |
| 189 width_ = bitmap.width(); | |
| 190 height_ = bitmap.height(); | |
| 191 row_length_ = static_cast<int>(bitmap.rowBytes()); | |
| 192 size_t size = row_length_ * height_; | |
| 193 data_.resize(size); | |
| 194 memcpy(&*data_.begin(), bitmap.getAddr(0, 0), size); | |
| 195 } | |
| 196 | |
| 197 private: | |
| 198 // Pixel dimensions of the image. | |
| 199 int width_; | |
| 200 int height_; | |
| 201 | |
| 202 // Length of a line in bytes. | |
| 203 int row_length_; | |
| 204 | |
| 205 // Actual bitmap data in arrays of RGBAs (so when loaded as uint32, it's | |
| 206 // 0xABGR). | |
| 207 std::vector<unsigned char> data_; | |
| 208 | |
| 209 // Flag to signal if the comparison functions should ignore the alpha channel. | |
| 210 const bool ignore_alpha_; | |
| 211 | |
| 212 DISALLOW_COPY_AND_ASSIGN(Image); | |
| 213 }; | |
| 214 | |
| 215 // Base for tests. Capability to process an image. | |
| 216 class ImageTest : public testing::Test { | |
| 217 public: | |
| 218 // In what state is the test running. | |
| 219 enum ProcessAction { | |
| 220 GENERATE, | |
| 221 COMPARE, | |
| 222 NOOP, | |
| 223 }; | |
| 224 | |
| 225 ImageTest(ProcessAction default_action) | |
| 226 : action_(default_action) { | |
| 227 } | |
| 228 | |
| 229 protected: | |
| 230 virtual void SetUp() { | |
| 231 const testing::TestInfo& test_info = | |
| 232 *testing::UnitTest::GetInstance()->current_test_info(); | |
| 233 PathService::Get(base::DIR_SOURCE_ROOT, &test_dir_); | |
| 234 test_dir_ = test_dir_.AppendASCII("skia"). | |
| 235 AppendASCII("ext"). | |
| 236 AppendASCII("data"). | |
| 237 AppendASCII(test_info.test_case_name()). | |
| 238 AppendASCII(test_info.name()); | |
| 239 | |
| 240 // Hack for a quick lowercase. We assume all the tests names are ASCII. | |
| 241 base::FilePath::StringType tmp(test_dir_.value()); | |
| 242 for (size_t i = 0; i < tmp.size(); ++i) | |
| 243 tmp[i] = base::ToLowerASCII(tmp[i]); | |
| 244 test_dir_ = base::FilePath(tmp); | |
| 245 | |
| 246 if (action_ == GENERATE) { | |
| 247 // Make sure the directory exist. | |
| 248 base::CreateDirectory(test_dir_); | |
| 249 } | |
| 250 } | |
| 251 | |
| 252 // Returns the fully qualified path of a data file. | |
| 253 base::FilePath test_file(const base::FilePath::StringType& filename) const { | |
| 254 // Hack for a quick lowercase. We assume all the test data file names are | |
| 255 // ASCII. | |
| 256 #if defined(OS_WIN) | |
| 257 std::string tmp = base::UTF16ToASCII(filename); | |
| 258 #else | |
| 259 std::string tmp(filename); | |
| 260 #endif | |
| 261 for (size_t i = 0; i < tmp.size(); ++i) | |
| 262 tmp[i] = base::ToLowerASCII(tmp[i]); | |
| 263 | |
| 264 return test_dir_.AppendASCII(tmp); | |
| 265 } | |
| 266 | |
| 267 // Compares or saves the bitmap currently loaded in the context, depending on | |
| 268 // kGenerating value. Returns 0 on success or any positive value between ]0, | |
| 269 // 100] on failure. The return value is the percentage of difference between | |
| 270 // the image in the file and the image in the canvas. | |
| 271 double ProcessCanvas(skia::PlatformCanvas& canvas, | |
| 272 base::FilePath::StringType filename) const { | |
| 273 filename = filename + FILE_PATH_LITERAL(".png"); | |
| 274 switch (action_) { | |
| 275 case GENERATE: | |
| 276 SaveImage(canvas, filename); | |
| 277 return 0.; | |
| 278 case COMPARE: | |
| 279 return CompareImage(canvas, filename); | |
| 280 case NOOP: | |
| 281 return 0; | |
| 282 default: | |
| 283 // Invalid state, returns that the image is 100 different. | |
| 284 return 100.; | |
| 285 } | |
| 286 } | |
| 287 | |
| 288 // Compares the bitmap currently loaded in the context with the file. Returns | |
| 289 // the percentage of pixel difference between both images, between 0 and 100. | |
| 290 double CompareImage(skia::PlatformCanvas& canvas, | |
| 291 const base::FilePath::StringType& filename) const { | |
| 292 Image image1(canvas); | |
| 293 Image image2(test_file(filename)); | |
| 294 double diff = image1.PercentageDifferent(image2); | |
| 295 return diff; | |
| 296 } | |
| 297 | |
| 298 // Saves the bitmap currently loaded in the context into the file. | |
| 299 void SaveImage(skia::PlatformCanvas& canvas, | |
| 300 const base::FilePath::StringType& filename) const { | |
| 301 Image(canvas).SaveToFile(test_file(filename)); | |
| 302 } | |
| 303 | |
| 304 ProcessAction action_; | |
| 305 | |
| 306 // Path to directory used to contain the test data. | |
| 307 base::FilePath test_dir_; | |
| 308 | |
| 309 DISALLOW_COPY_AND_ASSIGN(ImageTest); | |
| 310 }; | |
| 311 | |
| 312 // Premultiply the Alpha channel on the R, B and G channels. | |
| 313 void Premultiply(SkBitmap bitmap) { | |
| 314 SkAutoLockPixels lock(bitmap); | |
| 315 for (int x = 0; x < bitmap.width(); ++x) { | |
| 316 for (int y = 0; y < bitmap.height(); ++y) { | |
| 317 uint32_t* pixel_addr = bitmap.getAddr32(x, y); | |
| 318 uint32_t color = *pixel_addr; | |
| 319 BYTE alpha = SkColorGetA(color); | |
| 320 if (!alpha) { | |
| 321 *pixel_addr = 0; | |
| 322 } else { | |
| 323 BYTE alpha_offset = alpha / 2; | |
| 324 *pixel_addr = SkColorSetARGB( | |
| 325 SkColorGetA(color), | |
| 326 (SkColorGetR(color) * 255 + alpha_offset) / alpha, | |
| 327 (SkColorGetG(color) * 255 + alpha_offset) / alpha, | |
| 328 (SkColorGetB(color) * 255 + alpha_offset) / alpha); | |
| 329 } | |
| 330 } | |
| 331 } | |
| 332 } | |
| 333 | |
| 334 void LoadPngFileToSkBitmap(const base::FilePath& filename, | |
| 335 SkBitmap* bitmap, | |
| 336 bool is_opaque) { | |
| 337 std::string compressed; | |
| 338 base::ReadFileToString(base::MakeAbsoluteFilePath(filename), &compressed); | |
| 339 ASSERT_TRUE(compressed.size()); | |
| 340 | |
| 341 ASSERT_TRUE(gfx::PNGCodec::Decode( | |
| 342 reinterpret_cast<const unsigned char*>(compressed.data()), | |
| 343 compressed.size(), bitmap)); | |
| 344 | |
| 345 EXPECT_EQ(is_opaque, bitmap->isOpaque()); | |
| 346 Premultiply(*bitmap); | |
| 347 } | |
| 348 | |
| 349 } // namespace | |
| 350 | |
| 351 // Streams an image. | |
| 352 inline std::ostream& operator<<(std::ostream& out, const Image& image) { | |
| 353 return out << "Image(" << image.width() << ", " | |
| 354 << image.height() << ", " << image.row_length() << ")"; | |
| 355 } | |
| 356 | |
| 357 // Runs simultaneously the same drawing commands on VectorCanvas and | |
| 358 // PlatformCanvas and compare the results. | |
| 359 class VectorCanvasTest : public ImageTest { | |
| 360 public: | |
| 361 typedef ImageTest parent; | |
| 362 | |
| 363 VectorCanvasTest() : parent(CurrentMode()), compare_canvas_(true) { | |
| 364 } | |
| 365 | |
| 366 protected: | |
| 367 virtual void SetUp() { | |
| 368 parent::SetUp(); | |
| 369 Init(100); | |
| 370 number_ = 0; | |
| 371 } | |
| 372 | |
| 373 virtual void TearDown() { | |
| 374 delete pcanvas_; | |
| 375 pcanvas_ = NULL; | |
| 376 | |
| 377 delete vcanvas_; | |
| 378 vcanvas_ = NULL; | |
| 379 | |
| 380 delete bitmap_; | |
| 381 bitmap_ = NULL; | |
| 382 | |
| 383 delete context_; | |
| 384 context_ = NULL; | |
| 385 | |
| 386 parent::TearDown(); | |
| 387 } | |
| 388 | |
| 389 void Init(int size) { | |
| 390 size_ = size; | |
| 391 context_ = new Context(); | |
| 392 bitmap_ = new Bitmap(*context_, size_, size_); | |
| 393 vcanvas_ = new VectorCanvas( | |
| 394 VectorPlatformDeviceEmf::CreateDevice( | |
| 395 size_, size_, true, context_->context())); | |
| 396 pcanvas_ = CreatePlatformCanvas(size_, size_, false); | |
| 397 | |
| 398 // Clear white. | |
| 399 vcanvas_->drawARGB(255, 255, 255, 255, SkXfermode::kSrc_Mode); | |
| 400 pcanvas_->drawARGB(255, 255, 255, 255, SkXfermode::kSrc_Mode); | |
| 401 } | |
| 402 | |
| 403 // Compares both canvas and returns the pixel difference in percentage between | |
| 404 // both images. 0 on success and ]0, 100] on failure. | |
| 405 double ProcessImage(const base::FilePath::StringType& filename) { | |
| 406 std::wstring number(base::StringPrintf(L"%02d_", number_++)); | |
| 407 double diff1 = parent::ProcessCanvas(*vcanvas_, number + L"vc_" + filename); | |
| 408 double diff2 = parent::ProcessCanvas(*pcanvas_, number + L"pc_" + filename); | |
| 409 if (!compare_canvas_) | |
| 410 return std::max(diff1, diff2); | |
| 411 | |
| 412 Image image1(*vcanvas_); | |
| 413 Image image2(*pcanvas_); | |
| 414 double diff = image1.PercentageDifferent(image2); | |
| 415 return std::max(std::max(diff1, diff2), diff); | |
| 416 } | |
| 417 | |
| 418 // Returns COMPARE, which is the default. If kGenerateSwitch command | |
| 419 // line argument is used to start this process, GENERATE is returned instead. | |
| 420 static ProcessAction CurrentMode() { | |
| 421 return base::CommandLine::ForCurrentProcess()->HasSwitch(kGenerateSwitch) | |
| 422 ? GENERATE | |
| 423 : COMPARE; | |
| 424 } | |
| 425 | |
| 426 // Length in x and y of the square canvas. | |
| 427 int size_; | |
| 428 | |
| 429 // Current image number in the current test. Used to number of test files. | |
| 430 int number_; | |
| 431 | |
| 432 // A temporary HDC to draw into. | |
| 433 Context* context_; | |
| 434 | |
| 435 // Bitmap created inside context_. | |
| 436 Bitmap* bitmap_; | |
| 437 | |
| 438 // Vector based canvas. | |
| 439 VectorCanvas* vcanvas_; | |
| 440 | |
| 441 // Pixel based canvas. | |
| 442 PlatformCanvas* pcanvas_; | |
| 443 | |
| 444 // When true (default), vcanvas_ and pcanvas_ contents are compared and | |
| 445 // verified to be identical. | |
| 446 bool compare_canvas_; | |
| 447 }; | |
| 448 | |
| 449 | |
| 450 //////////////////////////////////////////////////////////////////////////////// | |
| 451 // Actual tests | |
| 452 | |
| 453 #if !defined(USE_AURA) // http://crbug.com/154358 | |
| 454 | |
| 455 TEST_F(VectorCanvasTest, BasicDrawing) { | |
| 456 EXPECT_EQ(Image(*vcanvas_).PercentageDifferent(Image(*pcanvas_)), 0.) | |
| 457 << L"clean"; | |
| 458 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("clean"))); | |
| 459 | |
| 460 // Clear white. | |
| 461 { | |
| 462 vcanvas_->drawARGB(255, 255, 255, 255, SkXfermode::kSrc_Mode); | |
| 463 pcanvas_->drawARGB(255, 255, 255, 255, SkXfermode::kSrc_Mode); | |
| 464 } | |
| 465 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("drawARGB"))); | |
| 466 | |
| 467 // Diagonal line top-left to bottom-right. | |
| 468 { | |
| 469 SkPaint paint; | |
| 470 // Default color is black. | |
| 471 vcanvas_->drawLine(10, 10, 90, 90, paint); | |
| 472 pcanvas_->drawLine(10, 10, 90, 90, paint); | |
| 473 } | |
| 474 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("drawLine_black"))); | |
| 475 | |
| 476 // Rect. | |
| 477 { | |
| 478 SkPaint paint; | |
| 479 paint.setColor(SK_ColorGREEN); | |
| 480 vcanvas_->drawRectCoords(25, 25, 75, 75, paint); | |
| 481 pcanvas_->drawRectCoords(25, 25, 75, 75, paint); | |
| 482 } | |
| 483 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("drawRect_green"))); | |
| 484 | |
| 485 // A single-point rect doesn't leave any mark. | |
| 486 { | |
| 487 SkPaint paint; | |
| 488 paint.setColor(SK_ColorBLUE); | |
| 489 vcanvas_->drawRectCoords(5, 5, 5, 5, paint); | |
| 490 pcanvas_->drawRectCoords(5, 5, 5, 5, paint); | |
| 491 } | |
| 492 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("drawRect_noop"))); | |
| 493 | |
| 494 // Rect. | |
| 495 { | |
| 496 SkPaint paint; | |
| 497 paint.setColor(SK_ColorBLUE); | |
| 498 vcanvas_->drawRectCoords(75, 50, 80, 55, paint); | |
| 499 pcanvas_->drawRectCoords(75, 50, 80, 55, paint); | |
| 500 } | |
| 501 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("drawRect_noop"))); | |
| 502 | |
| 503 // Empty again | |
| 504 { | |
| 505 vcanvas_->drawPaint(SkPaint()); | |
| 506 pcanvas_->drawPaint(SkPaint()); | |
| 507 } | |
| 508 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("drawPaint_black"))); | |
| 509 | |
| 510 // Horizontal line left to right. | |
| 511 { | |
| 512 SkPaint paint; | |
| 513 paint.setColor(SK_ColorRED); | |
| 514 vcanvas_->drawLine(10, 20, 90, 20, paint); | |
| 515 pcanvas_->drawLine(10, 20, 90, 20, paint); | |
| 516 } | |
| 517 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("drawLine_left_to_right"))); | |
| 518 | |
| 519 // Vertical line downward. | |
| 520 { | |
| 521 SkPaint paint; | |
| 522 paint.setColor(SK_ColorRED); | |
| 523 vcanvas_->drawLine(30, 10, 30, 90, paint); | |
| 524 pcanvas_->drawLine(30, 10, 30, 90, paint); | |
| 525 } | |
| 526 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("drawLine_red"))); | |
| 527 } | |
| 528 | |
| 529 TEST_F(VectorCanvasTest, Circles) { | |
| 530 // There is NO WAY to make them agree. At least verify that the output doesn't | |
| 531 // change across versions. This test is disabled. See bug 1060231. | |
| 532 compare_canvas_ = false; | |
| 533 | |
| 534 // Stroked Circle. | |
| 535 { | |
| 536 SkPaint paint; | |
| 537 SkPath path; | |
| 538 path.addCircle(50, 75, 10); | |
| 539 paint.setStyle(SkPaint::kStroke_Style); | |
| 540 paint.setColor(SK_ColorMAGENTA); | |
| 541 vcanvas_->drawPath(path, paint); | |
| 542 pcanvas_->drawPath(path, paint); | |
| 543 } | |
| 544 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("circle_stroke"))); | |
| 545 | |
| 546 // Filled Circle. | |
| 547 { | |
| 548 SkPaint paint; | |
| 549 SkPath path; | |
| 550 path.addCircle(50, 25, 10); | |
| 551 paint.setStyle(SkPaint::kFill_Style); | |
| 552 vcanvas_->drawPath(path, paint); | |
| 553 pcanvas_->drawPath(path, paint); | |
| 554 } | |
| 555 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("circle_fill"))); | |
| 556 | |
| 557 // Stroked Circle over. | |
| 558 { | |
| 559 SkPaint paint; | |
| 560 SkPath path; | |
| 561 path.addCircle(50, 25, 10); | |
| 562 paint.setStyle(SkPaint::kStroke_Style); | |
| 563 paint.setColor(SK_ColorBLUE); | |
| 564 vcanvas_->drawPath(path, paint); | |
| 565 pcanvas_->drawPath(path, paint); | |
| 566 } | |
| 567 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("circle_over_strike"))); | |
| 568 | |
| 569 // Stroke and Fill Circle. | |
| 570 { | |
| 571 SkPaint paint; | |
| 572 SkPath path; | |
| 573 path.addCircle(12, 50, 10); | |
| 574 paint.setStyle(SkPaint::kStrokeAndFill_Style); | |
| 575 paint.setColor(SK_ColorRED); | |
| 576 vcanvas_->drawPath(path, paint); | |
| 577 pcanvas_->drawPath(path, paint); | |
| 578 } | |
| 579 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("circle_stroke_and_fill"))); | |
| 580 | |
| 581 // Line + Quad + Cubic. | |
| 582 { | |
| 583 SkPaint paint; | |
| 584 SkPath path; | |
| 585 paint.setStyle(SkPaint::kStroke_Style); | |
| 586 paint.setColor(SK_ColorGREEN); | |
| 587 path.moveTo(1, 1); | |
| 588 path.lineTo(60, 40); | |
| 589 path.lineTo(80, 80); | |
| 590 path.quadTo(20, 50, 10, 90); | |
| 591 path.quadTo(50, 20, 90, 10); | |
| 592 path.cubicTo(20, 40, 50, 50, 10, 10); | |
| 593 path.cubicTo(30, 20, 50, 50, 90, 10); | |
| 594 path.addRect(90, 90, 95, 96); | |
| 595 vcanvas_->drawPath(path, paint); | |
| 596 pcanvas_->drawPath(path, paint); | |
| 597 } | |
| 598 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("mixed_stroke"))); | |
| 599 } | |
| 600 | |
| 601 TEST_F(VectorCanvasTest, LineOrientation) { | |
| 602 // There is NO WAY to make them agree. At least verify that the output doesn't | |
| 603 // change across versions. This test is disabled. See bug 1060231. | |
| 604 compare_canvas_ = false; | |
| 605 | |
| 606 // Horizontal lines. | |
| 607 { | |
| 608 SkPaint paint; | |
| 609 paint.setColor(SK_ColorRED); | |
| 610 // Left to right. | |
| 611 vcanvas_->drawLine(10, 20, 90, 20, paint); | |
| 612 pcanvas_->drawLine(10, 20, 90, 20, paint); | |
| 613 // Right to left. | |
| 614 vcanvas_->drawLine(90, 30, 10, 30, paint); | |
| 615 pcanvas_->drawLine(90, 30, 10, 30, paint); | |
| 616 } | |
| 617 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("horizontal"))); | |
| 618 | |
| 619 // Vertical lines. | |
| 620 { | |
| 621 SkPaint paint; | |
| 622 paint.setColor(SK_ColorRED); | |
| 623 // Top down. | |
| 624 vcanvas_->drawLine(20, 10, 20, 90, paint); | |
| 625 pcanvas_->drawLine(20, 10, 20, 90, paint); | |
| 626 // Bottom up. | |
| 627 vcanvas_->drawLine(30, 90, 30, 10, paint); | |
| 628 pcanvas_->drawLine(30, 90, 30, 10, paint); | |
| 629 } | |
| 630 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("vertical"))); | |
| 631 | |
| 632 // Try again with a 180 degres rotation. | |
| 633 vcanvas_->rotate(180); | |
| 634 pcanvas_->rotate(180); | |
| 635 | |
| 636 // Horizontal lines (rotated). | |
| 637 { | |
| 638 SkPaint paint; | |
| 639 paint.setColor(SK_ColorRED); | |
| 640 vcanvas_->drawLine(-10, -25, -90, -25, paint); | |
| 641 pcanvas_->drawLine(-10, -25, -90, -25, paint); | |
| 642 vcanvas_->drawLine(-90, -35, -10, -35, paint); | |
| 643 pcanvas_->drawLine(-90, -35, -10, -35, paint); | |
| 644 } | |
| 645 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("horizontal_180"))); | |
| 646 | |
| 647 // Vertical lines (rotated). | |
| 648 { | |
| 649 SkPaint paint; | |
| 650 paint.setColor(SK_ColorRED); | |
| 651 vcanvas_->drawLine(-25, -10, -25, -90, paint); | |
| 652 pcanvas_->drawLine(-25, -10, -25, -90, paint); | |
| 653 vcanvas_->drawLine(-35, -90, -35, -10, paint); | |
| 654 pcanvas_->drawLine(-35, -90, -35, -10, paint); | |
| 655 } | |
| 656 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("vertical_180"))); | |
| 657 } | |
| 658 | |
| 659 TEST_F(VectorCanvasTest, PathOrientation) { | |
| 660 // There is NO WAY to make them agree. At least verify that the output doesn't | |
| 661 // change across versions. This test is disabled. See bug 1060231. | |
| 662 compare_canvas_ = false; | |
| 663 | |
| 664 // Horizontal lines. | |
| 665 { | |
| 666 SkPaint paint; | |
| 667 paint.setStyle(SkPaint::kStroke_Style); | |
| 668 paint.setColor(SK_ColorRED); | |
| 669 SkPath path; | |
| 670 SkPoint start; | |
| 671 start.set(10, 20); | |
| 672 SkPoint end; | |
| 673 end.set(90, 20); | |
| 674 path.moveTo(start); | |
| 675 path.lineTo(end); | |
| 676 vcanvas_->drawPath(path, paint); | |
| 677 pcanvas_->drawPath(path, paint); | |
| 678 } | |
| 679 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("drawPath_ltr"))); | |
| 680 | |
| 681 // Horizontal lines. | |
| 682 { | |
| 683 SkPaint paint; | |
| 684 paint.setStyle(SkPaint::kStroke_Style); | |
| 685 paint.setColor(SK_ColorRED); | |
| 686 SkPath path; | |
| 687 SkPoint start; | |
| 688 start.set(90, 30); | |
| 689 SkPoint end; | |
| 690 end.set(10, 30); | |
| 691 path.moveTo(start); | |
| 692 path.lineTo(end); | |
| 693 vcanvas_->drawPath(path, paint); | |
| 694 pcanvas_->drawPath(path, paint); | |
| 695 } | |
| 696 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("drawPath_rtl"))); | |
| 697 } | |
| 698 | |
| 699 TEST_F(VectorCanvasTest, DiagonalLines) { | |
| 700 SkPaint paint; | |
| 701 paint.setColor(SK_ColorRED); | |
| 702 | |
| 703 vcanvas_->drawLine(10, 10, 90, 90, paint); | |
| 704 pcanvas_->drawLine(10, 10, 90, 90, paint); | |
| 705 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("nw-se"))); | |
| 706 | |
| 707 // Starting here, there is NO WAY to make them agree. At least verify that the | |
| 708 // output doesn't change across versions. This test is disabled. See bug | |
| 709 // 1060231. | |
| 710 compare_canvas_ = false; | |
| 711 | |
| 712 vcanvas_->drawLine(10, 95, 90, 15, paint); | |
| 713 pcanvas_->drawLine(10, 95, 90, 15, paint); | |
| 714 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("sw-ne"))); | |
| 715 | |
| 716 vcanvas_->drawLine(90, 10, 10, 90, paint); | |
| 717 pcanvas_->drawLine(90, 10, 10, 90, paint); | |
| 718 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("ne-sw"))); | |
| 719 | |
| 720 vcanvas_->drawLine(95, 90, 15, 10, paint); | |
| 721 pcanvas_->drawLine(95, 90, 15, 10, paint); | |
| 722 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("se-nw"))); | |
| 723 } | |
| 724 | |
| 725 #if defined(OS_WIN) | |
| 726 #define MAYBE_PathEffects DISABLED_PathEffects | |
| 727 #else | |
| 728 #define MAYBE_PathEffects PathEffects | |
| 729 #endif | |
| 730 TEST_F(VectorCanvasTest, MAYBE_PathEffects) { | |
| 731 { | |
| 732 SkPaint paint; | |
| 733 SkScalar intervals[] = { 1, 1 }; | |
| 734 skia::RefPtr<SkPathEffect> effect = skia::AdoptRef( | |
| 735 new SkDashPathEffect(intervals, arraysize(intervals), 0)); | |
| 736 paint.setPathEffect(effect.get()); | |
| 737 paint.setColor(SK_ColorMAGENTA); | |
| 738 paint.setStyle(SkPaint::kStroke_Style); | |
| 739 | |
| 740 vcanvas_->drawLine(10, 10, 90, 10, paint); | |
| 741 pcanvas_->drawLine(10, 10, 90, 10, paint); | |
| 742 } | |
| 743 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("dash_line"))); | |
| 744 | |
| 745 | |
| 746 // Starting here, there is NO WAY to make them agree. At least verify that the | |
| 747 // output doesn't change across versions. This test is disabled. See bug | |
| 748 // 1060231. | |
| 749 compare_canvas_ = false; | |
| 750 | |
| 751 { | |
| 752 SkPaint paint; | |
| 753 SkScalar intervals[] = { 3, 5 }; | |
| 754 skia::RefPtr<SkPathEffect> effect = skia::AdoptRef( | |
| 755 new SkDashPathEffect(intervals, arraysize(intervals), 0)); | |
| 756 paint.setPathEffect(effect.get()); | |
| 757 paint.setColor(SK_ColorMAGENTA); | |
| 758 paint.setStyle(SkPaint::kStroke_Style); | |
| 759 | |
| 760 SkPath path; | |
| 761 path.moveTo(10, 15); | |
| 762 path.lineTo(90, 15); | |
| 763 path.lineTo(90, 90); | |
| 764 vcanvas_->drawPath(path, paint); | |
| 765 pcanvas_->drawPath(path, paint); | |
| 766 } | |
| 767 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("dash_path"))); | |
| 768 | |
| 769 { | |
| 770 SkPaint paint; | |
| 771 SkScalar intervals[] = { 2, 1 }; | |
| 772 skia::RefPtr<SkPathEffect> effect = skia::AdoptRef( | |
| 773 new SkDashPathEffect(intervals, arraysize(intervals), 0)); | |
| 774 paint.setPathEffect(effect.get()); | |
| 775 paint.setColor(SK_ColorMAGENTA); | |
| 776 paint.setStyle(SkPaint::kStroke_Style); | |
| 777 | |
| 778 vcanvas_->drawRectCoords(20, 20, 30, 30, paint); | |
| 779 pcanvas_->drawRectCoords(20, 20, 30, 30, paint); | |
| 780 } | |
| 781 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("dash_rect"))); | |
| 782 | |
| 783 // This thing looks like it has been drawn by a 3 years old kid. I haven't | |
| 784 // filed a bug on this since I guess nobody is expecting this to look nice. | |
| 785 { | |
| 786 SkPaint paint; | |
| 787 SkScalar intervals[] = { 1, 1 }; | |
| 788 skia::RefPtr<SkPathEffect> effect = skia::AdoptRef( | |
| 789 new SkDashPathEffect(intervals, arraysize(intervals), 0)); | |
| 790 paint.setPathEffect(effect.get()); | |
| 791 paint.setColor(SK_ColorMAGENTA); | |
| 792 paint.setStyle(SkPaint::kStroke_Style); | |
| 793 | |
| 794 SkPath path; | |
| 795 path.addCircle(50, 75, 10); | |
| 796 vcanvas_->drawPath(path, paint); | |
| 797 pcanvas_->drawPath(path, paint); | |
| 798 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("circle"))); | |
| 799 } | |
| 800 } | |
| 801 | |
| 802 TEST_F(VectorCanvasTest, Bitmaps) { | |
| 803 { | |
| 804 SkBitmap bitmap; | |
| 805 LoadPngFileToSkBitmap(test_file(L"bitmap_opaque.png"), &bitmap, true); | |
| 806 vcanvas_->drawBitmap(bitmap, 13, 3, NULL); | |
| 807 pcanvas_->drawBitmap(bitmap, 13, 3, NULL); | |
| 808 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("opaque"))); | |
| 809 } | |
| 810 | |
| 811 { | |
| 812 SkBitmap bitmap; | |
| 813 LoadPngFileToSkBitmap(test_file(L"bitmap_alpha.png"), &bitmap, false); | |
| 814 vcanvas_->drawBitmap(bitmap, 5, 15, NULL); | |
| 815 pcanvas_->drawBitmap(bitmap, 5, 15, NULL); | |
| 816 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("alpha"))); | |
| 817 } | |
| 818 } | |
| 819 | |
| 820 TEST_F(VectorCanvasTest, ClippingRect) { | |
| 821 SkBitmap bitmap; | |
| 822 LoadPngFileToSkBitmap(test_file(L"..\\bitmaps\\bitmap_opaque.png"), &bitmap, | |
| 823 true); | |
| 824 SkRect rect; | |
| 825 rect.fLeft = 2; | |
| 826 rect.fTop = 2; | |
| 827 rect.fRight = 30.5f; | |
| 828 rect.fBottom = 30.5f; | |
| 829 vcanvas_->clipRect(rect); | |
| 830 pcanvas_->clipRect(rect); | |
| 831 | |
| 832 vcanvas_->drawBitmap(bitmap, 13, 3, NULL); | |
| 833 pcanvas_->drawBitmap(bitmap, 13, 3, NULL); | |
| 834 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("rect"))); | |
| 835 } | |
| 836 | |
| 837 TEST_F(VectorCanvasTest, ClippingPath) { | |
| 838 SkBitmap bitmap; | |
| 839 LoadPngFileToSkBitmap(test_file(L"..\\bitmaps\\bitmap_opaque.png"), &bitmap, | |
| 840 true); | |
| 841 SkPath path; | |
| 842 path.addCircle(20, 20, 10); | |
| 843 vcanvas_->clipPath(path); | |
| 844 pcanvas_->clipPath(path); | |
| 845 | |
| 846 vcanvas_->drawBitmap(bitmap, 14, 3, NULL); | |
| 847 pcanvas_->drawBitmap(bitmap, 14, 3, NULL); | |
| 848 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("path"))); | |
| 849 } | |
| 850 | |
| 851 TEST_F(VectorCanvasTest, ClippingCombined) { | |
| 852 SkBitmap bitmap; | |
| 853 LoadPngFileToSkBitmap(test_file(L"..\\bitmaps\\bitmap_opaque.png"), &bitmap, | |
| 854 true); | |
| 855 | |
| 856 SkRect rect; | |
| 857 rect.fLeft = 2; | |
| 858 rect.fTop = 2; | |
| 859 rect.fRight = 30.5f; | |
| 860 rect.fBottom = 30.5f; | |
| 861 vcanvas_->clipRect(rect); | |
| 862 pcanvas_->clipRect(rect); | |
| 863 SkPath path; | |
| 864 path.addCircle(20, 20, 10); | |
| 865 vcanvas_->clipPath(path, SkRegion::kUnion_Op); | |
| 866 pcanvas_->clipPath(path, SkRegion::kUnion_Op); | |
| 867 | |
| 868 vcanvas_->drawBitmap(bitmap, 15, 3, NULL); | |
| 869 pcanvas_->drawBitmap(bitmap, 15, 3, NULL); | |
| 870 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("combined"))); | |
| 871 } | |
| 872 | |
| 873 TEST_F(VectorCanvasTest, ClippingIntersect) { | |
| 874 SkBitmap bitmap; | |
| 875 LoadPngFileToSkBitmap(test_file(L"..\\bitmaps\\bitmap_opaque.png"), &bitmap, | |
| 876 true); | |
| 877 | |
| 878 SkRect rect; | |
| 879 rect.fLeft = 2; | |
| 880 rect.fTop = 2; | |
| 881 rect.fRight = 30.5f; | |
| 882 rect.fBottom = 30.5f; | |
| 883 vcanvas_->clipRect(rect); | |
| 884 pcanvas_->clipRect(rect); | |
| 885 SkPath path; | |
| 886 path.addCircle(23, 23, 15); | |
| 887 vcanvas_->clipPath(path); | |
| 888 pcanvas_->clipPath(path); | |
| 889 | |
| 890 vcanvas_->drawBitmap(bitmap, 15, 3, NULL); | |
| 891 pcanvas_->drawBitmap(bitmap, 15, 3, NULL); | |
| 892 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("intersect"))); | |
| 893 } | |
| 894 | |
| 895 TEST_F(VectorCanvasTest, ClippingClean) { | |
| 896 SkBitmap bitmap; | |
| 897 LoadPngFileToSkBitmap(test_file(L"..\\bitmaps\\bitmap_opaque.png"), &bitmap, | |
| 898 true); | |
| 899 { | |
| 900 SkAutoCanvasRestore acrv(vcanvas_, true); | |
| 901 SkAutoCanvasRestore acrp(pcanvas_, true); | |
| 902 SkRect rect; | |
| 903 rect.fLeft = 2; | |
| 904 rect.fTop = 2; | |
| 905 rect.fRight = 30.5f; | |
| 906 rect.fBottom = 30.5f; | |
| 907 vcanvas_->clipRect(rect); | |
| 908 pcanvas_->clipRect(rect); | |
| 909 | |
| 910 vcanvas_->drawBitmap(bitmap, 15, 3, NULL); | |
| 911 pcanvas_->drawBitmap(bitmap, 15, 3, NULL); | |
| 912 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("clipped"))); | |
| 913 } | |
| 914 { | |
| 915 // Verify that the clipping region has been fixed back. | |
| 916 vcanvas_->drawBitmap(bitmap, 55, 3, NULL); | |
| 917 pcanvas_->drawBitmap(bitmap, 55, 3, NULL); | |
| 918 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("unclipped"))); | |
| 919 } | |
| 920 } | |
| 921 | |
| 922 // See http://crbug.com/26938 | |
| 923 TEST_F(VectorCanvasTest, DISABLED_Matrix) { | |
| 924 SkBitmap bitmap; | |
| 925 LoadPngFileToSkBitmap(test_file(L"..\\bitmaps\\bitmap_opaque.png"), &bitmap, | |
| 926 true); | |
| 927 { | |
| 928 vcanvas_->translate(15, 3); | |
| 929 pcanvas_->translate(15, 3); | |
| 930 vcanvas_->drawBitmap(bitmap, 0, 0, NULL); | |
| 931 pcanvas_->drawBitmap(bitmap, 0, 0, NULL); | |
| 932 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("translate1"))); | |
| 933 } | |
| 934 { | |
| 935 vcanvas_->translate(-30, -23); | |
| 936 pcanvas_->translate(-30, -23); | |
| 937 vcanvas_->drawBitmap(bitmap, 0, 0, NULL); | |
| 938 pcanvas_->drawBitmap(bitmap, 0, 0, NULL); | |
| 939 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("translate2"))); | |
| 940 } | |
| 941 vcanvas_->resetMatrix(); | |
| 942 pcanvas_->resetMatrix(); | |
| 943 | |
| 944 // For scaling and rotation, they use a different algorithm (nearest | |
| 945 // neighborhood vs smoothing). At least verify that the output doesn't change | |
| 946 // across versions. | |
| 947 compare_canvas_ = false; | |
| 948 | |
| 949 { | |
| 950 vcanvas_->scale(SkDoubleToScalar(1.9), SkDoubleToScalar(1.5)); | |
| 951 pcanvas_->scale(SkDoubleToScalar(1.9), SkDoubleToScalar(1.5)); | |
| 952 vcanvas_->drawBitmap(bitmap, 1, 1, NULL); | |
| 953 pcanvas_->drawBitmap(bitmap, 1, 1, NULL); | |
| 954 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("scale"))); | |
| 955 } | |
| 956 vcanvas_->resetMatrix(); | |
| 957 pcanvas_->resetMatrix(); | |
| 958 | |
| 959 { | |
| 960 vcanvas_->rotate(67); | |
| 961 pcanvas_->rotate(67); | |
| 962 vcanvas_->drawBitmap(bitmap, 20, -50, NULL); | |
| 963 pcanvas_->drawBitmap(bitmap, 20, -50, NULL); | |
| 964 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("rotate"))); | |
| 965 } | |
| 966 } | |
| 967 | |
| 968 #endif // !defined(USE_AURA) | |
| 969 | |
| 970 } // namespace skia | |
| OLD | NEW |