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/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/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 CommandLine::ForCurrentProcess()->HasSwitch(kGenerateSwitch) ? 422 GENERATE : COMPARE; 423 } 424 425 // Length in x and y of the square canvas. 426 int size_; 427 428 // Current image number in the current test. Used to number of test files. 429 int number_; 430 431 // A temporary HDC to draw into. 432 Context* context_; 433 434 // Bitmap created inside context_. 435 Bitmap* bitmap_; 436 437 // Vector based canvas. 438 VectorCanvas* vcanvas_; 439 440 // Pixel based canvas. 441 PlatformCanvas* pcanvas_; 442 443 // When true (default), vcanvas_ and pcanvas_ contents are compared and 444 // verified to be identical. 445 bool compare_canvas_; 446 }; 447 448 449 //////////////////////////////////////////////////////////////////////////////// 450 // Actual tests 451 452 #if !defined(USE_AURA) // http://crbug.com/154358 453 454 TEST_F(VectorCanvasTest, BasicDrawing) { 455 EXPECT_EQ(Image(*vcanvas_).PercentageDifferent(Image(*pcanvas_)), 0.) 456 << L"clean"; 457 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("clean"))); 458 459 // Clear white. 460 { 461 vcanvas_->drawARGB(255, 255, 255, 255, SkXfermode::kSrc_Mode); 462 pcanvas_->drawARGB(255, 255, 255, 255, SkXfermode::kSrc_Mode); 463 } 464 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("drawARGB"))); 465 466 // Diagonal line top-left to bottom-right. 467 { 468 SkPaint paint; 469 // Default color is black. 470 vcanvas_->drawLine(10, 10, 90, 90, paint); 471 pcanvas_->drawLine(10, 10, 90, 90, paint); 472 } 473 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("drawLine_black"))); 474 475 // Rect. 476 { 477 SkPaint paint; 478 paint.setColor(SK_ColorGREEN); 479 vcanvas_->drawRectCoords(25, 25, 75, 75, paint); 480 pcanvas_->drawRectCoords(25, 25, 75, 75, paint); 481 } 482 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("drawRect_green"))); 483 484 // A single-point rect doesn't leave any mark. 485 { 486 SkPaint paint; 487 paint.setColor(SK_ColorBLUE); 488 vcanvas_->drawRectCoords(5, 5, 5, 5, paint); 489 pcanvas_->drawRectCoords(5, 5, 5, 5, paint); 490 } 491 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("drawRect_noop"))); 492 493 // Rect. 494 { 495 SkPaint paint; 496 paint.setColor(SK_ColorBLUE); 497 vcanvas_->drawRectCoords(75, 50, 80, 55, paint); 498 pcanvas_->drawRectCoords(75, 50, 80, 55, paint); 499 } 500 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("drawRect_noop"))); 501 502 // Empty again 503 { 504 vcanvas_->drawPaint(SkPaint()); 505 pcanvas_->drawPaint(SkPaint()); 506 } 507 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("drawPaint_black"))); 508 509 // Horizontal line left to right. 510 { 511 SkPaint paint; 512 paint.setColor(SK_ColorRED); 513 vcanvas_->drawLine(10, 20, 90, 20, paint); 514 pcanvas_->drawLine(10, 20, 90, 20, paint); 515 } 516 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("drawLine_left_to_right"))); 517 518 // Vertical line downward. 519 { 520 SkPaint paint; 521 paint.setColor(SK_ColorRED); 522 vcanvas_->drawLine(30, 10, 30, 90, paint); 523 pcanvas_->drawLine(30, 10, 30, 90, paint); 524 } 525 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("drawLine_red"))); 526 } 527 528 TEST_F(VectorCanvasTest, Circles) { 529 // There is NO WAY to make them agree. At least verify that the output doesn't 530 // change across versions. This test is disabled. See bug 1060231. 531 compare_canvas_ = false; 532 533 // Stroked Circle. 534 { 535 SkPaint paint; 536 SkPath path; 537 path.addCircle(50, 75, 10); 538 paint.setStyle(SkPaint::kStroke_Style); 539 paint.setColor(SK_ColorMAGENTA); 540 vcanvas_->drawPath(path, paint); 541 pcanvas_->drawPath(path, paint); 542 } 543 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("circle_stroke"))); 544 545 // Filled Circle. 546 { 547 SkPaint paint; 548 SkPath path; 549 path.addCircle(50, 25, 10); 550 paint.setStyle(SkPaint::kFill_Style); 551 vcanvas_->drawPath(path, paint); 552 pcanvas_->drawPath(path, paint); 553 } 554 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("circle_fill"))); 555 556 // Stroked Circle over. 557 { 558 SkPaint paint; 559 SkPath path; 560 path.addCircle(50, 25, 10); 561 paint.setStyle(SkPaint::kStroke_Style); 562 paint.setColor(SK_ColorBLUE); 563 vcanvas_->drawPath(path, paint); 564 pcanvas_->drawPath(path, paint); 565 } 566 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("circle_over_strike"))); 567 568 // Stroke and Fill Circle. 569 { 570 SkPaint paint; 571 SkPath path; 572 path.addCircle(12, 50, 10); 573 paint.setStyle(SkPaint::kStrokeAndFill_Style); 574 paint.setColor(SK_ColorRED); 575 vcanvas_->drawPath(path, paint); 576 pcanvas_->drawPath(path, paint); 577 } 578 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("circle_stroke_and_fill"))); 579 580 // Line + Quad + Cubic. 581 { 582 SkPaint paint; 583 SkPath path; 584 paint.setStyle(SkPaint::kStroke_Style); 585 paint.setColor(SK_ColorGREEN); 586 path.moveTo(1, 1); 587 path.lineTo(60, 40); 588 path.lineTo(80, 80); 589 path.quadTo(20, 50, 10, 90); 590 path.quadTo(50, 20, 90, 10); 591 path.cubicTo(20, 40, 50, 50, 10, 10); 592 path.cubicTo(30, 20, 50, 50, 90, 10); 593 path.addRect(90, 90, 95, 96); 594 vcanvas_->drawPath(path, paint); 595 pcanvas_->drawPath(path, paint); 596 } 597 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("mixed_stroke"))); 598 } 599 600 TEST_F(VectorCanvasTest, LineOrientation) { 601 // There is NO WAY to make them agree. At least verify that the output doesn't 602 // change across versions. This test is disabled. See bug 1060231. 603 compare_canvas_ = false; 604 605 // Horizontal lines. 606 { 607 SkPaint paint; 608 paint.setColor(SK_ColorRED); 609 // Left to right. 610 vcanvas_->drawLine(10, 20, 90, 20, paint); 611 pcanvas_->drawLine(10, 20, 90, 20, paint); 612 // Right to left. 613 vcanvas_->drawLine(90, 30, 10, 30, paint); 614 pcanvas_->drawLine(90, 30, 10, 30, paint); 615 } 616 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("horizontal"))); 617 618 // Vertical lines. 619 { 620 SkPaint paint; 621 paint.setColor(SK_ColorRED); 622 // Top down. 623 vcanvas_->drawLine(20, 10, 20, 90, paint); 624 pcanvas_->drawLine(20, 10, 20, 90, paint); 625 // Bottom up. 626 vcanvas_->drawLine(30, 90, 30, 10, paint); 627 pcanvas_->drawLine(30, 90, 30, 10, paint); 628 } 629 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("vertical"))); 630 631 // Try again with a 180 degres rotation. 632 vcanvas_->rotate(180); 633 pcanvas_->rotate(180); 634 635 // Horizontal lines (rotated). 636 { 637 SkPaint paint; 638 paint.setColor(SK_ColorRED); 639 vcanvas_->drawLine(-10, -25, -90, -25, paint); 640 pcanvas_->drawLine(-10, -25, -90, -25, paint); 641 vcanvas_->drawLine(-90, -35, -10, -35, paint); 642 pcanvas_->drawLine(-90, -35, -10, -35, paint); 643 } 644 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("horizontal_180"))); 645 646 // Vertical lines (rotated). 647 { 648 SkPaint paint; 649 paint.setColor(SK_ColorRED); 650 vcanvas_->drawLine(-25, -10, -25, -90, paint); 651 pcanvas_->drawLine(-25, -10, -25, -90, paint); 652 vcanvas_->drawLine(-35, -90, -35, -10, paint); 653 pcanvas_->drawLine(-35, -90, -35, -10, paint); 654 } 655 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("vertical_180"))); 656 } 657 658 TEST_F(VectorCanvasTest, PathOrientation) { 659 // There is NO WAY to make them agree. At least verify that the output doesn't 660 // change across versions. This test is disabled. See bug 1060231. 661 compare_canvas_ = false; 662 663 // Horizontal lines. 664 { 665 SkPaint paint; 666 paint.setStyle(SkPaint::kStroke_Style); 667 paint.setColor(SK_ColorRED); 668 SkPath path; 669 SkPoint start; 670 start.set(10, 20); 671 SkPoint end; 672 end.set(90, 20); 673 path.moveTo(start); 674 path.lineTo(end); 675 vcanvas_->drawPath(path, paint); 676 pcanvas_->drawPath(path, paint); 677 } 678 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("drawPath_ltr"))); 679 680 // Horizontal lines. 681 { 682 SkPaint paint; 683 paint.setStyle(SkPaint::kStroke_Style); 684 paint.setColor(SK_ColorRED); 685 SkPath path; 686 SkPoint start; 687 start.set(90, 30); 688 SkPoint end; 689 end.set(10, 30); 690 path.moveTo(start); 691 path.lineTo(end); 692 vcanvas_->drawPath(path, paint); 693 pcanvas_->drawPath(path, paint); 694 } 695 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("drawPath_rtl"))); 696 } 697 698 TEST_F(VectorCanvasTest, DiagonalLines) { 699 SkPaint paint; 700 paint.setColor(SK_ColorRED); 701 702 vcanvas_->drawLine(10, 10, 90, 90, paint); 703 pcanvas_->drawLine(10, 10, 90, 90, paint); 704 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("nw-se"))); 705 706 // Starting here, there is NO WAY to make them agree. At least verify that the 707 // output doesn't change across versions. This test is disabled. See bug 708 // 1060231. 709 compare_canvas_ = false; 710 711 vcanvas_->drawLine(10, 95, 90, 15, paint); 712 pcanvas_->drawLine(10, 95, 90, 15, paint); 713 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("sw-ne"))); 714 715 vcanvas_->drawLine(90, 10, 10, 90, paint); 716 pcanvas_->drawLine(90, 10, 10, 90, paint); 717 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("ne-sw"))); 718 719 vcanvas_->drawLine(95, 90, 15, 10, paint); 720 pcanvas_->drawLine(95, 90, 15, 10, paint); 721 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("se-nw"))); 722 } 723 724 #if defined(OS_WIN) 725 #define MAYBE_PathEffects DISABLED_PathEffects 726 #else 727 #define MAYBE_PathEffects PathEffects 728 #endif 729 TEST_F(VectorCanvasTest, MAYBE_PathEffects) { 730 { 731 SkPaint paint; 732 SkScalar intervals[] = { 1, 1 }; 733 skia::RefPtr<SkPathEffect> effect = skia::AdoptRef( 734 new SkDashPathEffect(intervals, arraysize(intervals), 0)); 735 paint.setPathEffect(effect.get()); 736 paint.setColor(SK_ColorMAGENTA); 737 paint.setStyle(SkPaint::kStroke_Style); 738 739 vcanvas_->drawLine(10, 10, 90, 10, paint); 740 pcanvas_->drawLine(10, 10, 90, 10, paint); 741 } 742 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("dash_line"))); 743 744 745 // Starting here, there is NO WAY to make them agree. At least verify that the 746 // output doesn't change across versions. This test is disabled. See bug 747 // 1060231. 748 compare_canvas_ = false; 749 750 { 751 SkPaint paint; 752 SkScalar intervals[] = { 3, 5 }; 753 skia::RefPtr<SkPathEffect> effect = skia::AdoptRef( 754 new SkDashPathEffect(intervals, arraysize(intervals), 0)); 755 paint.setPathEffect(effect.get()); 756 paint.setColor(SK_ColorMAGENTA); 757 paint.setStyle(SkPaint::kStroke_Style); 758 759 SkPath path; 760 path.moveTo(10, 15); 761 path.lineTo(90, 15); 762 path.lineTo(90, 90); 763 vcanvas_->drawPath(path, paint); 764 pcanvas_->drawPath(path, paint); 765 } 766 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("dash_path"))); 767 768 { 769 SkPaint paint; 770 SkScalar intervals[] = { 2, 1 }; 771 skia::RefPtr<SkPathEffect> effect = skia::AdoptRef( 772 new SkDashPathEffect(intervals, arraysize(intervals), 0)); 773 paint.setPathEffect(effect.get()); 774 paint.setColor(SK_ColorMAGENTA); 775 paint.setStyle(SkPaint::kStroke_Style); 776 777 vcanvas_->drawRectCoords(20, 20, 30, 30, paint); 778 pcanvas_->drawRectCoords(20, 20, 30, 30, paint); 779 } 780 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("dash_rect"))); 781 782 // This thing looks like it has been drawn by a 3 years old kid. I haven't 783 // filed a bug on this since I guess nobody is expecting this to look nice. 784 { 785 SkPaint paint; 786 SkScalar intervals[] = { 1, 1 }; 787 skia::RefPtr<SkPathEffect> effect = skia::AdoptRef( 788 new SkDashPathEffect(intervals, arraysize(intervals), 0)); 789 paint.setPathEffect(effect.get()); 790 paint.setColor(SK_ColorMAGENTA); 791 paint.setStyle(SkPaint::kStroke_Style); 792 793 SkPath path; 794 path.addCircle(50, 75, 10); 795 vcanvas_->drawPath(path, paint); 796 pcanvas_->drawPath(path, paint); 797 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("circle"))); 798 } 799 } 800 801 TEST_F(VectorCanvasTest, Bitmaps) { 802 { 803 SkBitmap bitmap; 804 LoadPngFileToSkBitmap(test_file(L"bitmap_opaque.png"), &bitmap, true); 805 vcanvas_->drawBitmap(bitmap, 13, 3, NULL); 806 pcanvas_->drawBitmap(bitmap, 13, 3, NULL); 807 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("opaque"))); 808 } 809 810 { 811 SkBitmap bitmap; 812 LoadPngFileToSkBitmap(test_file(L"bitmap_alpha.png"), &bitmap, false); 813 vcanvas_->drawBitmap(bitmap, 5, 15, NULL); 814 pcanvas_->drawBitmap(bitmap, 5, 15, NULL); 815 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("alpha"))); 816 } 817 } 818 819 TEST_F(VectorCanvasTest, ClippingRect) { 820 SkBitmap bitmap; 821 LoadPngFileToSkBitmap(test_file(L"..\\bitmaps\\bitmap_opaque.png"), &bitmap, 822 true); 823 SkRect rect; 824 rect.fLeft = 2; 825 rect.fTop = 2; 826 rect.fRight = 30.5f; 827 rect.fBottom = 30.5f; 828 vcanvas_->clipRect(rect); 829 pcanvas_->clipRect(rect); 830 831 vcanvas_->drawBitmap(bitmap, 13, 3, NULL); 832 pcanvas_->drawBitmap(bitmap, 13, 3, NULL); 833 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("rect"))); 834 } 835 836 TEST_F(VectorCanvasTest, ClippingPath) { 837 SkBitmap bitmap; 838 LoadPngFileToSkBitmap(test_file(L"..\\bitmaps\\bitmap_opaque.png"), &bitmap, 839 true); 840 SkPath path; 841 path.addCircle(20, 20, 10); 842 vcanvas_->clipPath(path); 843 pcanvas_->clipPath(path); 844 845 vcanvas_->drawBitmap(bitmap, 14, 3, NULL); 846 pcanvas_->drawBitmap(bitmap, 14, 3, NULL); 847 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("path"))); 848 } 849 850 TEST_F(VectorCanvasTest, ClippingCombined) { 851 SkBitmap bitmap; 852 LoadPngFileToSkBitmap(test_file(L"..\\bitmaps\\bitmap_opaque.png"), &bitmap, 853 true); 854 855 SkRect rect; 856 rect.fLeft = 2; 857 rect.fTop = 2; 858 rect.fRight = 30.5f; 859 rect.fBottom = 30.5f; 860 vcanvas_->clipRect(rect); 861 pcanvas_->clipRect(rect); 862 SkPath path; 863 path.addCircle(20, 20, 10); 864 vcanvas_->clipPath(path, SkRegion::kUnion_Op); 865 pcanvas_->clipPath(path, SkRegion::kUnion_Op); 866 867 vcanvas_->drawBitmap(bitmap, 15, 3, NULL); 868 pcanvas_->drawBitmap(bitmap, 15, 3, NULL); 869 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("combined"))); 870 } 871 872 TEST_F(VectorCanvasTest, ClippingIntersect) { 873 SkBitmap bitmap; 874 LoadPngFileToSkBitmap(test_file(L"..\\bitmaps\\bitmap_opaque.png"), &bitmap, 875 true); 876 877 SkRect rect; 878 rect.fLeft = 2; 879 rect.fTop = 2; 880 rect.fRight = 30.5f; 881 rect.fBottom = 30.5f; 882 vcanvas_->clipRect(rect); 883 pcanvas_->clipRect(rect); 884 SkPath path; 885 path.addCircle(23, 23, 15); 886 vcanvas_->clipPath(path); 887 pcanvas_->clipPath(path); 888 889 vcanvas_->drawBitmap(bitmap, 15, 3, NULL); 890 pcanvas_->drawBitmap(bitmap, 15, 3, NULL); 891 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("intersect"))); 892 } 893 894 TEST_F(VectorCanvasTest, ClippingClean) { 895 SkBitmap bitmap; 896 LoadPngFileToSkBitmap(test_file(L"..\\bitmaps\\bitmap_opaque.png"), &bitmap, 897 true); 898 { 899 SkAutoCanvasRestore acrv(vcanvas_, true); 900 SkAutoCanvasRestore acrp(pcanvas_, true); 901 SkRect rect; 902 rect.fLeft = 2; 903 rect.fTop = 2; 904 rect.fRight = 30.5f; 905 rect.fBottom = 30.5f; 906 vcanvas_->clipRect(rect); 907 pcanvas_->clipRect(rect); 908 909 vcanvas_->drawBitmap(bitmap, 15, 3, NULL); 910 pcanvas_->drawBitmap(bitmap, 15, 3, NULL); 911 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("clipped"))); 912 } 913 { 914 // Verify that the clipping region has been fixed back. 915 vcanvas_->drawBitmap(bitmap, 55, 3, NULL); 916 pcanvas_->drawBitmap(bitmap, 55, 3, NULL); 917 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("unclipped"))); 918 } 919 } 920 921 // See http://crbug.com/26938 922 TEST_F(VectorCanvasTest, DISABLED_Matrix) { 923 SkBitmap bitmap; 924 LoadPngFileToSkBitmap(test_file(L"..\\bitmaps\\bitmap_opaque.png"), &bitmap, 925 true); 926 { 927 vcanvas_->translate(15, 3); 928 pcanvas_->translate(15, 3); 929 vcanvas_->drawBitmap(bitmap, 0, 0, NULL); 930 pcanvas_->drawBitmap(bitmap, 0, 0, NULL); 931 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("translate1"))); 932 } 933 { 934 vcanvas_->translate(-30, -23); 935 pcanvas_->translate(-30, -23); 936 vcanvas_->drawBitmap(bitmap, 0, 0, NULL); 937 pcanvas_->drawBitmap(bitmap, 0, 0, NULL); 938 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("translate2"))); 939 } 940 vcanvas_->resetMatrix(); 941 pcanvas_->resetMatrix(); 942 943 // For scaling and rotation, they use a different algorithm (nearest 944 // neighborhood vs smoothing). At least verify that the output doesn't change 945 // across versions. 946 compare_canvas_ = false; 947 948 { 949 vcanvas_->scale(SkDoubleToScalar(1.9), SkDoubleToScalar(1.5)); 950 pcanvas_->scale(SkDoubleToScalar(1.9), SkDoubleToScalar(1.5)); 951 vcanvas_->drawBitmap(bitmap, 1, 1, NULL); 952 pcanvas_->drawBitmap(bitmap, 1, 1, NULL); 953 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("scale"))); 954 } 955 vcanvas_->resetMatrix(); 956 pcanvas_->resetMatrix(); 957 958 { 959 vcanvas_->rotate(67); 960 pcanvas_->rotate(67); 961 vcanvas_->drawBitmap(bitmap, 20, -50, NULL); 962 pcanvas_->drawBitmap(bitmap, 20, -50, NULL); 963 EXPECT_EQ(0., ProcessImage(FILE_PATH_LITERAL("rotate"))); 964 } 965 } 966 967 #endif // !defined(USE_AURA) 968 969 } // namespace skia 970