Index: samplecode/SampleQuadStroker.cpp |
diff --git a/samplecode/SampleQuadStroker.cpp b/samplecode/SampleQuadStroker.cpp |
index 4fd6e7434b691ae55083c69a4fb0ac8afd3dc5f3..a3863a89917d826e19e689d16ef8a7061f2bb235 100644 |
--- a/samplecode/SampleQuadStroker.cpp |
+++ b/samplecode/SampleQuadStroker.cpp |
@@ -85,6 +85,10 @@ struct StrokeTypeButton { |
bool fEnabled; |
}; |
+struct CircleTypeButton : public StrokeTypeButton { |
+ bool fFill; |
+}; |
+ |
class QuadStrokerView : public SampleView { |
enum { |
SKELETON_COLOR = 0xFF0000FF, |
@@ -92,9 +96,10 @@ class QuadStrokerView : public SampleView { |
}; |
enum { |
- kCount = 10 |
+ kCount = 15 |
}; |
SkPoint fPts[kCount]; |
+ SkRect fWeightControl; |
SkRect fErrorControl; |
SkRect fWidthControl; |
SkRect fBounds; |
@@ -103,11 +108,14 @@ class QuadStrokerView : public SampleView { |
SkAutoTUnref<SkSurface> fMinSurface; |
SkAutoTUnref<SkSurface> fMaxSurface; |
StrokeTypeButton fCubicButton; |
+ StrokeTypeButton fConicButton; |
StrokeTypeButton fQuadButton; |
StrokeTypeButton fRRectButton; |
+ CircleTypeButton fCircleButton; |
StrokeTypeButton fTextButton; |
SkString fText; |
SkScalar fTextSize; |
+ SkScalar fWeight; |
SkScalar fWidth, fDWidth; |
SkScalar fWidthScale; |
int fW, fH, fZoom; |
@@ -124,32 +132,44 @@ public: |
QuadStrokerView() { |
this->setBGColor(SK_ColorLTGRAY); |
- fPts[0].set(50, 200); |
+ fPts[0].set(50, 200); // cubic |
fPts[1].set(50, 100); |
fPts[2].set(150, 50); |
fPts[3].set(300, 50); |
- fPts[4].set(350, 200); |
+ fPts[4].set(350, 200); // conic |
fPts[5].set(350, 100); |
fPts[6].set(450, 50); |
- fPts[7].set(200, 200); |
- fPts[8].set(400, 400); |
+ fPts[7].set(150, 300); // quad |
+ fPts[8].set(150, 200); |
+ fPts[9].set(250, 150); |
+ |
+ fPts[10].set(200, 200); // rrect |
+ fPts[11].set(400, 400); |
+ |
+ fPts[12].set(250, 250); // oval |
+ fPts[13].set(450, 450); |
- fPts[9].set(250, 800); |
fText = "a"; |
fTextSize = 12; |
fWidth = 50; |
fDWidth = 0.25f; |
+ fWeight = 1; |
fCubicButton.fLabel = 'C'; |
fCubicButton.fEnabled = false; |
+ fConicButton.fLabel = 'K'; |
+ fConicButton.fEnabled = true; |
fQuadButton.fLabel = 'Q'; |
fQuadButton.fEnabled = false; |
fRRectButton.fLabel = 'R'; |
fRRectButton.fEnabled = false; |
+ fCircleButton.fLabel = 'O'; |
+ fCircleButton.fEnabled = false; |
+ fCircleButton.fFill = false; |
fTextButton.fLabel = 'T'; |
- fTextButton.fEnabled = true; |
+ fTextButton.fEnabled = false; |
fAnimate = true; |
setAsNeeded(); |
} |
@@ -183,12 +203,21 @@ protected: |
} |
void onSizeChange() SK_OVERRIDE { |
+ fWeightControl.setXYWH(this->width() - 150, 30, 30, 400); |
fErrorControl.setXYWH(this->width() - 100, 30, 30, 400); |
fWidthControl.setXYWH(this->width() - 50, 30, 30, 400); |
- fCubicButton.fBounds.setXYWH(this->width() - 50, 450, 30, 30); |
- fQuadButton.fBounds.setXYWH(this->width() - 50, 500, 30, 30); |
- fRRectButton.fBounds.setXYWH(this->width() - 50, 550, 30, 30); |
- fTextButton.fBounds.setXYWH(this->width() - 50, 600, 30, 30); |
+ int buttonOffset = 450; |
+ fCubicButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30); |
+ buttonOffset += 50; |
+ fConicButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30); |
+ buttonOffset += 50; |
+ fQuadButton.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); |
+ buttonOffset += 50; |
+ fTextButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30); |
this->INHERITED::onSizeChange(); |
} |
@@ -273,25 +302,26 @@ protected: |
} |
} |
- void draw_stroke(SkCanvas* canvas, const SkPath& path, SkScalar width, bool drawText) { |
+ void draw_stroke(SkCanvas* canvas, const SkPath& path, SkScalar width, SkScalar scale, |
+ bool drawText) { |
SkRect bounds = path.getBounds(); |
if (bounds.isEmpty()) { |
return; |
} |
- this->setWHZ(SkScalarCeilToInt(bounds.right()), SkScalarRoundToInt(fTextSize * 3 / 2), |
- SkScalarRoundToInt(950.0f / fTextSize)); |
+ this->setWHZ(SkScalarCeilToInt(bounds.right()), drawText |
+ ? SkScalarRoundToInt(scale * 3 / 2) : SkScalarRoundToInt(scale), |
+ SkScalarRoundToInt(950.0f / scale)); |
erase(fMinSurface); |
SkPaint paint; |
paint.setColor(0x1f1f0f0f); |
- fMinSurface->getCanvas()->drawPath(path, paint); |
paint.setStyle(SkPaint::kStroke_Style); |
- paint.setStrokeWidth(width * fTextSize * fTextSize); |
+ paint.setStrokeWidth(width * scale * scale); |
paint.setColor(0x3f0f1f3f); |
- fMinSurface->getCanvas()->drawPath(path, paint); |
- |
- this->copyMinToMax(); |
- fMaxSurface->draw(canvas, 0, 0, NULL); |
- |
+ if (drawText) { |
+ fMinSurface->getCanvas()->drawPath(path, paint); |
+ this->copyMinToMax(); |
+ fMaxSurface->draw(canvas, 0, 0, NULL); |
+ } |
paint.setAntiAlias(true); |
paint.setStyle(SkPaint::kStroke_Style); |
paint.setStrokeWidth(1); |
@@ -300,7 +330,7 @@ protected: |
SkPath scaled; |
SkMatrix matrix; |
matrix.reset(); |
- matrix.setScale(950 / fTextSize, 950 / fTextSize); |
+ matrix.setScale(950 / scale, 950 / scale); |
if (drawText) { |
path.transform(matrix, &scaled); |
} else { |
@@ -317,8 +347,11 @@ protected: |
SkPaint p; |
p.setStyle(SkPaint::kStroke_Style); |
- p.setStrokeWidth(width * fTextSize * fTextSize); |
- |
+ if (drawText) { |
+ p.setStrokeWidth(width * scale * scale); |
+ } else { |
+ p.setStrokeWidth(width); |
+ } |
p.getFillPath(path, &fill); |
SkPath scaledFill; |
if (drawText) { |
@@ -331,6 +364,33 @@ protected: |
draw_points(canvas, scaledFill, WIREFRAME_COLOR, false); |
} |
+ void draw_fill(SkCanvas* canvas, const SkRect& rect, SkScalar width) { |
+ if (rect.isEmpty()) { |
+ return; |
+ } |
+ SkPaint paint; |
+ paint.setColor(0x1f1f0f0f); |
+ paint.setStyle(SkPaint::kStroke_Style); |
+ paint.setStrokeWidth(width); |
+ SkPath path; |
+ SkScalar maxSide = SkTMax(rect.width(), rect.height()) / 2; |
+ SkPoint center = { rect.fLeft + maxSide, rect.fTop + maxSide }; |
+ path.addCircle(center.fX, center.fY, maxSide); |
+ canvas->drawPath(path, paint); |
+ paint.setStyle(SkPaint::kFill_Style); |
+ path.reset(); |
+ path.addCircle(center.fX, center.fY, maxSide - width / 2); |
+ paint.setColor(0x3f0f1f3f); |
+ canvas->drawPath(path, paint); |
+ path.reset(); |
+ path.setFillType(SkPath::kEvenOdd_FillType); |
+ path.addCircle(center.fX, center.fY, maxSide + width / 2); |
+ SkRect outside = SkRect::MakeXYWH(center.fX - maxSide - width, center.fY - maxSide - width, |
+ (maxSide + width) * 2, (maxSide + width) * 2); |
+ path.addRect(outside); |
+ canvas->drawPath(path, paint); |
+ } |
+ |
void draw_button(SkCanvas* canvas, const StrokeTypeButton& button) { |
SkPaint paint; |
paint.setAntiAlias(true); |
@@ -377,7 +437,8 @@ protected: |
} |
void setAsNeeded() { |
- if (fCubicButton.fEnabled || fQuadButton.fEnabled || fRRectButton.fEnabled) { |
+ if (fConicButton.fEnabled || fCubicButton.fEnabled || fQuadButton.fEnabled |
+ || fRRectButton.fEnabled || fCircleButton.fEnabled) { |
setForGeometry(); |
} else { |
setForText(); |
@@ -392,27 +453,34 @@ protected: |
path.moveTo(fPts[0]); |
path.cubicTo(fPts[1], fPts[2], fPts[3]); |
setForGeometry(); |
- draw_stroke(canvas, path, width, false); |
+ draw_stroke(canvas, path, width, 950, false); |
+ } |
+ |
+ if (fConicButton.fEnabled) { |
+ path.moveTo(fPts[4]); |
+ path.conicTo(fPts[5], fPts[6], fWeight); |
+ setForGeometry(); |
+ draw_stroke(canvas, path, width, 950, false); |
} |
if (fQuadButton.fEnabled) { |
path.reset(); |
- path.moveTo(fPts[4]); |
- path.quadTo(fPts[5], fPts[6]); |
+ path.moveTo(fPts[7]); |
+ path.quadTo(fPts[8], fPts[9]); |
setForGeometry(); |
- draw_stroke(canvas, path, width, false); |
+ draw_stroke(canvas, path, width, 950, false); |
} |
if (fRRectButton.fEnabled) { |
SkScalar rad = 32; |
SkRect r; |
- r.set(&fPts[7], 2); |
+ r.set(&fPts[10], 2); |
path.reset(); |
SkRRect rr; |
rr.setRectXY(r, rad, rad); |
path.addRRect(rr); |
setForGeometry(); |
- draw_stroke(canvas, path, width, false); |
+ draw_stroke(canvas, path, width, 950, false); |
path.reset(); |
SkRRect rr2; |
@@ -426,6 +494,19 @@ protected: |
canvas->drawPath(path, paint); |
} |
+ if (fCircleButton.fEnabled) { |
+ path.reset(); |
+ SkRect r; |
+ r.set(&fPts[12], 2); |
+ path.addOval(r); |
+ setForGeometry(); |
+ if (fCircleButton.fFill) { |
+ draw_fill(canvas, r, width); |
+ } else { |
+ draw_stroke(canvas, path, width, 950, false); |
+ } |
+ } |
+ |
if (fTextButton.fEnabled) { |
path.reset(); |
SkPaint paint; |
@@ -433,7 +514,7 @@ protected: |
paint.setTextSize(fTextSize); |
paint.getTextPath(fText.c_str(), fText.size(), 0, fTextSize, &path); |
setForText(); |
- draw_stroke(canvas, path, width * fWidthScale / fTextSize, true); |
+ draw_stroke(canvas, path, width * fWidthScale / fTextSize, fTextSize, true); |
} |
if (fAnimate) { |
@@ -445,6 +526,9 @@ protected: |
} |
} |
setAsNeeded(); |
+ if (fConicButton.fEnabled) { |
+ draw_control(canvas, fWeightControl, fWeight, 0, 5, "weight"); |
+ } |
#if QUAD_STROKE_APPROXIMATION && defined(SK_DEBUG) |
draw_control(canvas, fErrorControl, gDebugStrokerError, kStrokerErrorMin, kStrokerErrorMax, |
"error"); |
@@ -453,7 +537,9 @@ protected: |
kWidthMax * fWidthScale, "width"); |
draw_button(canvas, fQuadButton); |
draw_button(canvas, fCubicButton); |
+ draw_button(canvas, fConicButton); |
draw_button(canvas, fRRectButton); |
+ draw_button(canvas, fCircleButton); |
draw_button(canvas, fTextButton); |
this->inval(NULL); |
} |
@@ -472,9 +558,12 @@ protected: |
} |
} |
const SkRect& rectPt = SkRect::MakeXYWH(x, y, 1, 1); |
+ if (fWeightControl.contains(rectPt)) { |
+ return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 1); |
+ } |
#if QUAD_STROKE_APPROXIMATION && defined(SK_DEBUG) |
if (fErrorControl.contains(rectPt)) { |
- return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 1); |
+ return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 2); |
} |
#endif |
if (fWidthControl.contains(rectPt)) { |
@@ -484,17 +573,27 @@ protected: |
fCubicButton.fEnabled ^= true; |
return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 4); |
} |
+ if (fConicButton.fBounds.contains(rectPt)) { |
+ fConicButton.fEnabled ^= true; |
+ return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 5); |
+ } |
if (fQuadButton.fBounds.contains(rectPt)) { |
fQuadButton.fEnabled ^= true; |
- return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 5); |
+ return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 6); |
} |
if (fRRectButton.fBounds.contains(rectPt)) { |
fRRectButton.fEnabled ^= true; |
- return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 6); |
+ return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 7); |
+ } |
+ 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); |
} |
if (fTextButton.fBounds.contains(rectPt)) { |
fTextButton.fEnabled ^= true; |
- return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 7); |
+ return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 9); |
} |
return this->INHERITED::onFindClickHandler(x, y, modi); |
} |
@@ -510,9 +609,11 @@ protected: |
fPts[index].offset(SkIntToScalar(click->fICurr.fX - click->fIPrev.fX), |
SkIntToScalar(click->fICurr.fY - click->fIPrev.fY)); |
this->inval(NULL); |
+ } else if (index == (int) SK_ARRAY_COUNT(fPts) + 1) { |
+ fWeight = MapScreenYtoValue(click->fICurr.fY, fWeightControl, 0, 5); |
} |
#if QUAD_STROKE_APPROXIMATION && defined(SK_DEBUG) |
- else if (index == (int) SK_ARRAY_COUNT(fPts) + 1) { |
+ else if (index == (int) SK_ARRAY_COUNT(fPts) + 2) { |
gDebugStrokerError = SkTMax(FLT_EPSILON, MapScreenYtoValue(click->fICurr.fY, |
fErrorControl, kStrokerErrorMin, kStrokerErrorMax)); |
gDebugStrokerErrorSet = true; |