2011-07-28 14:26:00 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2011 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
2011-06-18 00:15:04 +00:00
|
|
|
*/
|
|
|
|
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "gm/gm.h"
|
2019-05-01 21:28:53 +00:00
|
|
|
#include "include/core/SkCanvas.h"
|
|
|
|
#include "include/core/SkColor.h"
|
|
|
|
#include "include/core/SkPaint.h"
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "include/core/SkPath.h"
|
2019-05-01 21:28:53 +00:00
|
|
|
#include "include/core/SkPathEffect.h"
|
|
|
|
#include "include/core/SkPoint.h"
|
|
|
|
#include "include/core/SkRect.h"
|
|
|
|
#include "include/core/SkScalar.h"
|
|
|
|
#include "include/core/SkSize.h"
|
|
|
|
#include "include/core/SkString.h"
|
|
|
|
#include "include/core/SkTypes.h"
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "include/effects/SkDashPathEffect.h"
|
2019-05-01 21:28:53 +00:00
|
|
|
#include "include/private/SkFloatBits.h"
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "include/utils/SkParsePath.h"
|
|
|
|
#include "include/utils/SkRandom.h"
|
|
|
|
#include "tools/ToolUtils.h"
|
2011-06-18 00:15:04 +00:00
|
|
|
|
2019-05-01 21:28:53 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
2011-06-18 00:15:04 +00:00
|
|
|
#define W 400
|
|
|
|
#define H 400
|
|
|
|
#define N 50
|
|
|
|
|
2016-09-01 18:24:54 +00:00
|
|
|
constexpr SkScalar SW = SkIntToScalar(W);
|
|
|
|
constexpr SkScalar SH = SkIntToScalar(H);
|
2011-06-18 00:15:04 +00:00
|
|
|
|
2014-12-15 20:54:51 +00:00
|
|
|
static void rnd_rect(SkRect* r, SkPaint* paint, SkRandom& rand) {
|
2011-06-18 00:15:04 +00:00
|
|
|
SkScalar x = rand.nextUScalar1() * W;
|
|
|
|
SkScalar y = rand.nextUScalar1() * H;
|
|
|
|
SkScalar w = rand.nextUScalar1() * (W >> 2);
|
|
|
|
SkScalar h = rand.nextUScalar1() * (H >> 2);
|
2011-08-26 14:40:38 +00:00
|
|
|
SkScalar hoffset = rand.nextSScalar1();
|
|
|
|
SkScalar woffset = rand.nextSScalar1();
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2019-08-24 23:39:13 +00:00
|
|
|
r->setXYWH(x, y, w, h);
|
2011-08-26 14:40:38 +00:00
|
|
|
r->offset(-w/2 + woffset, -h/2 + hoffset);
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2011-06-18 00:15:04 +00:00
|
|
|
paint->setColor(rand.nextU());
|
2019-02-15 21:13:57 +00:00
|
|
|
paint->setAlphaf(1.0f);
|
2011-06-18 00:15:04 +00:00
|
|
|
}
|
|
|
|
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2012-06-05 16:14:23 +00:00
|
|
|
class StrokesGM : public skiagm::GM {
|
2011-06-18 00:15:04 +00:00
|
|
|
public:
|
|
|
|
StrokesGM() {}
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2011-06-18 00:15:04 +00:00
|
|
|
protected:
|
2014-04-30 13:20:45 +00:00
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
SkString onShortName() override {
|
2011-06-18 00:15:04 +00:00
|
|
|
return SkString("strokes_round");
|
|
|
|
}
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
SkISize onISize() override {
|
2012-06-05 16:14:23 +00:00
|
|
|
return SkISize::Make(W, H*2);
|
2011-06-18 00:15:04 +00:00
|
|
|
}
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
void onDraw(SkCanvas* canvas) override {
|
2011-06-18 00:15:04 +00:00
|
|
|
SkPaint paint;
|
|
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
|
|
paint.setStrokeWidth(SkIntToScalar(9)/2);
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2011-06-18 00:15:04 +00:00
|
|
|
for (int y = 0; y < 2; y++) {
|
|
|
|
paint.setAntiAlias(!!y);
|
|
|
|
SkAutoCanvasRestore acr(canvas, true);
|
|
|
|
canvas->translate(0, SH * y);
|
|
|
|
canvas->clipRect(SkRect::MakeLTRB(
|
|
|
|
SkIntToScalar(2), SkIntToScalar(2)
|
|
|
|
, SW - SkIntToScalar(2), SH - SkIntToScalar(2)
|
|
|
|
));
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2014-12-15 20:54:51 +00:00
|
|
|
SkRandom rand;
|
2011-06-18 00:15:04 +00:00
|
|
|
for (int i = 0; i < N; i++) {
|
|
|
|
SkRect r;
|
|
|
|
rnd_rect(&r, &paint, rand);
|
|
|
|
canvas->drawOval(r, paint);
|
|
|
|
rnd_rect(&r, &paint, rand);
|
|
|
|
canvas->drawRoundRect(r, r.width()/4, r.height()/4, paint);
|
|
|
|
rnd_rect(&r, &paint, rand);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2011-06-18 00:15:04 +00:00
|
|
|
private:
|
2020-09-03 02:42:33 +00:00
|
|
|
using INHERITED = skiagm::GM;
|
2011-06-18 00:15:04 +00:00
|
|
|
};
|
|
|
|
|
2015-08-26 16:04:55 +00:00
|
|
|
/* See
|
|
|
|
https://code.google.com/p/chromium/issues/detail?id=422974 and
|
|
|
|
http://jsfiddle.net/1xnku3sg/2/
|
|
|
|
*/
|
|
|
|
class ZeroLenStrokesGM : public skiagm::GM {
|
|
|
|
SkPath fMoveHfPath, fMoveZfPath, fDashedfPath, fRefPath[4];
|
2015-09-09 20:20:49 +00:00
|
|
|
SkPath fCubicPath, fQuadPath, fLinePath;
|
2015-08-26 16:04:55 +00:00
|
|
|
protected:
|
|
|
|
void onOnceBeforeDraw() override {
|
|
|
|
|
|
|
|
SkAssertResult(SkParsePath::FromSVGString("M0,0h0M10,0h0M20,0h0", &fMoveHfPath));
|
|
|
|
SkAssertResult(SkParsePath::FromSVGString("M0,0zM10,0zM20,0z", &fMoveZfPath));
|
|
|
|
SkAssertResult(SkParsePath::FromSVGString("M0,0h25", &fDashedfPath));
|
2015-09-09 20:20:49 +00:00
|
|
|
SkAssertResult(SkParsePath::FromSVGString("M 0 0 C 0 0 0 0 0 0", &fCubicPath));
|
|
|
|
SkAssertResult(SkParsePath::FromSVGString("M 0 0 Q 0 0 0 0", &fQuadPath));
|
|
|
|
SkAssertResult(SkParsePath::FromSVGString("M 0 0 L 0 0", &fLinePath));
|
2015-08-26 16:04:55 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
|
|
fRefPath[0].addCircle(i * 10.f, 0, 5);
|
|
|
|
fRefPath[1].addCircle(i * 10.f, 0, 10);
|
|
|
|
fRefPath[2].addRect(i * 10.f - 4, -2, i * 10.f + 4, 6);
|
|
|
|
fRefPath[3].addRect(i * 10.f - 10, -10, i * 10.f + 10, 10);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SkString onShortName() override {
|
|
|
|
return SkString("zeroPath");
|
|
|
|
}
|
|
|
|
|
|
|
|
SkISize onISize() override {
|
|
|
|
return SkISize::Make(W, H*2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void onDraw(SkCanvas* canvas) override {
|
|
|
|
SkPaint fillPaint, strokePaint, dashPaint;
|
|
|
|
fillPaint.setAntiAlias(true);
|
|
|
|
strokePaint = fillPaint;
|
|
|
|
strokePaint.setStyle(SkPaint::kStroke_Style);
|
|
|
|
for (int i = 0; i < 2; ++i) {
|
2019-02-15 21:13:57 +00:00
|
|
|
fillPaint.setAlphaf(1.0f);
|
|
|
|
strokePaint.setAlphaf(1.0f);
|
2015-08-26 16:04:55 +00:00
|
|
|
strokePaint.setStrokeWidth(i ? 8.f : 10.f);
|
|
|
|
strokePaint.setStrokeCap(i ? SkPaint::kSquare_Cap : SkPaint::kRound_Cap);
|
|
|
|
canvas->save();
|
|
|
|
canvas->translate(10 + i * 100.f, 10);
|
|
|
|
canvas->drawPath(fMoveHfPath, strokePaint);
|
|
|
|
canvas->translate(0, 20);
|
|
|
|
canvas->drawPath(fMoveZfPath, strokePaint);
|
|
|
|
dashPaint = strokePaint;
|
|
|
|
const SkScalar intervals[] = { 0, 10 };
|
2016-03-18 18:22:57 +00:00
|
|
|
dashPaint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0));
|
2015-08-26 16:04:55 +00:00
|
|
|
SkPath fillPath;
|
|
|
|
dashPaint.getFillPath(fDashedfPath, &fillPath);
|
|
|
|
canvas->translate(0, 20);
|
|
|
|
canvas->drawPath(fDashedfPath, dashPaint);
|
|
|
|
canvas->translate(0, 20);
|
|
|
|
canvas->drawPath(fRefPath[i * 2], fillPaint);
|
|
|
|
strokePaint.setStrokeWidth(20);
|
2019-02-15 21:13:57 +00:00
|
|
|
strokePaint.setAlphaf(0.5f);
|
2015-08-26 16:04:55 +00:00
|
|
|
canvas->translate(0, 50);
|
|
|
|
canvas->drawPath(fMoveHfPath, strokePaint);
|
|
|
|
canvas->translate(0, 30);
|
|
|
|
canvas->drawPath(fMoveZfPath, strokePaint);
|
|
|
|
canvas->translate(0, 30);
|
2019-02-15 21:13:57 +00:00
|
|
|
fillPaint.setAlphaf(0.5f);
|
2015-08-26 16:04:55 +00:00
|
|
|
canvas->drawPath(fRefPath[1 + i * 2], fillPaint);
|
2015-09-09 20:20:49 +00:00
|
|
|
canvas->translate(0, 30);
|
|
|
|
canvas->drawPath(fCubicPath, strokePaint);
|
|
|
|
canvas->translate(0, 30);
|
|
|
|
canvas->drawPath(fQuadPath, strokePaint);
|
|
|
|
canvas->translate(0, 30);
|
|
|
|
canvas->drawPath(fLinePath, strokePaint);
|
2015-08-26 16:04:55 +00:00
|
|
|
canvas->restore();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2020-09-03 02:42:33 +00:00
|
|
|
using INHERITED = skiagm::GM;
|
2015-08-26 16:04:55 +00:00
|
|
|
};
|
|
|
|
|
2015-10-26 15:17:04 +00:00
|
|
|
class TeenyStrokesGM : public skiagm::GM {
|
|
|
|
|
|
|
|
SkString onShortName() override {
|
|
|
|
return SkString("teenyStrokes");
|
|
|
|
}
|
|
|
|
|
|
|
|
SkISize onISize() override {
|
|
|
|
return SkISize::Make(W, H*2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void line(SkScalar scale, SkCanvas* canvas, SkColor color) {
|
|
|
|
SkPaint p;
|
|
|
|
p.setAntiAlias(true);
|
|
|
|
p.setStyle(SkPaint::kStroke_Style);
|
|
|
|
p.setColor(color);
|
|
|
|
canvas->translate(50, 0);
|
2020-06-26 14:10:49 +00:00
|
|
|
canvas->save();
|
2015-10-26 15:17:04 +00:00
|
|
|
p.setStrokeWidth(scale * 5);
|
2020-06-26 14:10:49 +00:00
|
|
|
canvas->scale(1 / scale, 1 / scale);
|
2015-10-26 15:17:04 +00:00
|
|
|
canvas->drawLine(20 * scale, 20 * scale, 20 * scale, 100 * scale, p);
|
|
|
|
canvas->drawLine(20 * scale, 20 * scale, 100 * scale, 100 * scale, p);
|
|
|
|
canvas->restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
void onDraw(SkCanvas* canvas) override {
|
|
|
|
line(0.00005f, canvas, SK_ColorBLACK);
|
|
|
|
line(0.000045f, canvas, SK_ColorRED);
|
|
|
|
line(0.0000035f, canvas, SK_ColorGREEN);
|
|
|
|
line(0.000003f, canvas, SK_ColorBLUE);
|
|
|
|
line(0.000002f, canvas, SK_ColorBLACK);
|
|
|
|
}
|
|
|
|
private:
|
2020-09-03 02:42:33 +00:00
|
|
|
using INHERITED = skiagm::GM;
|
2015-10-26 15:17:04 +00:00
|
|
|
};
|
|
|
|
|
2015-11-30 21:47:11 +00:00
|
|
|
DEF_SIMPLE_GM(CubicStroke, canvas, 384, 384) {
|
|
|
|
SkPaint p;
|
|
|
|
p.setAntiAlias(true);
|
|
|
|
p.setStyle(SkPaint::kStroke_Style);
|
|
|
|
p.setStrokeWidth(1.0720f);
|
2020-06-26 14:10:49 +00:00
|
|
|
SkPath path;
|
2015-11-30 21:47:11 +00:00
|
|
|
path.moveTo(-6000,-6000);
|
|
|
|
path.cubicTo(-3500,5500,-500,5500,2500,-6500);
|
|
|
|
canvas->drawPath(path, p);
|
|
|
|
p.setStrokeWidth(1.0721f);
|
|
|
|
canvas->translate(10, 10);
|
|
|
|
canvas->drawPath(path, p);
|
|
|
|
p.setStrokeWidth(1.0722f);
|
|
|
|
canvas->translate(10, 10);
|
|
|
|
canvas->drawPath(path, p);
|
|
|
|
}
|
2015-10-26 15:17:04 +00:00
|
|
|
|
2015-12-08 12:29:45 +00:00
|
|
|
DEF_SIMPLE_GM(zerolinestroke, canvas, 90, 120) {
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
|
|
paint.setStrokeWidth(20);
|
|
|
|
paint.setAntiAlias(true);
|
|
|
|
paint.setStrokeCap(SkPaint::kRound_Cap);
|
|
|
|
|
|
|
|
SkPath path;
|
|
|
|
path.moveTo(30, 90);
|
|
|
|
path.lineTo(30, 90);
|
|
|
|
path.lineTo(60, 90);
|
|
|
|
path.lineTo(60, 90);
|
|
|
|
canvas->drawPath(path, paint);
|
|
|
|
|
|
|
|
path.reset();
|
|
|
|
path.moveTo(30, 30);
|
|
|
|
path.lineTo(60, 30);
|
|
|
|
canvas->drawPath(path, paint);
|
|
|
|
|
|
|
|
path.reset();
|
|
|
|
path.moveTo(30, 60);
|
|
|
|
path.lineTo(30, 60);
|
|
|
|
path.lineTo(60, 60);
|
|
|
|
canvas->drawPath(path, paint);
|
|
|
|
}
|
|
|
|
|
2015-12-22 14:13:33 +00:00
|
|
|
DEF_SIMPLE_GM(quadcap, canvas, 200, 200) {
|
|
|
|
SkPaint p;
|
|
|
|
p.setAntiAlias(true);
|
|
|
|
p.setStyle(SkPaint::kStroke_Style);
|
|
|
|
p.setStrokeWidth(0);
|
|
|
|
SkPath path;
|
|
|
|
SkPoint pts[] = {{105.738571f,13.126318f},
|
2016-03-29 16:03:52 +00:00
|
|
|
{105.738571f,13.126318f},
|
2015-12-22 14:13:33 +00:00
|
|
|
{123.753784f,1.f}};
|
|
|
|
SkVector tangent = pts[1] - pts[2];
|
|
|
|
tangent.normalize();
|
|
|
|
SkPoint pts2[3];
|
|
|
|
memcpy(pts2, pts, sizeof(pts));
|
|
|
|
const SkScalar capOutset = SK_ScalarPI / 8;
|
|
|
|
pts2[0].fX += tangent.fX * capOutset;
|
|
|
|
pts2[0].fY += tangent.fY * capOutset;
|
|
|
|
pts2[1].fX += tangent.fX * capOutset;
|
|
|
|
pts2[1].fY += tangent.fY * capOutset;
|
|
|
|
pts2[2].fX += -tangent.fX * capOutset;
|
|
|
|
pts2[2].fY += -tangent.fY * capOutset;
|
|
|
|
path.moveTo(pts2[0]);
|
|
|
|
path.quadTo(pts2[1], pts2[2]);
|
|
|
|
canvas->drawPath(path, p);
|
|
|
|
|
|
|
|
path.reset();
|
|
|
|
path.moveTo(pts[0]);
|
|
|
|
path.quadTo(pts[1], pts[2]);
|
|
|
|
p.setStrokeCap(SkPaint::kRound_Cap);
|
|
|
|
canvas->translate(30, 0);
|
|
|
|
canvas->drawPath(path, p);
|
|
|
|
}
|
|
|
|
|
2012-06-05 16:14:23 +00:00
|
|
|
class Strokes2GM : public skiagm::GM {
|
2011-06-18 00:15:04 +00:00
|
|
|
SkPath fPath;
|
2015-02-25 17:04:04 +00:00
|
|
|
protected:
|
2015-03-26 01:17:31 +00:00
|
|
|
void onOnceBeforeDraw() override {
|
2014-12-15 20:54:51 +00:00
|
|
|
SkRandom rand;
|
2011-06-18 00:15:04 +00:00
|
|
|
fPath.moveTo(0, 0);
|
|
|
|
for (int i = 0; i < 13; i++) {
|
|
|
|
SkScalar x = rand.nextUScalar1() * (W >> 1);
|
|
|
|
SkScalar y = rand.nextUScalar1() * (H >> 1);
|
|
|
|
fPath.lineTo(x, y);
|
|
|
|
}
|
|
|
|
}
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2014-04-30 13:20:45 +00:00
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
SkString onShortName() override {
|
2011-06-18 00:15:04 +00:00
|
|
|
return SkString("strokes_poly");
|
|
|
|
}
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
SkISize onISize() override {
|
2012-06-05 16:14:23 +00:00
|
|
|
return SkISize::Make(W, H*2);
|
2011-06-18 00:15:04 +00:00
|
|
|
}
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
void onDraw(SkCanvas* canvas) override {
|
2011-06-18 00:15:04 +00:00
|
|
|
canvas->drawColor(SK_ColorWHITE);
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2011-06-18 00:15:04 +00:00
|
|
|
SkPaint paint;
|
|
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
|
|
paint.setStrokeWidth(SkIntToScalar(9)/2);
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2011-06-18 00:15:04 +00:00
|
|
|
for (int y = 0; y < 2; y++) {
|
|
|
|
paint.setAntiAlias(!!y);
|
|
|
|
SkAutoCanvasRestore acr(canvas, true);
|
|
|
|
canvas->translate(0, SH * y);
|
|
|
|
canvas->clipRect(SkRect::MakeLTRB(SkIntToScalar(2),
|
|
|
|
SkIntToScalar(2),
|
|
|
|
SW - SkIntToScalar(2),
|
|
|
|
SH - SkIntToScalar(2)));
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2014-12-15 20:54:51 +00:00
|
|
|
SkRandom rand;
|
2011-06-18 00:15:04 +00:00
|
|
|
for (int i = 0; i < N/2; i++) {
|
|
|
|
SkRect r;
|
|
|
|
rnd_rect(&r, &paint, rand);
|
2016-07-12 22:01:19 +00:00
|
|
|
canvas->rotate(SkIntToScalar(15), SW/2, SH/2);
|
2011-06-18 00:15:04 +00:00
|
|
|
canvas->drawPath(fPath, paint);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2011-06-18 00:15:04 +00:00
|
|
|
private:
|
2020-09-03 02:42:33 +00:00
|
|
|
using INHERITED = skiagm::GM;
|
2011-06-18 00:15:04 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2012-06-05 16:14:23 +00:00
|
|
|
static SkRect inset(const SkRect& r) {
|
|
|
|
SkRect rr(r);
|
|
|
|
rr.inset(r.width()/10, r.height()/10);
|
|
|
|
return rr;
|
|
|
|
}
|
2011-06-18 00:15:04 +00:00
|
|
|
|
2012-06-05 16:14:23 +00:00
|
|
|
class Strokes3GM : public skiagm::GM {
|
|
|
|
static void make0(SkPath* path, const SkRect& bounds, SkString* title) {
|
2019-11-22 18:34:02 +00:00
|
|
|
path->addRect(bounds, SkPathDirection::kCW);
|
|
|
|
path->addRect(inset(bounds), SkPathDirection::kCW);
|
2012-06-05 16:14:23 +00:00
|
|
|
title->set("CW CW");
|
|
|
|
}
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2012-06-05 16:14:23 +00:00
|
|
|
static void make1(SkPath* path, const SkRect& bounds, SkString* title) {
|
2019-11-22 18:34:02 +00:00
|
|
|
path->addRect(bounds, SkPathDirection::kCW);
|
|
|
|
path->addRect(inset(bounds), SkPathDirection::kCCW);
|
2012-06-05 16:14:23 +00:00
|
|
|
title->set("CW CCW");
|
|
|
|
}
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2012-06-05 16:14:23 +00:00
|
|
|
static void make2(SkPath* path, const SkRect& bounds, SkString* title) {
|
2019-11-22 18:34:02 +00:00
|
|
|
path->addOval(bounds, SkPathDirection::kCW);
|
|
|
|
path->addOval(inset(bounds), SkPathDirection::kCW);
|
2012-06-05 16:14:23 +00:00
|
|
|
title->set("CW CW");
|
|
|
|
}
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2012-06-05 16:14:23 +00:00
|
|
|
static void make3(SkPath* path, const SkRect& bounds, SkString* title) {
|
2019-11-22 18:34:02 +00:00
|
|
|
path->addOval(bounds, SkPathDirection::kCW);
|
|
|
|
path->addOval(inset(bounds), SkPathDirection::kCCW);
|
2012-06-05 16:14:23 +00:00
|
|
|
title->set("CW CCW");
|
|
|
|
}
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2012-06-05 16:14:23 +00:00
|
|
|
static void make4(SkPath* path, const SkRect& bounds, SkString* title) {
|
2019-11-22 18:34:02 +00:00
|
|
|
path->addRect(bounds, SkPathDirection::kCW);
|
2012-06-05 16:14:23 +00:00
|
|
|
SkRect r = bounds;
|
|
|
|
r.inset(bounds.width() / 10, -bounds.height() / 10);
|
2019-11-22 18:34:02 +00:00
|
|
|
path->addOval(r, SkPathDirection::kCW);
|
2012-06-05 16:14:23 +00:00
|
|
|
title->set("CW CW");
|
|
|
|
}
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2012-06-05 16:14:23 +00:00
|
|
|
static void make5(SkPath* path, const SkRect& bounds, SkString* title) {
|
2019-11-22 18:34:02 +00:00
|
|
|
path->addRect(bounds, SkPathDirection::kCW);
|
2012-06-05 16:14:23 +00:00
|
|
|
SkRect r = bounds;
|
|
|
|
r.inset(bounds.width() / 10, -bounds.height() / 10);
|
2019-11-22 18:34:02 +00:00
|
|
|
path->addOval(r, SkPathDirection::kCCW);
|
2012-06-05 16:14:23 +00:00
|
|
|
title->set("CW CCW");
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
Strokes3GM() {}
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2012-06-05 16:14:23 +00:00
|
|
|
protected:
|
2014-04-30 13:20:45 +00:00
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
SkString onShortName() override {
|
2012-06-05 16:14:23 +00:00
|
|
|
return SkString("strokes3");
|
|
|
|
}
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
SkISize onISize() override {
|
2015-02-23 14:51:04 +00:00
|
|
|
return SkISize::Make(1500, 1500);
|
2012-06-05 16:14:23 +00:00
|
|
|
}
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
void onDraw(SkCanvas* canvas) override {
|
2012-06-05 16:14:23 +00:00
|
|
|
SkPaint origPaint;
|
|
|
|
origPaint.setAntiAlias(true);
|
|
|
|
origPaint.setStyle(SkPaint::kStroke_Style);
|
|
|
|
SkPaint fillPaint(origPaint);
|
|
|
|
fillPaint.setColor(SK_ColorRED);
|
|
|
|
SkPaint strokePaint(origPaint);
|
2019-03-20 16:12:10 +00:00
|
|
|
strokePaint.setColor(ToolUtils::color_to_565(0xFF4444FF));
|
2012-06-05 16:14:23 +00:00
|
|
|
|
|
|
|
void (*procs[])(SkPath*, const SkRect&, SkString*) = {
|
|
|
|
make0, make1, make2, make3, make4, make5
|
|
|
|
};
|
|
|
|
|
2015-02-23 14:51:04 +00:00
|
|
|
canvas->translate(SkIntToScalar(20), SkIntToScalar(80));
|
2012-06-05 16:14:23 +00:00
|
|
|
|
|
|
|
SkRect bounds = SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(50));
|
|
|
|
SkScalar dx = bounds.width() * 4/3;
|
|
|
|
SkScalar dy = bounds.height() * 5;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < SK_ARRAY_COUNT(procs); ++i) {
|
|
|
|
SkPath orig;
|
|
|
|
SkString str;
|
|
|
|
procs[i](&orig, bounds, &str);
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2012-06-05 16:14:23 +00:00
|
|
|
canvas->save();
|
|
|
|
for (int j = 0; j < 13; ++j) {
|
|
|
|
strokePaint.setStrokeWidth(SK_Scalar1 * j * j);
|
|
|
|
canvas->drawPath(orig, strokePaint);
|
|
|
|
canvas->drawPath(orig, origPaint);
|
|
|
|
SkPath fill;
|
|
|
|
strokePaint.getFillPath(orig, &fill);
|
|
|
|
canvas->drawPath(fill, fillPaint);
|
|
|
|
canvas->translate(dx + strokePaint.getStrokeWidth(), 0);
|
|
|
|
}
|
|
|
|
canvas->restore();
|
|
|
|
canvas->translate(0, dy);
|
|
|
|
}
|
|
|
|
}
|
2012-08-23 18:19:56 +00:00
|
|
|
|
2012-06-05 16:14:23 +00:00
|
|
|
private:
|
2020-09-03 02:42:33 +00:00
|
|
|
using INHERITED = skiagm::GM;
|
2012-06-05 16:14:23 +00:00
|
|
|
};
|
|
|
|
|
2015-05-19 18:05:37 +00:00
|
|
|
class Strokes4GM : public skiagm::GM {
|
|
|
|
public:
|
|
|
|
Strokes4GM() {}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
SkString onShortName() override {
|
|
|
|
return SkString("strokes_zoomed");
|
|
|
|
}
|
|
|
|
|
|
|
|
SkISize onISize() override {
|
|
|
|
return SkISize::Make(W, H*2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void onDraw(SkCanvas* canvas) override {
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
|
|
paint.setStrokeWidth(0.055f);
|
2016-03-29 16:03:52 +00:00
|
|
|
|
2015-05-19 18:05:37 +00:00
|
|
|
canvas->scale(1000, 1000);
|
|
|
|
canvas->drawCircle(0, 2, 1.97f, paint);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2020-09-03 02:42:33 +00:00
|
|
|
using INHERITED = skiagm::GM;
|
2015-05-19 18:05:37 +00:00
|
|
|
};
|
|
|
|
|
2015-08-25 20:19:06 +00:00
|
|
|
// Test stroking for curves that produce degenerate tangents when t is 0 or 1 (see bug 4191)
|
|
|
|
class Strokes5GM : public skiagm::GM {
|
|
|
|
public:
|
|
|
|
Strokes5GM() {}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
SkString onShortName() override {
|
|
|
|
return SkString("zero_control_stroke");
|
|
|
|
}
|
|
|
|
|
|
|
|
SkISize onISize() override {
|
|
|
|
return SkISize::Make(W, H*2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void onDraw(SkCanvas* canvas) override {
|
|
|
|
SkPaint p;
|
|
|
|
p.setColor(SK_ColorRED);
|
|
|
|
p.setAntiAlias(true);
|
|
|
|
p.setStyle(SkPaint::kStroke_Style);
|
|
|
|
p.setStrokeWidth(40);
|
|
|
|
p.setStrokeCap(SkPaint::kButt_Cap);
|
|
|
|
|
|
|
|
SkPath path;
|
|
|
|
path.moveTo(157.474f,111.753f);
|
|
|
|
path.cubicTo(128.5f,111.5f,35.5f,29.5f,35.5f,29.5f);
|
|
|
|
canvas->drawPath(path, p);
|
|
|
|
path.reset();
|
|
|
|
path.moveTo(250, 50);
|
|
|
|
path.quadTo(280, 80, 280, 80);
|
|
|
|
canvas->drawPath(path, p);
|
|
|
|
path.reset();
|
|
|
|
path.moveTo(150, 50);
|
|
|
|
path.conicTo(180, 80, 180, 80, 0.707f);
|
|
|
|
canvas->drawPath(path, p);
|
|
|
|
|
|
|
|
path.reset();
|
|
|
|
path.moveTo(157.474f,311.753f);
|
|
|
|
path.cubicTo(157.474f,311.753f,85.5f,229.5f,35.5f,229.5f);
|
|
|
|
canvas->drawPath(path, p);
|
|
|
|
path.reset();
|
|
|
|
path.moveTo(280, 250);
|
|
|
|
path.quadTo(280, 250, 310, 280);
|
|
|
|
canvas->drawPath(path, p);
|
|
|
|
path.reset();
|
|
|
|
path.moveTo(180, 250);
|
|
|
|
path.conicTo(180, 250, 210, 280, 0.707f);
|
|
|
|
canvas->drawPath(path, p);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2020-09-03 02:42:33 +00:00
|
|
|
using INHERITED = skiagm::GM;
|
2015-08-25 20:19:06 +00:00
|
|
|
};
|
|
|
|
|
2015-05-19 18:05:37 +00:00
|
|
|
|
2012-06-05 16:14:23 +00:00
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2015-12-10 21:31:59 +00:00
|
|
|
DEF_GM( return new StrokesGM; )
|
|
|
|
DEF_GM( return new Strokes2GM; )
|
|
|
|
DEF_GM( return new Strokes3GM; )
|
|
|
|
DEF_GM( return new Strokes4GM; )
|
|
|
|
DEF_GM( return new Strokes5GM; )
|
2015-08-26 16:04:55 +00:00
|
|
|
|
2015-08-26 20:07:48 +00:00
|
|
|
DEF_GM( return new ZeroLenStrokesGM; )
|
2015-10-26 15:17:04 +00:00
|
|
|
DEF_GM( return new TeenyStrokesGM; )
|
2017-12-13 17:47:15 +00:00
|
|
|
|
|
|
|
DEF_SIMPLE_GM(zerolinedash, canvas, 256, 256) {
|
|
|
|
canvas->clear(SK_ColorWHITE);
|
|
|
|
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setColor(SkColorSetARGB(255, 0, 0, 0));
|
|
|
|
paint.setStrokeWidth(11);
|
|
|
|
paint.setStrokeCap(SkPaint::kRound_Cap);
|
|
|
|
paint.setStrokeJoin(SkPaint::kBevel_Join);
|
|
|
|
|
|
|
|
SkScalar dash_pattern[] = {1, 5};
|
|
|
|
paint.setPathEffect(SkDashPathEffect::Make(dash_pattern, 2, 0));
|
|
|
|
|
|
|
|
canvas->drawLine(100, 100, 100, 100, paint);
|
|
|
|
}
|
2017-12-21 14:55:00 +00:00
|
|
|
|
|
|
|
#ifdef PDF_IS_FIXED_SO_THIS_DOESNT_BREAK_IT
|
|
|
|
DEF_SIMPLE_GM(longrect_dash, canvas, 250, 250) {
|
|
|
|
canvas->clear(SK_ColorWHITE);
|
|
|
|
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setColor(SkColorSetARGB(255, 0, 0, 0));
|
|
|
|
paint.setStrokeWidth(5);
|
|
|
|
paint.setStrokeCap(SkPaint::kRound_Cap);
|
|
|
|
paint.setStrokeJoin(SkPaint::kBevel_Join);
|
|
|
|
paint.setStyle(SkPaint::kStroke_Style);
|
|
|
|
SkScalar dash_pattern[] = {1, 5};
|
|
|
|
paint.setPathEffect(SkDashPathEffect::Make(dash_pattern, 2, 0));
|
|
|
|
// try all combinations of stretching bounds
|
|
|
|
for (auto left : { 20.f, -100001.f } ) {
|
|
|
|
for (auto top : { 20.f, -100001.f } ) {
|
|
|
|
for (auto right : { 40.f, 100001.f } ) {
|
|
|
|
for (auto bottom : { 40.f, 100001.f } ) {
|
|
|
|
canvas->save();
|
|
|
|
canvas->clipRect({10, 10, 50, 50});
|
|
|
|
canvas->drawRect({left, top, right, bottom}, paint);
|
|
|
|
canvas->restore();
|
|
|
|
canvas->translate(60, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
canvas->translate(-60 * 4, 60);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2021-05-25 13:11:59 +00:00
|
|
|
|
|
|
|
DEF_SIMPLE_GM(inner_join_geometry, canvas, 1000, 700) {
|
|
|
|
// These paths trigger cases where we must add inner join geometry.
|
|
|
|
// skbug.com/11964
|
|
|
|
const SkPoint pathPoints[] = {
|
|
|
|
/*moveTo*/ /*lineTo*/ /*lineTo*/
|
|
|
|
{119, 71}, {129, 151}, {230, 24},
|
|
|
|
{200, 144}, {129, 151}, {230, 24},
|
|
|
|
{192, 176}, {224, 175}, {281, 103},
|
|
|
|
{233, 205}, {224, 175}, {281, 103},
|
|
|
|
{121, 216}, {234, 189}, {195, 147},
|
|
|
|
{141, 216}, {254, 189}, {238, 250},
|
|
|
|
{159, 202}, {269, 197}, {289, 165},
|
|
|
|
{159, 202}, {269, 197}, {287, 227},
|
|
|
|
};
|
|
|
|
|
|
|
|
SkPaint pathPaint;
|
|
|
|
pathPaint.setStroke(true);
|
|
|
|
pathPaint.setAntiAlias(true);
|
|
|
|
pathPaint.setStrokeWidth(100);
|
|
|
|
|
|
|
|
SkPaint skeletonPaint;
|
|
|
|
skeletonPaint.setStroke(true);
|
|
|
|
skeletonPaint.setAntiAlias(true);
|
|
|
|
skeletonPaint.setStrokeWidth(0);
|
|
|
|
skeletonPaint.setColor(SK_ColorRED);
|
|
|
|
|
|
|
|
canvas->translate(0, 50);
|
|
|
|
for (size_t i = 0; i < SK_ARRAY_COUNT(pathPoints) / 3; i++) {
|
|
|
|
auto path = SkPath::Polygon(pathPoints + i * 3, 3, false);
|
|
|
|
canvas->drawPath(path, pathPaint);
|
|
|
|
|
|
|
|
SkPath fillPath;
|
|
|
|
pathPaint.getFillPath(path, &fillPath);
|
|
|
|
canvas->drawPath(fillPath, skeletonPaint);
|
|
|
|
|
|
|
|
canvas->translate(200, 0);
|
|
|
|
if ((i + 1) % 4 == 0) {
|
|
|
|
canvas->translate(-800, 200);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
Fix nearly flat edge detection in GrTriangulator
Adds a GM reproducing triangulator failure. The stroker generated
geometry shown in the GM had two edges intersecting on the inner
contour. One of the edges was practically vertical, such that its top
and bottom vertices X coordinates differed by 1ulp (approx 4.8e-7 when
x = 7.5). The intersection was computed correctly in double but then
clamped to exactly 7.5 when stored back in float at (7.5, ~11), which
is still a reasonable intersection point along the edge represented
by (7.5,0) to (7.5000048,~68).
However, with a sorting direction of horizontal for the vertices,
vertices are sorted on increasing x and then *decreasing* y. The
computed intersection is then technically above the edge's top
vertex. In the original code, the edge was not considered flat, so
it assumes that the intersection vertex is below the top vertex
and above the bottom vertex.
The issue was with the nearly_flat function only checking the difference
against machine epsilon without taking the magnitude of the vertices
into account. However, just changing nearly_flat to use ulp instead of
epsilon led to infinite recursion and asserts on a number of tests due
to inaccuracies in edge intersection tests. To address these issues,
I reworked clamp() to work on X and Y independently, which avoids the
need to check nearly_flat entirely. Additionally, edge intersection
detects when it might be inaccurate due to really large vertex coords
and recursively splits to reject false positives.
Bug: skia:12244
Change-Id: I9a92a163e8c53af799332f1f9369fccd3a9fbf31
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/432196
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
2021-08-03 19:05:26 +00:00
|
|
|
|
|
|
|
DEF_SIMPLE_GM(skbug12244, canvas, 150, 150) {
|
|
|
|
// Should look like a stroked triangle; these vertices are the results of the SkStroker
|
|
|
|
// but we draw as a filled path in order to highlight that it's the GPU triangulating path
|
|
|
|
// renderer that's the source of the problem, and not the stroking operation. The original
|
|
|
|
// path was a simple:
|
|
|
|
// m(0,0), l(100, 40), l(0, 80), l(0,0) with a stroke width of 15px
|
|
|
|
SkPath path;
|
|
|
|
path.moveTo(2.7854299545288085938, -6.9635753631591796875);
|
|
|
|
path.lineTo( 120.194366455078125, 40);
|
|
|
|
path.lineTo(-7.5000004768371582031, 91.07775115966796875);
|
|
|
|
path.lineTo(-7.5000004768371582031, -11.077748298645019531);
|
|
|
|
path.lineTo(2.7854299545288085938, -6.9635753631591796875);
|
|
|
|
path.moveTo(-2.7854299545288085938, 6.9635753631591796875);
|
|
|
|
path.lineTo( 0, 0);
|
|
|
|
path.lineTo( 7.5, 0);
|
|
|
|
path.lineTo(7.5000004768371582031, 68.92224884033203125);
|
|
|
|
path.lineTo( 79.805633544921875, 40);
|
|
|
|
path.lineTo(-2.7854299545288085938, 6.9635753631591796875);
|
|
|
|
|
|
|
|
SkPaint p;
|
|
|
|
p.setColor(SK_ColorGREEN);
|
|
|
|
|
|
|
|
canvas->translate(20.f, 20.f);
|
|
|
|
canvas->drawPath(path, p);
|
|
|
|
}
|