18b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary/* 28b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary * Copyright 2015 Google Inc. 38b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary * 48b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary * Use of this source code is governed by a BSD-style license that can be 58b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary * found in the LICENSE file. 68b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary */ 78b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary 8ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman#include "SkAutoPixmapStorage.h" 9ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman#include "SkColorPriv.h" 10ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman#include "SkImage.h" 11ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman#include "SkParsePath.h" 128b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary#include "SkPath.h" 13ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman#include "SkSurface.h" 148b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary#include "gm.h" 158b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary 16ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman// GM to test combinations of stroking zero length paths with different caps and other settings 17ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman// Variables: 18ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman// * Antialiasing: On, Off 19ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman// * Caps: Butt, Round, Square 20ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman// * Stroke width: 0, 0.9, 1, 1.1, 15, 25 21ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman// * Path form: M, ML, MLZ, MZ 22ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman// * Path contours: 1 or 2 23ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman// * Path verbs: Line, Quad, Cubic, Conic 24ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman// 25ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman// Each test is drawn to a 50x20 offscreen surface, and expected to produce some number (0 - 2) of 26ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman// visible pieces of cap geometry. These are counted by scanning horizontally for peaks (blobs). 27ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 28ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osmanstatic bool draw_path_cell(SkCanvas* canvas, SkImage* img, int expectedCaps) { 29ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman // Draw the image 30ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman canvas->drawImage(img, 0, 0); 31ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 32ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman int w = img->width(), h = img->height(); 33ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 34ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman // Read the pixels back 35ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman SkImageInfo info = SkImageInfo::MakeN32Premul(w, h); 36ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman SkAutoPixmapStorage pmap; 37ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman pmap.alloc(info); 38ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman SkAssertResult(img->readPixels(pmap, 0, 0)); 39ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 40ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman // To account for rasterization differences, we scan the middle two rows [y, y+1] of the image 41ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman SkASSERT(h % 2 == 0); 42ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman int y = (h - 1) / 2; 43ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 44ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman bool inBlob = false; 45ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman int numBlobs = 0; 46ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman for (int x = 0; x < w; ++x) { 47ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman // We drew white-on-black. We can look for any non-zero value. Just check red. 48ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman // And we care if either row is non-zero, so just add them to simplify everything. 49ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman uint32_t v = SkGetPackedR32(*pmap.addr32(x, y)) + SkGetPackedR32(*pmap.addr32(x, y + 1)); 50ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 51ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman if (!inBlob && v) { 52ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman ++numBlobs; 53ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman } 54ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman inBlob = SkToBool(v); 55ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman } 561f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 57ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman SkPaint outline; 58ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman outline.setStyle(SkPaint::kStroke_Style); 59ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman if (numBlobs == expectedCaps) { 60ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman outline.setColor(0xFF007F00); // Green 61ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman } else if (numBlobs > expectedCaps) { 62ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman outline.setColor(0xFF7F7F00); // Yellow -- more geometry than expected 63ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman } else { 64ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman outline.setColor(0xFF7F0000); // Red -- missing some geometry 651f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 661f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 67ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman canvas->drawRect(SkRect::MakeWH(w, h), outline); 68ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman return numBlobs == expectedCaps; 69ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman} 701f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 71ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osmanstatic const SkPaint::Cap kCaps[] = { 72ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman SkPaint::kButt_Cap, 73ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman SkPaint::kRound_Cap, 74ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman SkPaint::kSquare_Cap 75ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman}; 76ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 77ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osmanstatic const SkScalar kWidths[] = { 0.0f, 0.9f, 1.0f, 1.1f, 15.0f, 25.0f }; 78ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 79ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman// Full set of path structures for single contour case (each primitive with and without a close) 80ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osmanstatic const char* kAllVerbs[] = { 81ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman nullptr, 82ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman "z ", 83ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman "l 0 0 ", 84ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman "l 0 0 z ", 85ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman "q 0 0 0 0 ", 86ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman "q 0 0 0 0 z ", 87ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman "c 0 0 0 0 0 0 ", 88ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman "c 0 0 0 0 0 0 z ", 89ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman "a 0 0 0 0 0 0 0 ", 90ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman "a 0 0 0 0 0 0 0 z " 91ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman}; 92ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 93ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman// Reduced set of path structures for double contour case, to keep total number of cases down 94ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osmanstatic const char* kSomeVerbs[] = { 95ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman nullptr, 96ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman "z ", 97ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman "l 0 0 ", 98ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman "l 0 0 z ", 99ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman "q 0 0 0 0 ", 100ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman "q 0 0 0 0 z ", 101ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman}; 1021f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 103ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osmanstatic const int kCellWidth = 50; 104ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osmanstatic const int kCellHeight = 20; 105ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osmanstatic const int kCellPad = 2; 106ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 107ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osmanstatic const int kNumRows = SK_ARRAY_COUNT(kCaps) * SK_ARRAY_COUNT(kWidths); 108ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osmanstatic const int kNumColumns = SK_ARRAY_COUNT(kAllVerbs); 109ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osmanstatic const int kTotalWidth = kNumColumns * (kCellWidth + kCellPad) + kCellPad; 110ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osmanstatic const int kTotalHeight = kNumRows * (kCellHeight + kCellPad) + kCellPad; 111ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 112ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osmanstatic const int kDblContourNumColums = SK_ARRAY_COUNT(kSomeVerbs) * SK_ARRAY_COUNT(kSomeVerbs); 113ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osmanstatic const int kDblContourTotalWidth = kDblContourNumColums * (kCellWidth + kCellPad) + kCellPad; 114ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 115ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman// 50% transparent versions of the colors used for positive/negative triage icons on gold.skia.org 116ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osmanstatic const SkColor kFailureRed = 0x7FE7298A; 117ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osmanstatic const SkColor kSuccessGreen = 0x7F1B9E77; 118ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 119ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osmanstatic void draw_zero_length_capped_paths(SkCanvas* canvas, bool aa) { 120ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman canvas->translate(kCellPad, kCellPad); 121ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 122ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman SkImageInfo info = canvas->imageInfo().makeWH(kCellWidth, kCellHeight); 123ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman auto surface = canvas->makeSurface(info); 124ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman if (!surface) { 125ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman surface = SkSurface::MakeRasterN32Premul(kCellWidth, kCellHeight); 1261f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 1278b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary 128ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman SkPaint paint; 129ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman paint.setColor(SK_ColorWHITE); 130ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman paint.setAntiAlias(aa); 131ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman paint.setStyle(SkPaint::kStroke_Style); 1328b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary 133ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman int numFailedTests = 0; 134ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman for (auto cap : kCaps) { 135ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman for (auto width : kWidths) { 136ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman paint.setStrokeCap(cap); 137ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman paint.setStrokeWidth(width); 138ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman canvas->save(); 139515ccafc98d5b26f39f913a6a9606a0dac5c514fBrian Osman 140ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman for (auto verb : kAllVerbs) { 141ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman SkString pathStr; 142ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman pathStr.appendf("M %f %f ", (kCellWidth - 1) * 0.5f, (kCellHeight - 1) * 0.5f); 143ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman if (verb) { 144ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman pathStr.append(verb); 1451f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 1468b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary 147ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman SkPath path; 148ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman SkParsePath::FromSVGString(pathStr.c_str(), &path); 1498b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary 150ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman surface->getCanvas()->clear(SK_ColorTRANSPARENT); 151ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman surface->getCanvas()->drawPath(path, paint); 152ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman auto img = surface->makeImageSnapshot(); 1538b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary 154ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman // All cases should draw one cap, except for butt capped, and dangling moves 155ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman // (without a verb or close), which shouldn't draw anything. 156ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman int expectedCaps = ((SkPaint::kButt_Cap == cap) || !verb) ? 0 : 1; 1571f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 158ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman if (!draw_path_cell(canvas, img.get(), expectedCaps)) { 159ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman ++numFailedTests; 160ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman } 161ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman canvas->translate(kCellWidth + kCellPad, 0); 1621f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 1631f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark canvas->restore(); 164ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman canvas->translate(0, kCellHeight + kCellPad); 1651f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 1661f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 1671f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 168ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman canvas->drawColor(numFailedTests > 0 ? kFailureRed : kSuccessGreen); 169ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman} 1701f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 171ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian OsmanDEF_SIMPLE_GM_BG(zero_length_paths_aa, canvas, kTotalWidth, kTotalHeight, SK_ColorBLACK) { 172ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman draw_zero_length_capped_paths(canvas, true); 173ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman} 174ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 175ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian OsmanDEF_SIMPLE_GM_BG(zero_length_paths_bw, canvas, kTotalWidth, kTotalHeight, SK_ColorBLACK) { 176ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman draw_zero_length_capped_paths(canvas, false); 177ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman} 178ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 179ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osmanstatic void draw_zero_length_capped_paths_dbl_contour(SkCanvas* canvas, bool aa) { 180ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman canvas->translate(kCellPad, kCellPad); 1811f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 182ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman SkImageInfo info = canvas->imageInfo().makeWH(kCellWidth, kCellHeight); 183ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman auto surface = canvas->makeSurface(info); 184ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman if (!surface) { 185ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman surface = SkSurface::MakeRasterN32Premul(kCellWidth, kCellHeight); 186ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman } 187ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 188ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman SkPaint paint; 189ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman paint.setColor(SK_ColorWHITE); 190ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman paint.setAntiAlias(aa); 191ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman paint.setStyle(SkPaint::kStroke_Style); 192ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 193ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman int numFailedTests = 0; 194ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman for (auto cap : kCaps) { 195ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman for (auto width : kWidths) { 196ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman paint.setStrokeCap(cap); 197ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman paint.setStrokeWidth(width); 1981f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark canvas->save(); 199ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 200ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman for (auto firstVerb : kSomeVerbs) { 201ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman for (auto secondVerb : kSomeVerbs) { 202ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman int expectedCaps = 0; 203ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 204ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman SkString pathStr; 205ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman pathStr.append("M 9.5 9.5 "); 206ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman if (firstVerb) { 207ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman pathStr.append(firstVerb); 208ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman ++expectedCaps; 209ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman } 210ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman pathStr.append("M 40.5 9.5 "); 211ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman if (secondVerb) { 212ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman pathStr.append(secondVerb); 213ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman ++expectedCaps; 214ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman } 215ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 216ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman SkPath path; 217ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman SkParsePath::FromSVGString(pathStr.c_str(), &path); 218ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 219ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman surface->getCanvas()->clear(SK_ColorTRANSPARENT); 220ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman surface->getCanvas()->drawPath(path, paint); 221ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman auto img = surface->makeImageSnapshot(); 222ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 223ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman if (SkPaint::kButt_Cap == cap) { 224ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman expectedCaps = 0; 225ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman } 226ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman 227ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman if (!draw_path_cell(canvas, img.get(), expectedCaps)) { 228ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman ++numFailedTests; 229ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman } 230ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman canvas->translate(kCellWidth + kCellPad, 0); 231ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman } 232ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman } 2331f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark canvas->restore(); 234ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman canvas->translate(0, kCellHeight + kCellPad); 2351f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 2361f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 2371f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 238ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman canvas->drawColor(numFailedTests > 0 ? kFailureRed : kSuccessGreen); 239ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman} 2401f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 241ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian OsmanDEF_SIMPLE_GM_BG(zero_length_paths_dbl_aa, canvas, kDblContourTotalWidth, kTotalHeight, 242ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman SK_ColorBLACK) { 243ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman draw_zero_length_capped_paths_dbl_contour(canvas, true); 244ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman} 2451f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 246ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian OsmanDEF_SIMPLE_GM_BG(zero_length_paths_dbl_bw, canvas, kDblContourTotalWidth, kTotalHeight, 247ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman SK_ColorBLACK) { 248ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman draw_zero_length_capped_paths_dbl_contour(canvas, false); 249ee6aa80e88a7b2953e9b6e4dfa6bd44355815f03Brian Osman} 250