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