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 file_util::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 = file_util::OpenFile(filename, "wb"); 139 ASSERT_TRUE(f); 140 ASSERT_EQ(fwrite(&*compressed.begin(), 1, compressed.size(), f), 141 compressed.size()); 142 file_util::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 file_util::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 = WideToASCII(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 file_util::ReadFileToString(base::MakeAbsoluteFilePath(filename), 339 &compressed); 340 ASSERT_TRUE(compressed.size()); 341 342 ASSERT_TRUE(gfx::PNGCodec::Decode( 343 reinterpret_cast<const unsigned char*>(compressed.data()), 344 compressed.size(), bitmap)); 345 346 EXPECT_EQ(is_opaque, bitmap->isOpaque()); 347 Premultiply(*bitmap); 348 } 349 350 } // namespace 351 352 // Streams an image. 353 inline std::ostream& operator<<(std::ostream& out, const Image& image) { 354 return out << "Image(" << image.width() << ", " 355 << image.height() << ", " << image.row_length() << ")"; 356 } 357 358 // Runs simultaneously the same drawing commands on VectorCanvas and 359 // PlatformCanvas and compare the results. 360 class VectorCanvasTest : public ImageTest { 361 public: 362 typedef ImageTest parent; 363 364 VectorCanvasTest() : parent(CurrentMode()), compare_canvas_(true) { 365 } 366 367 protected: 368 virtual void SetUp() { 369 parent::SetUp(); 370 Init(100); 371 number_ = 0; 372 } 373 374 virtual void TearDown() { 375 delete pcanvas_; 376 pcanvas_ = NULL; 377 378 delete vcanvas_; 379 vcanvas_ = NULL; 380 381 delete bitmap_; 382 bitmap_ = NULL; 383 384 delete context_; 385 context_ = NULL; 386 387 parent::TearDown(); 388 } 389 390 void Init(int size) { 391 size_ = size; 392 context_ = new Context(); 393 bitmap_ = new Bitmap(*context_, size_, size_); 394 vcanvas_ = new VectorCanvas( 395 VectorPlatformDeviceEmf::CreateDevice( 396 size_, size_, true, context_->context())); 397 pcanvas_ = CreatePlatformCanvas(size_, size_, false); 398 399 // Clear white. 400 vcanvas_->drawARGB(255, 255, 255, 255, SkXfermode::kSrc_Mode); 401 pcanvas_->drawARGB(255, 255, 255, 255, SkXfermode::kSrc_Mode); 402 } 403 404 // Compares both canvas and returns the pixel difference in percentage between 405 // both images. 0 on success and ]0, 100] on failure. 406 double ProcessImage(const base::FilePath::StringType& filename) { 407 std::wstring number(base::StringPrintf(L"%02d_", number_++)); 408 double diff1 = parent::ProcessCanvas(*vcanvas_, number + L"vc_" + filename); 409 double diff2 = parent::ProcessCanvas(*pcanvas_, number + L"pc_" + filename); 410 if (!compare_canvas_) 411 return std::max(diff1, diff2); 412 413 Image image1(*vcanvas_); 414 Image image2(*pcanvas_); 415 double diff = image1.PercentageDifferent(image2); 416 return std::max(std::max(diff1, diff2), diff); 417 } 418 419 // Returns COMPARE, which is the default. If kGenerateSwitch command 420 // line argument is used to start this process, GENERATE is returned instead. 421 static ProcessAction CurrentMode() { 422 return CommandLine::ForCurrentProcess()->HasSwitch(kGenerateSwitch) ? 423 GENERATE : 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 971