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