123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815 |
- /*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "include/core/SkBlendMode.h"
- #include "include/core/SkCanvas.h"
- #include "include/core/SkColor.h"
- #include "include/core/SkFont.h"
- #include "include/core/SkImageInfo.h"
- #include "include/core/SkMatrix.h"
- #include "include/core/SkPaint.h"
- #include "include/core/SkPath.h"
- #include "include/core/SkPathMeasure.h"
- #include "include/core/SkPoint.h"
- #include "include/core/SkRRect.h"
- #include "include/core/SkRect.h"
- #include "include/core/SkRefCnt.h"
- #include "include/core/SkScalar.h"
- #include "include/core/SkShader.h"
- #include "include/core/SkString.h"
- #include "include/core/SkSurface.h"
- #include "include/core/SkTypes.h"
- #include "include/private/SkTArray.h"
- #include "include/private/SkTemplates.h"
- #include "include/utils/SkTextUtils.h"
- #include "samplecode/Sample.h"
- #include "src/core/SkGeometry.h"
- #include "src/core/SkPointPriv.h"
- #include "src/core/SkStroke.h"
- #include "tools/ToolUtils.h"
- #include <cfloat>
- class SkEvent;
- static bool hittest(const SkPoint& target, SkScalar x, SkScalar y) {
- const SkScalar TOL = 7;
- return SkPoint::Distance(target, SkPoint::Make(x, y)) <= TOL;
- }
- static int getOnCurvePoints(const SkPath& path, SkPoint storage[]) {
- SkPath::RawIter iter(path);
- SkPoint pts[4];
- SkPath::Verb verb;
- int count = 0;
- while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
- switch (verb) {
- case SkPath::kMove_Verb:
- case SkPath::kLine_Verb:
- case SkPath::kQuad_Verb:
- case SkPath::kConic_Verb:
- case SkPath::kCubic_Verb:
- storage[count++] = pts[0];
- break;
- default:
- break;
- }
- }
- return count;
- }
- static void getContourCounts(const SkPath& path, SkTArray<int>* contourCounts) {
- SkPath::RawIter iter(path);
- SkPoint pts[4];
- SkPath::Verb verb;
- int count = 0;
- while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
- switch (verb) {
- case SkPath::kMove_Verb:
- case SkPath::kLine_Verb:
- count += 1;
- break;
- case SkPath::kQuad_Verb:
- case SkPath::kConic_Verb:
- count += 2;
- break;
- case SkPath::kCubic_Verb:
- count += 3;
- break;
- case SkPath::kClose_Verb:
- contourCounts->push_back(count);
- count = 0;
- break;
- default:
- break;
- }
- }
- if (count > 0) {
- contourCounts->push_back(count);
- }
- }
- static void erase(const sk_sp<SkSurface>& surface) {
- SkCanvas* canvas = surface->getCanvas();
- if (canvas) {
- canvas->clear(SK_ColorTRANSPARENT);
- }
- }
- struct StrokeTypeButton {
- SkRect fBounds;
- char fLabel;
- bool fEnabled;
- };
- struct CircleTypeButton : public StrokeTypeButton {
- bool fFill;
- };
- class QuadStrokerView : public Sample {
- enum {
- SKELETON_COLOR = 0xFF0000FF,
- WIREFRAME_COLOR = 0x80FF0000
- };
- enum {
- kCount = 18
- };
- SkPoint fPts[kCount];
- SkRect fWeightControl;
- SkRect fRadiusControl;
- SkRect fErrorControl;
- SkRect fWidthControl;
- SkRect fBounds;
- SkMatrix fMatrix, fInverse;
- sk_sp<SkShader> fShader;
- sk_sp<SkSurface> fMinSurface;
- sk_sp<SkSurface> fMaxSurface;
- 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;
- bool fAnimate;
- bool fDrawRibs;
- bool fDrawTangents;
- bool fDrawTDivs;
- #ifdef SK_DEBUG
- #define kStrokerErrorMin 0.001f
- #define kStrokerErrorMax 5
- #endif
- #define kWidthMin 1
- #define kWidthMax 100
- public:
- QuadStrokerView() {
- this->setBGColor(SK_ColorLTGRAY);
- 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); // conic
- fPts[5].set(350, 100);
- fPts[6].set(450, 50);
- fPts[7].set(150, 300); // quad
- fPts[8].set(150, 200);
- fPts[9].set(250, 150);
- 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[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 = false;
- fQuadButton.fLabel = 'Q';
- fQuadButton.fEnabled = false;
- fArcButton.fLabel = 'A';
- fArcButton.fEnabled = true;
- fRRectButton.fLabel = 'R';
- fRRectButton.fEnabled = false;
- fCircleButton.fLabel = 'O';
- fCircleButton.fEnabled = true;
- fCircleButton.fFill = true;
- fTextButton.fLabel = 'T';
- fTextButton.fEnabled = false;
- fAnimate = false;
- setAsNeeded();
- }
- protected:
- SkString name() override { return SkString("QuadStroker"); }
- bool onChar(SkUnichar uni) override {
- if (fTextButton.fEnabled) {
- switch (uni) {
- case ' ':
- fText = "";
- break;
- case '-':
- fTextSize = SkTMax(1.0f, fTextSize - 1);
- break;
- case '+':
- case '=':
- fTextSize += 1;
- break;
- default:
- fText.appendUnichar(uni);
- }
- return true;
- }
- return false;
- }
- 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);
- 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;
- 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);
- buttonOffset += 50;
- fTextButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30);
- this->INHERITED::onSizeChange();
- }
- void copyMinToMax() {
- erase(fMaxSurface);
- SkCanvas* canvas = fMaxSurface->getCanvas();
- canvas->save();
- canvas->concat(fMatrix);
- fMinSurface->draw(canvas, 0, 0, nullptr);
- canvas->restore();
- SkPaint paint;
- paint.setBlendMode(SkBlendMode::kClear);
- for (int iy = 1; iy < fH; ++iy) {
- SkScalar y = SkIntToScalar(iy * fZoom);
- canvas->drawLine(0, y - SK_ScalarHalf, 999, y - SK_ScalarHalf, paint);
- }
- for (int ix = 1; ix < fW; ++ix) {
- SkScalar x = SkIntToScalar(ix * fZoom);
- canvas->drawLine(x - SK_ScalarHalf, 0, x - SK_ScalarHalf, 999, paint);
- }
- }
- void setWHZ(int width, int height, int zoom) {
- fZoom = zoom;
- fBounds.set(0, 0, SkIntToScalar(width * zoom), SkIntToScalar(height * zoom));
- fMatrix.setScale(SkIntToScalar(zoom), SkIntToScalar(zoom));
- fInverse.setScale(SK_Scalar1 / zoom, SK_Scalar1 / zoom);
- fShader = ToolUtils::create_checkerboard_shader(0xFFCCCCCC, 0xFFFFFFFF, zoom);
- SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
- fMinSurface = SkSurface::MakeRaster(info);
- info = info.makeWH(width * zoom, height * zoom);
- fMaxSurface = SkSurface::MakeRaster(info);
- }
- void draw_points(SkCanvas* canvas, const SkPath& path, SkColor color,
- bool show_lines) {
- SkPaint paint;
- paint.setColor(color);
- paint.setAlpha(0x80);
- paint.setAntiAlias(true);
- int n = path.countPoints();
- SkAutoSTArray<32, SkPoint> pts(n);
- if (show_lines && fDrawTangents) {
- SkTArray<int> contourCounts;
- getContourCounts(path, &contourCounts);
- SkPoint* ptPtr = pts.get();
- for (int i = 0; i < contourCounts.count(); ++i) {
- int count = contourCounts[i];
- path.getPoints(ptPtr, count);
- canvas->drawPoints(SkCanvas::kPolygon_PointMode, count, ptPtr, paint);
- ptPtr += count;
- }
- } else {
- n = getOnCurvePoints(path, pts.get());
- }
- paint.setStrokeWidth(5);
- canvas->drawPoints(SkCanvas::kPoints_PointMode, n, pts.get(), paint);
- }
- void draw_ribs(SkCanvas* canvas, const SkPath& path, SkScalar width,
- SkColor color) {
- const SkScalar radius = width / 2;
- SkPathMeasure meas(path, false);
- SkScalar total = meas.getLength();
- SkScalar delta = 8;
- SkPaint paint, labelP;
- paint.setColor(color);
- labelP.setColor(color & 0xff5f9f5f);
- SkFont font;
- SkPoint pos, tan;
- int index = 0;
- for (SkScalar dist = 0; dist <= total; dist += delta) {
- if (meas.getPosTan(dist, &pos, &tan)) {
- tan.scale(radius);
- SkPointPriv::RotateCCW(&tan);
- canvas->drawLine(pos.x() + tan.x(), pos.y() + tan.y(),
- pos.x() - tan.x(), pos.y() - tan.y(), paint);
- if (0 == index % 10) {
- SkString label;
- label.appendS32(index);
- SkRect dot = SkRect::MakeXYWH(pos.x() - 2, pos.y() - 2, 4, 4);
- canvas->drawRect(dot, labelP);
- canvas->drawString(label,
- pos.x() - tan.x() * 1.25f, pos.y() - tan.y() * 1.25f, font, labelP);
- }
- }
- ++index;
- }
- }
- void draw_t_divs(SkCanvas* canvas, const SkPath& path, SkScalar width, SkColor color) {
- const SkScalar radius = width / 2;
- SkPaint paint;
- paint.setColor(color);
- SkPathMeasure meas(path, false);
- SkScalar total = meas.getLength();
- SkScalar delta = 8;
- int ribs = 0;
- for (SkScalar dist = 0; dist <= total; dist += delta) {
- ++ribs;
- }
- SkPath::RawIter iter(path);
- SkPoint pts[4];
- if (SkPath::kMove_Verb != iter.next(pts)) {
- SkASSERT(0);
- return;
- }
- SkPath::Verb verb = iter.next(pts);
- SkASSERT(SkPath::kLine_Verb <= verb && verb <= SkPath::kCubic_Verb);
- SkPoint pos, tan;
- for (int index = 0; index < ribs; ++index) {
- SkScalar t = (SkScalar) index / ribs;
- switch (verb) {
- case SkPath::kLine_Verb:
- tan = pts[1] - pts[0];
- pos = pts[0];
- pos.fX += tan.fX * t;
- pos.fY += tan.fY * t;
- break;
- case SkPath::kQuad_Verb:
- pos = SkEvalQuadAt(pts, t);
- tan = SkEvalQuadTangentAt(pts, t);
- break;
- case SkPath::kConic_Verb: {
- SkConic conic(pts, iter.conicWeight());
- pos = conic.evalAt(t);
- tan = conic.evalTangentAt(t);
- } break;
- case SkPath::kCubic_Verb:
- SkEvalCubicAt(pts, t, &pos, &tan, nullptr);
- break;
- default:
- SkASSERT(0);
- return;
- }
- tan.setLength(radius);
- SkPointPriv::RotateCCW(&tan);
- canvas->drawLine(pos.x() + tan.x(), pos.y() + tan.y(),
- pos.x() - tan.x(), pos.y() - tan.y(), paint);
- if (0 == index % 10) {
- SkString label;
- label.appendS32(index);
- canvas->drawString(label,
- pos.x() + tan.x() * 1.25f, pos.y() + tan.y() * 1.25f, SkFont(), paint);
- }
- }
- }
- void draw_stroke(SkCanvas* canvas, const SkPath& path, SkScalar width, SkScalar scale,
- bool drawText) {
- if (path.isEmpty()) {
- return;
- }
- SkRect bounds = path.getBounds();
- this->setWHZ(SkScalarCeilToInt(bounds.right()), drawText
- ? SkScalarRoundToInt(scale * 3 / 2) : SkScalarRoundToInt(scale),
- SkScalarRoundToInt(950.0f / scale));
- erase(fMinSurface);
- SkPaint paint;
- paint.setColor(0x1f1f0f0f);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setStrokeWidth(width * scale * scale);
- paint.setColor(0x3f0f1f3f);
- if (drawText) {
- fMinSurface->getCanvas()->drawPath(path, paint);
- this->copyMinToMax();
- fMaxSurface->draw(canvas, 0, 0, nullptr);
- }
- paint.setAntiAlias(true);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setStrokeWidth(1);
- paint.setColor(SKELETON_COLOR);
- SkPath scaled;
- SkMatrix matrix;
- matrix.reset();
- matrix.setScale(950 / scale, 950 / scale);
- if (drawText) {
- path.transform(matrix, &scaled);
- } else {
- scaled = path;
- }
- canvas->drawPath(scaled, paint);
- draw_points(canvas, scaled, SKELETON_COLOR, true);
- if (fDrawRibs) {
- draw_ribs(canvas, scaled, width, 0xFF00FF00);
- }
- if (fDrawTDivs) {
- draw_t_divs(canvas, scaled, width, 0xFF3F3F00);
- }
- SkPath fill;
- SkPaint p;
- p.setStyle(SkPaint::kStroke_Style);
- if (drawText) {
- p.setStrokeWidth(width * scale * scale);
- } else {
- p.setStrokeWidth(width);
- }
- p.getFillPath(path, &fill);
- SkPath scaledFill;
- if (drawText) {
- fill.transform(matrix, &scaledFill);
- } else {
- scaledFill = fill;
- }
- paint.setColor(WIREFRAME_COLOR);
- canvas->drawPath(scaledFill, paint);
- 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);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setColor(button.fEnabled ? 0xFF3F0000 : 0x6F3F0000);
- canvas->drawRect(button.fBounds, paint);
- paint.setColor(button.fEnabled ? 0xFF3F0000 : 0x6F3F0000);
- paint.setStyle(SkPaint::kFill_Style);
- SkFont font;
- font.setSize(25.0f);
- SkTextUtils::Draw(canvas, &button.fLabel, 1, SkTextEncoding::kUTF8,
- button.fBounds.centerX(), button.fBounds.fBottom - 5,
- font, paint, SkTextUtils::kCenter_Align);
- }
- void draw_control(SkCanvas* canvas, const SkRect& bounds, SkScalar value,
- SkScalar min, SkScalar max, const char* name) {
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setStyle(SkPaint::kStroke_Style);
- canvas->drawRect(bounds, paint);
- SkScalar scale = max - min;
- SkScalar yPos = bounds.fTop + (value - min) * bounds.height() / scale;
- paint.setColor(0xFFFF0000);
- canvas->drawLine(bounds.fLeft - 5, yPos, bounds.fRight + 5, yPos, paint);
- SkString label;
- label.printf("%0.3g", value);
- paint.setColor(0xFF000000);
- paint.setStyle(SkPaint::kFill_Style);
- SkFont font(nullptr, 11.0f);
- canvas->drawString(label, bounds.fLeft + 5, yPos - 5, font, paint);
- font.setSize(13.0f);
- canvas->drawString(name, bounds.fLeft, bounds.bottom() + 11, font, paint);
- }
- void setForGeometry() {
- fDrawRibs = true;
- fDrawTangents = true;
- fDrawTDivs = false;
- fWidthScale = 1;
- }
- void setForText() {
- fDrawRibs = fDrawTangents = fDrawTDivs = false;
- fWidthScale = 0.002f;
- }
- void setForSingles() {
- setForGeometry();
- fDrawTDivs = true;
- }
- void setAsNeeded() {
- if (fConicButton.fEnabled || fCubicButton.fEnabled || fQuadButton.fEnabled) {
- setForSingles();
- } 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;
- SkPointPriv::RotateCCW(before, &beforeCCW);
- SkPointPriv::RotateCCW(after, &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;
- SkPointPriv::RotateCW(before, &beforeCW);
- SkPointPriv::RotateCW(after, &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;
- if (fCubicButton.fEnabled) {
- path.moveTo(fPts[0]);
- path.cubicTo(fPts[1], fPts[2], fPts[3]);
- setForSingles();
- draw_stroke(canvas, path, width, 950, false);
- }
- if (fConicButton.fEnabled) {
- path.reset();
- path.moveTo(fPts[4]);
- path.conicTo(fPts[5], fPts[6], fWeight);
- setForSingles();
- draw_stroke(canvas, path, width, 950, false);
- }
- if (fQuadButton.fEnabled) {
- path.reset();
- path.moveTo(fPts[7]);
- path.quadTo(fPts[8], fPts[9]);
- setForSingles();
- 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[13], 2);
- path.reset();
- SkRRect rr;
- rr.setRectXY(r, rad, rad);
- path.addRRect(rr);
- setForGeometry();
- draw_stroke(canvas, path, width, 950, false);
- path.reset();
- SkRRect rr2;
- rr.inset(width/2, width/2, &rr2);
- path.addRRect(rr2, SkPath::kCCW_Direction);
- rr.inset(-width/2, -width/2, &rr2);
- path.addRRect(rr2, SkPath::kCW_Direction);
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setColor(0x40FF8844);
- canvas->drawPath(path, paint);
- }
- if (fCircleButton.fEnabled) {
- path.reset();
- SkRect r;
- 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);
- }
- }
- if (fTextButton.fEnabled) {
- path.reset();
- SkFont font;
- font.setSize(fTextSize);
- SkTextUtils::GetPath(fText.c_str(), fText.size(), SkTextEncoding::kUTF8,
- 0, fTextSize, font, &path);
- setForText();
- draw_stroke(canvas, path, width * fWidthScale / fTextSize, fTextSize, true);
- }
- if (fAnimate) {
- fWidth += fDWidth;
- if (fDWidth > 0 && fWidth > kWidthMax) {
- fDWidth = -fDWidth;
- } else if (fDWidth < 0 && fWidth < kWidthMin) {
- fDWidth = -fDWidth;
- }
- }
- setAsNeeded();
- 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");
- #endif
- draw_control(canvas, fWidthControl, fWidth * fWidthScale, kWidthMin * fWidthScale,
- kWidthMax * fWidthScale, "width");
- 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);
- }
- class MyClick : public Click {
- public:
- int fIndex;
- MyClick(int index) : fIndex(index) {}
- };
- virtual Sample::Click* onFindClickHandler(SkScalar x, SkScalar y,
- ModifierKey modi) override {
- for (size_t i = 0; i < SK_ARRAY_COUNT(fPts); ++i) {
- if (hittest(fPts[i], x, y)) {
- return new MyClick((int)i);
- }
- }
- const SkRect& rectPt = SkRect::MakeXYWH(x, y, 1, 1);
- if (fWeightControl.contains(rectPt)) {
- return new MyClick((int) SK_ARRAY_COUNT(fPts) + 1);
- }
- if (fRadiusControl.contains(rectPt)) {
- return new MyClick((int) SK_ARRAY_COUNT(fPts) + 2);
- }
- #ifdef SK_DEBUG
- if (fErrorControl.contains(rectPt)) {
- return new MyClick((int) SK_ARRAY_COUNT(fPts) + 3);
- }
- #endif
- if (fWidthControl.contains(rectPt)) {
- return new MyClick((int) SK_ARRAY_COUNT(fPts) + 4);
- }
- if (fCubicButton.fBounds.contains(rectPt)) {
- fCubicButton.fEnabled ^= true;
- return new MyClick((int) SK_ARRAY_COUNT(fPts) + 5);
- }
- if (fConicButton.fBounds.contains(rectPt)) {
- fConicButton.fEnabled ^= true;
- return new MyClick((int) SK_ARRAY_COUNT(fPts) + 6);
- }
- if (fQuadButton.fBounds.contains(rectPt)) {
- fQuadButton.fEnabled ^= true;
- return new MyClick((int) SK_ARRAY_COUNT(fPts) + 7);
- }
- if (fArcButton.fBounds.contains(rectPt)) {
- fArcButton.fEnabled ^= true;
- return new MyClick((int) SK_ARRAY_COUNT(fPts) + 8);
- }
- if (fRRectButton.fBounds.contains(rectPt)) {
- fRRectButton.fEnabled ^= true;
- return new MyClick((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((int) SK_ARRAY_COUNT(fPts) + 10);
- }
- if (fTextButton.fBounds.contains(rectPt)) {
- fTextButton.fEnabled ^= true;
- return new MyClick((int) SK_ARRAY_COUNT(fPts) + 11);
- }
- return nullptr;
- }
- static SkScalar MapScreenYtoValue(SkScalar y, const SkRect& control, SkScalar min,
- SkScalar max) {
- return (y - control.fTop) / control.height() * (max - min) + min;
- }
- bool onClick(Click* click) override {
- int index = ((MyClick*)click)->fIndex;
- if (index < (int) SK_ARRAY_COUNT(fPts)) {
- fPts[index].offset(click->fCurr.fX - click->fPrev.fX,
- click->fCurr.fY - click->fPrev.fY);
- } else if (index == (int) SK_ARRAY_COUNT(fPts) + 1) {
- fWeight = MapScreenYtoValue(click->fCurr.fY, fWeightControl, 0, 5);
- } else if (index == (int) SK_ARRAY_COUNT(fPts) + 2) {
- fRadius = MapScreenYtoValue(click->fCurr.fY, fRadiusControl, 0, 500);
- }
- #ifdef SK_DEBUG
- else if (index == (int) SK_ARRAY_COUNT(fPts) + 3) {
- gDebugStrokerError = SkTMax(FLT_EPSILON, MapScreenYtoValue(click->fCurr.fY,
- fErrorControl, kStrokerErrorMin, kStrokerErrorMax));
- gDebugStrokerErrorSet = true;
- }
- #endif
- else if (index == (int) SK_ARRAY_COUNT(fPts) + 4) {
- fWidth = SkTMax(FLT_EPSILON, MapScreenYtoValue(click->fCurr.fY, fWidthControl,
- kWidthMin, kWidthMax));
- fAnimate = fWidth <= kWidthMin;
- }
- return true;
- }
- private:
- typedef Sample INHERITED;
- };
- ///////////////////////////////////////////////////////////////////////////////
- DEF_SAMPLE( return new QuadStrokerView(); )
|