diff options
author | caryclark <caryclark@google.com> | 2015-12-16 08:53:41 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-12-16 08:53:41 -0800 |
commit | 1f17ab59929f5f5eb399e09690ef9dbc21525ccc (patch) | |
tree | 586b48eda597366b6a061f3e9a68ebfc56285709 /gm/path_stroke_with_zero_length.cpp | |
parent | da420b976e61071cfe5de10556b4b23e519091d6 (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.cpp | 213 |
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(); ) + |