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