replace arcto quads with a conic

also, remove code used only for
the quad generation

R=reed@google.com
BUG=578885
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1612543003

Review URL: https://codereview.chromium.org/1612543003
This commit is contained in:
caryclark 2016-01-20 11:55:11 -08:00 committed by Commit bot
parent 55b29b2551
commit 88651aeb55
4 changed files with 118 additions and 28 deletions

View File

@ -77,7 +77,10 @@ static void getContourCounts(const SkPath& path, SkTArray<int>* contourCounts) {
}
static void erase(SkSurface* surface) {
surface->getCanvas()->clear(SK_ColorTRANSPARENT);
SkCanvas* canvas = surface->getCanvas();
if (canvas) {
canvas->clear(SK_ColorTRANSPARENT);
}
}
struct StrokeTypeButton {
@ -97,10 +100,11 @@ class QuadStrokerView : public SampleView {
};
enum {
kCount = 15
kCount = 18
};
SkPoint fPts[kCount];
SkRect fWeightControl;
SkRect fRadiusControl;
SkRect fErrorControl;
SkRect fWidthControl;
SkRect fBounds;
@ -111,12 +115,14 @@ class QuadStrokerView : public SampleView {
StrokeTypeButton fCubicButton;
StrokeTypeButton fConicButton;
StrokeTypeButton fQuadButton;
StrokeTypeButton fArcButton;
StrokeTypeButton fRRectButton;
CircleTypeButton fCircleButton;
StrokeTypeButton fTextButton;
SkString fText;
SkScalar fTextSize;
SkScalar fWeight;
SkScalar fRadius;
SkScalar fWidth, fDWidth;
SkScalar fWidthScale;
int fW, fH, fZoom;
@ -147,32 +153,39 @@ public:
fPts[8].set(150, 200);
fPts[9].set(250, 150);
fPts[10].set(200, 200); // rrect
fPts[11].set(400, 400);
fPts[10].set(250, 200); // arc
fPts[11].set(250, 300);
fPts[12].set(150, 350);
fPts[12].set(250, 250); // oval
fPts[13].set(450, 450);
fPts[13].set(200, 200); // rrect
fPts[14].set(400, 400);
fPts[15].set(250, 250); // oval
fPts[16].set(450, 450);
fText = "a";
fTextSize = 12;
fWidth = 50;
fDWidth = 0.25f;
fWeight = 1;
fRadius = 150;
fCubicButton.fLabel = 'C';
fCubicButton.fEnabled = false;
fConicButton.fLabel = 'K';
fConicButton.fEnabled = true;
fConicButton.fEnabled = false;
fQuadButton.fLabel = 'Q';
fQuadButton.fEnabled = false;
fArcButton.fLabel = 'A';
fArcButton.fEnabled = true;
fRRectButton.fLabel = 'R';
fRRectButton.fEnabled = false;
fCircleButton.fLabel = 'O';
fCircleButton.fEnabled = false;
fCircleButton.fFill = false;
fCircleButton.fEnabled = true;
fCircleButton.fFill = true;
fTextButton.fLabel = 'T';
fTextButton.fEnabled = false;
fAnimate = true;
fAnimate = false;
setAsNeeded();
}
@ -205,6 +218,7 @@ protected:
}
void onSizeChange() override {
fRadiusControl.setXYWH(this->width() - 200, 30, 30, 400);
fWeightControl.setXYWH(this->width() - 150, 30, 30, 400);
fErrorControl.setXYWH(this->width() - 100, 30, 30, 400);
fWidthControl.setXYWH(this->width() - 50, 30, 30, 400);
@ -215,6 +229,8 @@ protected:
buttonOffset += 50;
fQuadButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30);
buttonOffset += 50;
fArcButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30);
buttonOffset += 50;
fRRectButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30);
buttonOffset += 50;
fCircleButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30);
@ -519,13 +535,47 @@ protected:
void setAsNeeded() {
if (fConicButton.fEnabled || fCubicButton.fEnabled || fQuadButton.fEnabled) {
setForSingles();
} else if (fRRectButton.fEnabled || fCircleButton.fEnabled) {
} else if (fRRectButton.fEnabled || fCircleButton.fEnabled || fArcButton.fEnabled) {
setForGeometry();
} else {
setForText();
}
}
bool arcCenter(SkPoint* center) {
SkPath path;
path.moveTo(fPts[10]);
path.arcTo(fPts[11], fPts[12], fRadius);
SkPath::Iter iter(path, false);
SkPoint pts[4];
iter.next(pts);
if (SkPath::kLine_Verb == iter.next(pts)) {
iter.next(pts);
}
SkVector before = pts[0] - pts[1];
SkVector after = pts[1] - pts[2];
before.setLength(fRadius);
after.setLength(fRadius);
SkVector beforeCCW, afterCCW;
before.rotateCCW(&beforeCCW);
after.rotateCCW(&afterCCW);
beforeCCW += pts[0];
afterCCW += pts[2];
*center = beforeCCW;
if (SkScalarNearlyEqual(beforeCCW.fX, afterCCW.fX)
&& SkScalarNearlyEqual(beforeCCW.fY, afterCCW.fY)) {
return true;
}
SkVector beforeCW, afterCW;
before.rotateCW(&beforeCW);
after.rotateCW(&afterCW);
beforeCW += pts[0];
afterCW += pts[2];
*center = beforeCW;
return SkScalarNearlyEqual(beforeCW.fX, afterCW.fX)
&& SkScalarNearlyEqual(beforeCCW.fY, afterCW.fY);
}
void onDrawContent(SkCanvas* canvas) override {
SkPath path;
SkScalar width = fWidth;
@ -553,10 +603,23 @@ protected:
draw_stroke(canvas, path, width, 950, false);
}
if (fArcButton.fEnabled) {
path.reset();
path.moveTo(fPts[10]);
path.arcTo(fPts[11], fPts[12], fRadius);
setForGeometry();
draw_stroke(canvas, path, width, 950, false);
SkPath pathPts;
pathPts.moveTo(fPts[10]);
pathPts.lineTo(fPts[11]);
pathPts.lineTo(fPts[12]);
draw_points(canvas, pathPts, SK_ColorDKGRAY, true);
}
if (fRRectButton.fEnabled) {
SkScalar rad = 32;
SkRect r;
r.set(&fPts[10], 2);
r.set(&fPts[13], 2);
path.reset();
SkRRect rr;
rr.setRectXY(r, rad, rad);
@ -579,10 +642,17 @@ protected:
if (fCircleButton.fEnabled) {
path.reset();
SkRect r;
r.set(&fPts[12], 2);
r.set(&fPts[15], 2);
path.addOval(r);
setForGeometry();
if (fCircleButton.fFill) {
if (fArcButton.fEnabled) {
SkPoint center;
if (arcCenter(&center)) {
r.set(center.fX - fRadius, center.fY - fRadius, center.fX + fRadius,
center.fY + fRadius);
}
}
draw_fill(canvas, r, width);
} else {
draw_stroke(canvas, path, width, 950, false);
@ -611,6 +681,9 @@ protected:
if (fConicButton.fEnabled) {
draw_control(canvas, fWeightControl, fWeight, 0, 5, "weight");
}
if (fArcButton.fEnabled) {
draw_control(canvas, fRadiusControl, fRadius, 0, 500, "radius");
}
#ifdef SK_DEBUG
draw_control(canvas, fErrorControl, gDebugStrokerError, kStrokerErrorMin, kStrokerErrorMax,
"error");
@ -620,6 +693,7 @@ protected:
draw_button(canvas, fQuadButton);
draw_button(canvas, fCubicButton);
draw_button(canvas, fConicButton);
draw_button(canvas, fArcButton);
draw_button(canvas, fRRectButton);
draw_button(canvas, fCircleButton);
draw_button(canvas, fTextButton);
@ -643,39 +717,46 @@ protected:
if (fWeightControl.contains(rectPt)) {
return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 1);
}
if (fRadiusControl.contains(rectPt)) {
return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 2);
}
#ifdef SK_DEBUG
if (fErrorControl.contains(rectPt)) {
return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 2);
return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 3);
}
#endif
if (fWidthControl.contains(rectPt)) {
return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 3);
return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 4);
}
if (fCubicButton.fBounds.contains(rectPt)) {
fCubicButton.fEnabled ^= true;
return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 4);
return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 5);
}
if (fConicButton.fBounds.contains(rectPt)) {
fConicButton.fEnabled ^= true;
return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 5);
return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 6);
}
if (fQuadButton.fBounds.contains(rectPt)) {
fQuadButton.fEnabled ^= true;
return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 6);
return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 7);
}
if (fArcButton.fBounds.contains(rectPt)) {
fArcButton.fEnabled ^= true;
return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 8);
}
if (fRRectButton.fBounds.contains(rectPt)) {
fRRectButton.fEnabled ^= true;
return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 7);
return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 9);
}
if (fCircleButton.fBounds.contains(rectPt)) {
bool wasEnabled = fCircleButton.fEnabled;
fCircleButton.fEnabled = !fCircleButton.fFill;
fCircleButton.fFill = wasEnabled && !fCircleButton.fFill;
return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 8);
return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 10);
}
if (fTextButton.fBounds.contains(rectPt)) {
fTextButton.fEnabled ^= true;
return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 9);
return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 11);
}
return this->INHERITED::onFindClickHandler(x, y, modi);
}
@ -693,15 +774,17 @@ protected:
this->inval(nullptr);
} else if (index == (int) SK_ARRAY_COUNT(fPts) + 1) {
fWeight = MapScreenYtoValue(click->fICurr.fY, fWeightControl, 0, 5);
} else if (index == (int) SK_ARRAY_COUNT(fPts) + 2) {
fRadius = MapScreenYtoValue(click->fICurr.fY, fRadiusControl, 0, 500);
}
#ifdef SK_DEBUG
else if (index == (int) SK_ARRAY_COUNT(fPts) + 2) {
else if (index == (int) SK_ARRAY_COUNT(fPts) + 3) {
gDebugStrokerError = SkTMax(FLT_EPSILON, MapScreenYtoValue(click->fICurr.fY,
fErrorControl, kStrokerErrorMin, kStrokerErrorMax));
gDebugStrokerErrorSet = true;
}
#endif
else if (index == (int) SK_ARRAY_COUNT(fPts) + 3) {
else if (index == (int) SK_ARRAY_COUNT(fPts) + 4) {
fWidth = SkTMax(FLT_EPSILON, MapScreenYtoValue(click->fICurr.fY, fWidthControl,
kWidthMin, kWidthMax));
fAnimate = fWidth <= kWidthMin;

View File

@ -951,6 +951,7 @@ bool SkChopMonoCubicAtX(SkPoint src[4], SkScalar x, SkPoint dst[7]) {
///////////////////////////////////////////////////////////////////////////////
#ifdef SK_SUPPORT_LEGACY_ARCTO
/* Find t value for quadratic [a, b, c] = d.
Return 0 if there is no solution within [0, 1)
*/
@ -1120,7 +1121,7 @@ int SkBuildQuadArc(const SkVector& uStart, const SkVector& uStop,
matrix.mapPoints(quadPoints, pointCount);
return pointCount;
}
#endif
///////////////////////////////////////////////////////////////////////////////
//

View File

@ -194,6 +194,7 @@ enum SkRotationDirection {
kCCW_SkRotationDirection
};
#ifdef SK_SUPPORT_LEGACY_ARCTO
/** Maximum number of points needed in the quadPoints[] parameter for
SkBuildQuadArc()
*/
@ -207,6 +208,7 @@ enum SkRotationDirection {
*/
int SkBuildQuadArc(const SkVector& unitStart, const SkVector& unitStop,
SkRotationDirection, const SkMatrix*, SkPoint quadPoints[]);
#endif
struct SkConic {
SkConic() {}

View File

@ -1301,13 +1301,16 @@ void SkPath::arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar
return;
}
SkScalar dist = SkScalarMulDiv(radius, SK_Scalar1 - cosh, sinh);
if (dist < 0) {
dist = -dist;
}
SkScalar dist = SkScalarAbs(SkScalarMulDiv(radius, SK_Scalar1 - cosh, sinh));
SkScalar xx = x1 - SkScalarMul(dist, before.fX);
SkScalar yy = y1 - SkScalarMul(dist, before.fY);
#ifndef SK_SUPPORT_LEGACY_ARCTO
after.setLength(dist);
this->lineTo(xx, yy);
SkScalar weight = SkScalarSqrt(SK_ScalarHalf + cosh * SK_ScalarHalf);
this->conicTo(x1, y1, x1 + after.fX, y1 + after.fY, weight);
#else
SkRotationDirection arcDir;
// now turn before/after into normals
@ -1336,6 +1339,7 @@ void SkPath::arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar
for (int i = 1; i < count; i += 2) {
this->quadTo(pts[i], pts[i+1]);
}
#endif
}
///////////////////////////////////////////////////////////////////////////////