Index: samplecode/SampleQuadStroker.cpp |
diff --git a/samplecode/SampleQuadStroker.cpp b/samplecode/SampleQuadStroker.cpp |
index 88f7dfd4aea1667a2b3a31a2aaf1918f9de1d2e9..eae683f82ed29519cf119fb92d8eff0ae8f2d2aa 100644 |
--- a/samplecode/SampleQuadStroker.cpp |
+++ b/samplecode/SampleQuadStroker.cpp |
@@ -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[13].set(200, 200); // rrect |
+ fPts[14].set(400, 400); |
- fPts[12].set(250, 250); // oval |
- fPts[13].set(450, 450); |
+ 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(¢er)) { |
+ 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; |