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