aboutsummaryrefslogtreecommitdiffhomepage
path: root/gm/path_stroke_with_zero_length.cpp
diff options
context:
space:
mode:
authorGravatar caryclark <caryclark@google.com>2015-12-16 08:53:41 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2015-12-16 08:53:41 -0800
commit1f17ab59929f5f5eb399e09690ef9dbc21525ccc (patch)
tree586b48eda597366b6a061f3e9a68ebfc56285709 /gm/path_stroke_with_zero_length.cpp
parentda420b976e61071cfe5de10556b4b23e519091d6 (diff)
This brings hairlines into agreement with thick strokes.
Add more testing and a pixel magnification to GM. R=reed@google.com, fmalita@chromium.org BUG=skia:4599 GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1527083002 Review URL: https://codereview.chromium.org/1527083002
Diffstat (limited to 'gm/path_stroke_with_zero_length.cpp')
-rw-r--r--gm/path_stroke_with_zero_length.cpp213
1 files changed, 177 insertions, 36 deletions
diff --git a/gm/path_stroke_with_zero_length.cpp b/gm/path_stroke_with_zero_length.cpp
index dc52947da3..6f542bac3f 100644
--- a/gm/path_stroke_with_zero_length.cpp
+++ b/gm/path_stroke_with_zero_length.cpp
@@ -9,46 +9,187 @@
#include "SkStream.h"
#include "gm.h"
+
// Test how short paths are stroked with various caps
-DEF_SIMPLE_GM(path_stroke_with_zero_length, canvas, 240, 120) {
- SkPath paths[5];
- paths[0].moveTo(30.0f, 0); // single line segment
- paths[0].rLineTo(30.0f, 0);
+class StrokeZeroGM : public skiagm::GM {
+ SkPath fPaths[8];
+ SkPath fClipL, fClipR, fClipS;
+
+protected:
+ void onOnceBeforeDraw() override {
+ fClipL.moveTo(0, 0);
+ fClipL.lineTo(3, 0);
+ fClipL.lineTo(2.5f, 1);
+ fClipL.lineTo(3.5f, 2.5f);
+ fClipL.lineTo(2.5f, 4);
+ fClipL.lineTo(3, 5);
+ fClipL.lineTo(0, 5);
+ fClipL.close();
+
+ fClipR.moveTo(34, 0);
+ fClipR.lineTo(34, 5);
+ fClipR.lineTo(31, 5);
+ fClipR.lineTo(30.5, 4);
+ fClipR.lineTo(31.5, 2.5);
+ fClipR.lineTo(30.5, 1);
+ fClipR.lineTo(31, 0);
+ fClipR.close();
+
+ fClipS.addRect(SkRect::MakeIWH(4, 5));
+
+ fPaths[0].moveTo(30, 0); // single line segment
+ fPaths[0].rLineTo(30, 0);
+
+ fPaths[1].moveTo(90, 0); // single line segment with close (does not draw caps)
+ fPaths[1].rLineTo(30, 0);
+ fPaths[1].close();
+
+ fPaths[2].moveTo(150, 0); // zero-length line
+ fPaths[2].rLineTo(0, 0);
+
+ fPaths[3].moveTo(180, 0); // zero-length line with close (expected not to draw)
+ fPaths[3].rLineTo(0, 0);
+ fPaths[3].close();
+
+ fPaths[4].moveTo(210, 0); // close only, no line
+ fPaths[4].close();
+
+ fPaths[5].moveTo(30, 90); // all combos below should draw two caps
+ fPaths[5].rLineTo(0, 0);
+ fPaths[5].moveTo(60, 90);
+ fPaths[5].rLineTo(0, 0);
+
+ fPaths[6].moveTo(90, 90);
+ fPaths[6].close();
+ fPaths[6].moveTo(120, 90);
+ fPaths[6].close();
+
+ fPaths[7].moveTo(150, 90);
+ fPaths[7].rLineTo(0, 0);
+ fPaths[7].moveTo(180, 90);
+ fPaths[7].close();
+ }
+
+
+ SkString onShortName() override {
+ return SkString("path_stroke_with_zero_length");
+ }
+
+ SkISize onISize() override {
+ return SkISize::Make(1120, 840);
+ }
- paths[1].moveTo(90.0f, 0); // single line segment with close
- paths[1].rLineTo(30.0f, 0);
- paths[1].close();
+ void onDraw(SkCanvas* canvas) override {
+ SkPaint bkgrnd;
+ bkgrnd.setColor(SK_ColorWHITE);
+ canvas->drawRect(SkRect::MakeIWH(onISize().fWidth, onISize().fHeight), bkgrnd);
- paths[2].moveTo(150.0f, 0); // zero-length line
- paths[2].rLineTo(0, 0);
+ auto drawPaths = [&](SkPaint& paint, int indexMask) {
+ canvas->translate(0, 30.0f);
+ int index = 0;
+ for (const SkPath& path : fPaths) {
+ if (indexMask & (1 << index)) {
+ canvas->drawPath(path, paint);
+ }
+ if (paint.getStrokeWidth() < 2) {
+ drawFat(canvas, path, paint, index);
+ }
+ ++index;
+ }
+ };
- paths[3].moveTo(180.0f, 0); // zero-length line with close
- paths[3].rLineTo(0, 0);
- paths[3].close();
+ if (false) { // debugging variant that draws a single element
+ SkScalar width = 0;
+ bool antialias = true;
- paths[4].moveTo(210.0f, 0); // close only, no line
- paths[4].close();
+ SkPaint butt;
+ butt.setAntiAlias(antialias);
+ butt.setStyle(SkPaint::kStroke_Style);
+ butt.setStrokeWidth(width);
- auto drawPaths = [&](const SkPaint& paint) {
- canvas->translate(0, 30.0f);
- for (const SkPath& path : paths) {
- canvas->drawPath(path, paint);
+ SkPaint round(butt);
+ round.setStrokeCap(SkPaint::kRound_Cap);
+ drawPaths(round, 1 << 7);
+ return;
}
- };
-
- SkAutoCanvasRestore autoCanvasRestore(canvas, true);
-
- SkPaint butt;
- butt.setStyle(SkPaint::kStroke_Style);
- butt.setStrokeWidth(20.0f);
- butt.setStrokeCap(SkPaint::kButt_Cap);
- drawPaths(butt);
-
- SkPaint round(butt);
- round.setStrokeCap(SkPaint::kRound_Cap);
- drawPaths(round);
-
- SkPaint square(butt);
- square.setStrokeCap(SkPaint::kSquare_Cap);
- drawPaths(square);
-}
+
+ SkScalar widths[] = { 0, .999f, 1, 1.001f, 20 };
+ bool aliases[] = { false, true };
+ for (bool antialias : aliases) {
+ canvas->save();
+ for (SkScalar width : widths) {
+ canvas->save();
+ SkPaint butt;
+ butt.setAntiAlias(antialias);
+ butt.setStyle(SkPaint::kStroke_Style);
+ butt.setStrokeWidth(width);
+ drawPaths(butt, -1);
+
+ SkPaint round(butt);
+ round.setStrokeCap(SkPaint::kRound_Cap);
+ drawPaths(round, -1);
+
+ SkPaint square(butt);
+ square.setStrokeCap(SkPaint::kSquare_Cap);
+ drawPaths(square, -1);
+ canvas->restore();
+ canvas->translate(220, 0);
+ }
+ canvas->restore();
+ canvas->translate(0, 210);
+ }
+ }
+
+private:
+ void drawFat(SkCanvas* canvas, const SkPath& path, const SkPaint& paint, int index) {
+ const SkScalar scale = 10;
+ SkRect bounds = path.getBounds();
+ SkBitmap offscreen;
+ offscreen.allocN32Pixels(SkScalarRoundToInt(bounds.width() + 4),
+ SkScalarRoundToInt(bounds.height() + 4));
+ SkScalar pathX = bounds.fLeft - 2;
+ SkScalar pathY = bounds.fTop - 2;
+ SkMatrix cMatrix = canvas->getTotalMatrix();
+ if (!canvas->readPixels(&offscreen, SkScalarRoundToInt(pathX + cMatrix.getTranslateX()),
+ SkScalarRoundToInt(pathY + cMatrix.getTranslateY()))) {
+ return;
+ }
+
+ canvas->save();
+ SkMatrix clipM;
+ clipM.reset();
+ clipM.preScale(scale, scale);
+ clipM.postTranslate(bounds.fLeft - 17, bounds.fTop - 24.5f + 420);
+ SkPath clip;
+ if (index < 2) {
+ fClipL.transform(clipM, &clip);
+ } else {
+ fClipS.transform(clipM, &clip);
+ }
+ canvas->clipPath(clip, SkRegion::kIntersect_Op, true);
+ canvas->scale(scale, scale);
+ canvas->drawBitmap(offscreen, (bounds.fLeft - 17) / scale,
+ (bounds.fTop - 20 + 420) / scale);
+ canvas->restore();
+
+ if (bounds.width() > 20) {
+ canvas->save();
+ clipM.reset();
+ clipM.preScale(scale, scale);
+ clipM.postTranslate(bounds.fLeft - 17 - 275, bounds.fTop - 24.5f + 420);
+ SkPath clip;
+ fClipR.transform(clipM, &clip);
+ canvas->clipPath(clip, SkRegion::kIntersect_Op, true);
+ canvas->scale(10.f, 10.f);
+ canvas->drawBitmap(offscreen, (bounds.fLeft - 17 - 275
+ + (index >= 5 ? 5 : 0)) / scale, (bounds.fTop - 20 + 420) / scale);
+ canvas->restore();
+ }
+ }
+
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+DEF_GM( return new StrokeZeroGM(); )
+