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 88b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary#include "SkPath.h" 98b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary#include "SkStream.h" 108b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary#include "gm.h" 118b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary 121f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 138b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary// Test how short paths are stroked with various caps 141f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclarkclass StrokeZeroGM : public skiagm::GM { 151f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkPath fPaths[8]; 161f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkPath fClipL, fClipR, fClipS; 171f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 181f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclarkprotected: 191f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark void onOnceBeforeDraw() override { 201f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fClipL.moveTo(0, 0); 211f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fClipL.lineTo(3, 0); 221f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fClipL.lineTo(2.5f, 1); 231f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fClipL.lineTo(3.5f, 2.5f); 241f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fClipL.lineTo(2.5f, 4); 251f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fClipL.lineTo(3, 5); 261f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fClipL.lineTo(0, 5); 271f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fClipL.close(); 281f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 291f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fClipR.moveTo(34, 0); 301f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fClipR.lineTo(34, 5); 311f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fClipR.lineTo(31, 5); 321f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fClipR.lineTo(30.5, 4); 331f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fClipR.lineTo(31.5, 2.5); 341f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fClipR.lineTo(30.5, 1); 351f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fClipR.lineTo(31, 0); 361f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fClipR.close(); 371f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 381f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fClipS.addRect(SkRect::MakeIWH(4, 5)); 391f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 401f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[0].moveTo(30, 0); // single line segment 411f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[0].rLineTo(30, 0); 421f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 431f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[1].moveTo(90, 0); // single line segment with close (does not draw caps) 441f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[1].rLineTo(30, 0); 451f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[1].close(); 461f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 471f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[2].moveTo(150, 0); // zero-length line 481f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[2].rLineTo(0, 0); 491f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 501f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[3].moveTo(180, 0); // zero-length line with close (expected not to draw) 511f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[3].rLineTo(0, 0); 521f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[3].close(); 531f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 541f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[4].moveTo(210, 0); // close only, no line 551f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[4].close(); 561f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 571f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[5].moveTo(30, 90); // all combos below should draw two caps 581f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[5].rLineTo(0, 0); 591f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[5].moveTo(60, 90); 601f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[5].rLineTo(0, 0); 611f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 621f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[6].moveTo(90, 90); 631f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[6].close(); 641f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[6].moveTo(120, 90); 651f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[6].close(); 661f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 671f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[7].moveTo(150, 90); 681f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[7].rLineTo(0, 0); 691f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[7].moveTo(180, 90); 701f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fPaths[7].close(); 711f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 721f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 731f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 741f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkString onShortName() override { 751f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark return SkString("path_stroke_with_zero_length"); 761f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 771f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 781f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkISize onISize() override { 791f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark return SkISize::Make(1120, 840); 801f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 818b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary 821f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark void onDraw(SkCanvas* canvas) override { 831f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkPaint bkgrnd; 841f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark bkgrnd.setColor(SK_ColorWHITE); 851f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark canvas->drawRect(SkRect::MakeIWH(onISize().fWidth, onISize().fHeight), bkgrnd); 868b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary 871f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark auto drawPaths = [&](SkPaint& paint, int indexMask) { 881f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark canvas->translate(0, 30.0f); 891f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark int index = 0; 901f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark for (const SkPath& path : fPaths) { 911f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark if (indexMask & (1 << index)) { 921f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark canvas->drawPath(path, paint); 931f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 9448156ed412410c9d27b560e8596e3f34d175a277mtklein if (this->getMode() == skiagm::GM::kSample_Mode && paint.getStrokeWidth() < 2) { 951f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark drawFat(canvas, path, paint, index); 961f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 971f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark ++index; 981f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 991f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark }; 1008b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary 1011f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark if (false) { // debugging variant that draws a single element 1021f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkScalar width = 0; 1031f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark bool antialias = true; 1048b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary 1051f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkPaint butt; 1061f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark butt.setAntiAlias(antialias); 1071f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark butt.setStyle(SkPaint::kStroke_Style); 1081f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark butt.setStrokeWidth(width); 1098b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary 1101f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkPaint round(butt); 1111f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark round.setStrokeCap(SkPaint::kRound_Cap); 1121f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark drawPaths(round, 1 << 7); 1131f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark return; 1148b2bc252faed7c751cf9248c3833c0631f498b7dhalcanary } 1151f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 1161f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkScalar widths[] = { 0, .999f, 1, 1.001f, 20 }; 1171f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark bool aliases[] = { false, true }; 1181f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark for (bool antialias : aliases) { 1191f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark canvas->save(); 120636270245fb486559b0324e9bb9e794d56bc3101mtklein for (SkScalar width : widths) { 1211f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark canvas->save(); 1221f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkPaint butt; 1231f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark butt.setAntiAlias(antialias); 1241f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark butt.setStyle(SkPaint::kStroke_Style); 1251f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark butt.setStrokeWidth(width); 1261f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark drawPaths(butt, -1); 1271f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 1281f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkPaint round(butt); 1291f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark round.setStrokeCap(SkPaint::kRound_Cap); 1301f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark drawPaths(round, -1); 1311f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 1321f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkPaint square(butt); 1331f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark square.setStrokeCap(SkPaint::kSquare_Cap); 1341f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark drawPaths(square, -1); 1351f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark canvas->restore(); 1361f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark canvas->translate(220, 0); 1371f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 1381f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark canvas->restore(); 1391f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark canvas->translate(0, 210); 1401f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 1411f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 1421f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 1431f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclarkprivate: 1441f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark void drawFat(SkCanvas* canvas, const SkPath& path, const SkPaint& paint, int index) { 1451f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark const SkScalar scale = 10; 1461f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkRect bounds = path.getBounds(); 1471f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkBitmap offscreen; 1481f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark offscreen.allocN32Pixels(SkScalarRoundToInt(bounds.width() + 4), 1491f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkScalarRoundToInt(bounds.height() + 4)); 150636270245fb486559b0324e9bb9e794d56bc3101mtklein offscreen.eraseColor(SK_ColorWHITE); 1511f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkScalar pathX = bounds.fLeft - 2; 1521f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkScalar pathY = bounds.fTop - 2; 1531f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkMatrix cMatrix = canvas->getTotalMatrix(); 1541f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark if (!canvas->readPixels(&offscreen, SkScalarRoundToInt(pathX + cMatrix.getTranslateX()), 1551f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkScalarRoundToInt(pathY + cMatrix.getTranslateY()))) { 1561f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark return; 1571f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 1581f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 1591f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark canvas->save(); 1601f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkMatrix clipM; 1611f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark clipM.reset(); 1621f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark clipM.preScale(scale, scale); 1631f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark clipM.postTranslate(bounds.fLeft - 17, bounds.fTop - 24.5f + 420); 1641f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkPath clip; 1651f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark if (index < 2) { 1661f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fClipL.transform(clipM, &clip); 1671f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } else { 1681f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fClipS.transform(clipM, &clip); 1691f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 170669983856d99b9312be3166b7dd1f8483a90c315reed canvas->clipPath(clip, true); 1711f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark canvas->scale(scale, scale); 1721f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark canvas->drawBitmap(offscreen, (bounds.fLeft - 17) / scale, 1731f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark (bounds.fTop - 20 + 420) / scale); 1741f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark canvas->restore(); 1751f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 1761f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark if (bounds.width() > 20) { 1771f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark canvas->save(); 1781f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark clipM.reset(); 1791f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark clipM.preScale(scale, scale); 1801f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark clipM.postTranslate(bounds.fLeft - 17 - 275, bounds.fTop - 24.5f + 420); 1811f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark SkPath clip; 1821f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark fClipR.transform(clipM, &clip); 183669983856d99b9312be3166b7dd1f8483a90c315reed canvas->clipPath(clip, true); 1841f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark canvas->scale(10.f, 10.f); 1851f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark canvas->drawBitmap(offscreen, (bounds.fLeft - 17 - 275 1861f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark + (index >= 5 ? 5 : 0)) / scale, (bounds.fTop - 20 + 420) / scale); 1871f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark canvas->restore(); 1881f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 1891f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark } 1901f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 1911f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark}; 1921f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 1931f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark/////////////////////////////////////////////////////////////////////////////// 1941f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclark 1951f17ab59929f5f5eb399e09690ef9dbc21525ccccaryclarkDEF_GM( return new StrokeZeroGM(); ) 196