1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2012 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/core/SkBlendMode.h"
9cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h"
10cb93a386Sopenharmony_ci#include "include/core/SkColor.h"
11cb93a386Sopenharmony_ci#include "include/core/SkImageInfo.h"
12cb93a386Sopenharmony_ci#include "include/core/SkMatrix.h"
13cb93a386Sopenharmony_ci#include "include/core/SkPaint.h"
14cb93a386Sopenharmony_ci#include "include/core/SkPath.h"
15cb93a386Sopenharmony_ci#include "include/core/SkPoint.h"
16cb93a386Sopenharmony_ci#include "include/core/SkRect.h"
17cb93a386Sopenharmony_ci#include "include/core/SkRefCnt.h"
18cb93a386Sopenharmony_ci#include "include/core/SkScalar.h"
19cb93a386Sopenharmony_ci#include "include/core/SkShader.h"
20cb93a386Sopenharmony_ci#include "include/core/SkString.h"
21cb93a386Sopenharmony_ci#include "include/core/SkSurface.h"
22cb93a386Sopenharmony_ci#include "include/core/SkTypes.h"
23cb93a386Sopenharmony_ci#include "samplecode/Sample.h"
24cb93a386Sopenharmony_ci#include "src/core/SkPointPriv.h"
25cb93a386Sopenharmony_ci#include "tools/ToolUtils.h"
26cb93a386Sopenharmony_ci
27cb93a386Sopenharmony_ciclass SkEvent;
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_ci#define FAT_PIXEL_COLOR     SK_ColorBLACK
30cb93a386Sopenharmony_ci#define PIXEL_CENTER_SIZE   3
31cb93a386Sopenharmony_ci#define WIRE_FRAME_COLOR    0xFFFF0000  /*0xFF00FFFF*/
32cb93a386Sopenharmony_ci#define WIRE_FRAME_SIZE     1.5f
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_cistatic SkScalar apply_grid(SkScalar x) {
35cb93a386Sopenharmony_ci    const SkScalar grid = 2;
36cb93a386Sopenharmony_ci    return SkScalarRoundToScalar(x * grid) / grid;
37cb93a386Sopenharmony_ci}
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_cistatic void apply_grid(SkPoint pts[], int count) {
40cb93a386Sopenharmony_ci    for (int i = 0; i < count; ++i) {
41cb93a386Sopenharmony_ci        pts[i].set(apply_grid(pts[i].fX), apply_grid(pts[i].fY));
42cb93a386Sopenharmony_ci    }
43cb93a386Sopenharmony_ci}
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_cistatic void erase(SkSurface* surface) {
46cb93a386Sopenharmony_ci    surface->getCanvas()->clear(SK_ColorTRANSPARENT);
47cb93a386Sopenharmony_ci}
48cb93a386Sopenharmony_ci
49cb93a386Sopenharmony_ciclass FatBits {
50cb93a386Sopenharmony_cipublic:
51cb93a386Sopenharmony_ci    FatBits() {
52cb93a386Sopenharmony_ci        fAA = false;
53cb93a386Sopenharmony_ci        fStyle = kHair_Style;
54cb93a386Sopenharmony_ci        fGrid = false;
55cb93a386Sopenharmony_ci        fShowSkeleton = true;
56cb93a386Sopenharmony_ci        fUseClip = false;
57cb93a386Sopenharmony_ci        fRectAsOval = false;
58cb93a386Sopenharmony_ci        fUseTriangle = false;
59cb93a386Sopenharmony_ci        fStrokeCap = SkPaint::kButt_Cap;
60cb93a386Sopenharmony_ci
61cb93a386Sopenharmony_ci        fClipRect.setLTRB(2, 2, 11, 8 );
62cb93a386Sopenharmony_ci    }
63cb93a386Sopenharmony_ci
64cb93a386Sopenharmony_ci    int getZoom() const { return fZoom; }
65cb93a386Sopenharmony_ci
66cb93a386Sopenharmony_ci    bool getAA() const { return fAA; }
67cb93a386Sopenharmony_ci    void setAA(bool aa) { fAA = aa; }
68cb93a386Sopenharmony_ci
69cb93a386Sopenharmony_ci    bool getGrid() const { return fGrid; }
70cb93a386Sopenharmony_ci    void setGrid(bool g) { fGrid = g; }
71cb93a386Sopenharmony_ci
72cb93a386Sopenharmony_ci    bool getShowSkeleton() const { return fShowSkeleton; }
73cb93a386Sopenharmony_ci    void setShowSkeleton(bool ss) { fShowSkeleton = ss; }
74cb93a386Sopenharmony_ci
75cb93a386Sopenharmony_ci    bool getTriangle() const { return fUseTriangle; }
76cb93a386Sopenharmony_ci    void setTriangle(bool ut) { fUseTriangle = ut; }
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_ci    void toggleRectAsOval() { fRectAsOval = !fRectAsOval; }
79cb93a386Sopenharmony_ci
80cb93a386Sopenharmony_ci    void togglePixelColors() {
81cb93a386Sopenharmony_ci        if (fShader == fShader0) {
82cb93a386Sopenharmony_ci            fShader = fShader1;
83cb93a386Sopenharmony_ci        } else {
84cb93a386Sopenharmony_ci            fShader = fShader0;
85cb93a386Sopenharmony_ci        }
86cb93a386Sopenharmony_ci    }
87cb93a386Sopenharmony_ci
88cb93a386Sopenharmony_ci    float fStrokeWidth = 1;
89cb93a386Sopenharmony_ci
90cb93a386Sopenharmony_ci    bool getUseClip() const { return fUseClip; }
91cb93a386Sopenharmony_ci    void setUseClip(bool uc) { fUseClip = uc; }
92cb93a386Sopenharmony_ci
93cb93a386Sopenharmony_ci    enum Style {
94cb93a386Sopenharmony_ci        kHair_Style,
95cb93a386Sopenharmony_ci        kStroke_Style,
96cb93a386Sopenharmony_ci    };
97cb93a386Sopenharmony_ci    Style getStyle() const { return fStyle; }
98cb93a386Sopenharmony_ci    void setStyle(Style s) { fStyle = s; }
99cb93a386Sopenharmony_ci
100cb93a386Sopenharmony_ci    void setWHZ(int width, int height, int zoom) {
101cb93a386Sopenharmony_ci        fW = width;
102cb93a386Sopenharmony_ci        fH = height;
103cb93a386Sopenharmony_ci        fZoom = zoom;
104cb93a386Sopenharmony_ci        fBounds.setIWH(width * zoom, height * zoom);
105cb93a386Sopenharmony_ci        fMatrix.setScale(SkIntToScalar(zoom), SkIntToScalar(zoom));
106cb93a386Sopenharmony_ci        fInverse.setScale(SK_Scalar1 / zoom, SK_Scalar1 / zoom);
107cb93a386Sopenharmony_ci        fShader0 = ToolUtils::create_checkerboard_shader(0xFFDDDDDD, 0xFFFFFFFF, zoom);
108cb93a386Sopenharmony_ci        fShader1 = SkShaders::Color(SK_ColorWHITE);
109cb93a386Sopenharmony_ci        fShader = fShader0;
110cb93a386Sopenharmony_ci
111cb93a386Sopenharmony_ci        SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
112cb93a386Sopenharmony_ci        fMinSurface = SkSurface::MakeRaster(info);
113cb93a386Sopenharmony_ci        info = info.makeWH(width * zoom, height * zoom);
114cb93a386Sopenharmony_ci        fMaxSurface = SkSurface::MakeRaster(info);
115cb93a386Sopenharmony_ci    }
116cb93a386Sopenharmony_ci
117cb93a386Sopenharmony_ci    void drawBG(SkCanvas*);
118cb93a386Sopenharmony_ci    void drawFG(SkCanvas*);
119cb93a386Sopenharmony_ci    void drawLine(SkCanvas*, SkPoint pts[2]);
120cb93a386Sopenharmony_ci    void drawRect(SkCanvas* canvas, SkPoint pts[2]);
121cb93a386Sopenharmony_ci    void drawTriangle(SkCanvas* canvas, SkPoint pts[3]);
122cb93a386Sopenharmony_ci
123cb93a386Sopenharmony_ci    SkPaint::Cap fStrokeCap;
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_ciprivate:
126cb93a386Sopenharmony_ci    bool fAA, fGrid, fShowSkeleton, fUseClip, fRectAsOval, fUseTriangle;
127cb93a386Sopenharmony_ci    Style fStyle;
128cb93a386Sopenharmony_ci    int fW, fH, fZoom;
129cb93a386Sopenharmony_ci    SkMatrix            fMatrix, fInverse;
130cb93a386Sopenharmony_ci    SkRect              fBounds, fClipRect;
131cb93a386Sopenharmony_ci    sk_sp<SkShader>     fShader0;
132cb93a386Sopenharmony_ci    sk_sp<SkShader>     fShader1;
133cb93a386Sopenharmony_ci    sk_sp<SkShader>     fShader;
134cb93a386Sopenharmony_ci    sk_sp<SkSurface>    fMinSurface;
135cb93a386Sopenharmony_ci    sk_sp<SkSurface>    fMaxSurface;
136cb93a386Sopenharmony_ci
137cb93a386Sopenharmony_ci    void setupPaint(SkPaint* paint) {
138cb93a386Sopenharmony_ci        bool aa = this->getAA();
139cb93a386Sopenharmony_ci        paint->setStrokeCap(fStrokeCap);
140cb93a386Sopenharmony_ci        switch (fStyle) {
141cb93a386Sopenharmony_ci            case kHair_Style:
142cb93a386Sopenharmony_ci                paint->setStrokeWidth(0);
143cb93a386Sopenharmony_ci                break;
144cb93a386Sopenharmony_ci            case kStroke_Style:
145cb93a386Sopenharmony_ci                paint->setStrokeWidth(fStrokeWidth);
146cb93a386Sopenharmony_ci                break;
147cb93a386Sopenharmony_ci        }
148cb93a386Sopenharmony_ci        paint->setAntiAlias(aa);
149cb93a386Sopenharmony_ci    }
150cb93a386Sopenharmony_ci
151cb93a386Sopenharmony_ci    void setupSkeletonPaint(SkPaint* paint) {
152cb93a386Sopenharmony_ci        paint->setStyle(SkPaint::kStroke_Style);
153cb93a386Sopenharmony_ci        paint->setStrokeWidth(WIRE_FRAME_SIZE);
154cb93a386Sopenharmony_ci        paint->setColor(fShowSkeleton ? WIRE_FRAME_COLOR : 0);
155cb93a386Sopenharmony_ci        paint->setAntiAlias(true);
156cb93a386Sopenharmony_ci    }
157cb93a386Sopenharmony_ci
158cb93a386Sopenharmony_ci    void drawTriangleSkeleton(SkCanvas* max, const SkPoint pts[]);
159cb93a386Sopenharmony_ci    void drawLineSkeleton(SkCanvas* max, const SkPoint pts[]);
160cb93a386Sopenharmony_ci    void drawRectSkeleton(SkCanvas* max, const SkRect& r) {
161cb93a386Sopenharmony_ci        SkPaint paint;
162cb93a386Sopenharmony_ci        this->setupSkeletonPaint(&paint);
163cb93a386Sopenharmony_ci        SkPath path;
164cb93a386Sopenharmony_ci
165cb93a386Sopenharmony_ci        fRectAsOval ? path.addOval(r) : path.addRect(r);
166cb93a386Sopenharmony_ci        max->drawPath(path, paint);
167cb93a386Sopenharmony_ci    }
168cb93a386Sopenharmony_ci
169cb93a386Sopenharmony_ci    void copyMinToMax() {
170cb93a386Sopenharmony_ci        erase(fMaxSurface.get());
171cb93a386Sopenharmony_ci        SkCanvas* canvas = fMaxSurface->getCanvas();
172cb93a386Sopenharmony_ci        canvas->save();
173cb93a386Sopenharmony_ci        canvas->concat(fMatrix);
174cb93a386Sopenharmony_ci        fMinSurface->draw(canvas, 0, 0);
175cb93a386Sopenharmony_ci        canvas->restore();
176cb93a386Sopenharmony_ci
177cb93a386Sopenharmony_ci        SkPaint paint;
178cb93a386Sopenharmony_ci        paint.setBlendMode(SkBlendMode::kClear);
179cb93a386Sopenharmony_ci        for (int iy = 1; iy < fH; ++iy) {
180cb93a386Sopenharmony_ci            SkScalar y = SkIntToScalar(iy * fZoom);
181cb93a386Sopenharmony_ci            canvas->drawLine(0, y - SK_ScalarHalf, 999, y - SK_ScalarHalf, paint);
182cb93a386Sopenharmony_ci        }
183cb93a386Sopenharmony_ci        for (int ix = 1; ix < fW; ++ix) {
184cb93a386Sopenharmony_ci            SkScalar x = SkIntToScalar(ix * fZoom);
185cb93a386Sopenharmony_ci            canvas->drawLine(x - SK_ScalarHalf, 0, x - SK_ScalarHalf, 999, paint);
186cb93a386Sopenharmony_ci        }
187cb93a386Sopenharmony_ci    }
188cb93a386Sopenharmony_ci};
189cb93a386Sopenharmony_ci
190cb93a386Sopenharmony_civoid FatBits::drawBG(SkCanvas* canvas) {
191cb93a386Sopenharmony_ci    SkPaint paint;
192cb93a386Sopenharmony_ci
193cb93a386Sopenharmony_ci    paint.setShader(fShader);
194cb93a386Sopenharmony_ci    canvas->drawRect(fBounds, paint);
195cb93a386Sopenharmony_ci    paint.setShader(nullptr);
196cb93a386Sopenharmony_ci}
197cb93a386Sopenharmony_ci
198cb93a386Sopenharmony_civoid FatBits::drawFG(SkCanvas* canvas) {
199cb93a386Sopenharmony_ci    SkPaint inner, outer;
200cb93a386Sopenharmony_ci
201cb93a386Sopenharmony_ci    inner.setAntiAlias(true);
202cb93a386Sopenharmony_ci    inner.setColor(SK_ColorBLACK);
203cb93a386Sopenharmony_ci    inner.setStrokeWidth(PIXEL_CENTER_SIZE);
204cb93a386Sopenharmony_ci
205cb93a386Sopenharmony_ci    outer.setAntiAlias(true);
206cb93a386Sopenharmony_ci    outer.setColor(SK_ColorWHITE);
207cb93a386Sopenharmony_ci    outer.setStrokeWidth(PIXEL_CENTER_SIZE + 2);
208cb93a386Sopenharmony_ci
209cb93a386Sopenharmony_ci    SkScalar half = SkIntToScalar(fZoom) / 2;
210cb93a386Sopenharmony_ci    for (int iy = 0; iy < fH; ++iy) {
211cb93a386Sopenharmony_ci        SkScalar y = SkIntToScalar(iy * fZoom) + half;
212cb93a386Sopenharmony_ci        for (int ix = 0; ix < fW; ++ix) {
213cb93a386Sopenharmony_ci            SkScalar x = SkIntToScalar(ix * fZoom) + half;
214cb93a386Sopenharmony_ci
215cb93a386Sopenharmony_ci            canvas->drawPoint(x, y, outer);
216cb93a386Sopenharmony_ci            canvas->drawPoint(x, y, inner);
217cb93a386Sopenharmony_ci        }
218cb93a386Sopenharmony_ci    }
219cb93a386Sopenharmony_ci
220cb93a386Sopenharmony_ci    if (fUseClip) {
221cb93a386Sopenharmony_ci        SkPaint p;
222cb93a386Sopenharmony_ci        p.setStyle(SkPaint::kStroke_Style);
223cb93a386Sopenharmony_ci        p.setColor(SK_ColorLTGRAY);
224cb93a386Sopenharmony_ci        SkRect r = {
225cb93a386Sopenharmony_ci            fClipRect.fLeft * fZoom,
226cb93a386Sopenharmony_ci            fClipRect.fTop * fZoom,
227cb93a386Sopenharmony_ci            fClipRect.fRight * fZoom,
228cb93a386Sopenharmony_ci            fClipRect.fBottom * fZoom
229cb93a386Sopenharmony_ci        };
230cb93a386Sopenharmony_ci        canvas->drawRect(r, p);
231cb93a386Sopenharmony_ci    }
232cb93a386Sopenharmony_ci}
233cb93a386Sopenharmony_ci
234cb93a386Sopenharmony_civoid FatBits::drawLineSkeleton(SkCanvas* max, const SkPoint pts[]) {
235cb93a386Sopenharmony_ci    SkPaint paint;
236cb93a386Sopenharmony_ci    this->setupSkeletonPaint(&paint);
237cb93a386Sopenharmony_ci
238cb93a386Sopenharmony_ci    SkPath path;
239cb93a386Sopenharmony_ci    path.moveTo(pts[0]);
240cb93a386Sopenharmony_ci    path.lineTo(pts[1]);
241cb93a386Sopenharmony_ci
242cb93a386Sopenharmony_ci    if (fStyle == kStroke_Style) {
243cb93a386Sopenharmony_ci        SkPaint p;
244cb93a386Sopenharmony_ci        p.setStyle(SkPaint::kStroke_Style);
245cb93a386Sopenharmony_ci        p.setStrokeWidth(fStrokeWidth * fZoom);
246cb93a386Sopenharmony_ci        p.setStrokeCap(fStrokeCap);
247cb93a386Sopenharmony_ci        SkPath dst;
248cb93a386Sopenharmony_ci        p.getFillPath(path, &dst);
249cb93a386Sopenharmony_ci        path = dst;
250cb93a386Sopenharmony_ci
251cb93a386Sopenharmony_ci        path.moveTo(pts[0]);
252cb93a386Sopenharmony_ci        path.lineTo(pts[1]);
253cb93a386Sopenharmony_ci    }
254cb93a386Sopenharmony_ci    max->drawPath(path, paint);
255cb93a386Sopenharmony_ci}
256cb93a386Sopenharmony_ci
257cb93a386Sopenharmony_civoid FatBits::drawLine(SkCanvas* canvas, SkPoint pts[]) {
258cb93a386Sopenharmony_ci    SkPaint paint;
259cb93a386Sopenharmony_ci
260cb93a386Sopenharmony_ci    fInverse.mapPoints(pts, 2);
261cb93a386Sopenharmony_ci
262cb93a386Sopenharmony_ci    if (fGrid) {
263cb93a386Sopenharmony_ci        apply_grid(pts, 2);
264cb93a386Sopenharmony_ci    }
265cb93a386Sopenharmony_ci
266cb93a386Sopenharmony_ci    erase(fMinSurface.get());
267cb93a386Sopenharmony_ci    this->setupPaint(&paint);
268cb93a386Sopenharmony_ci    paint.setColor(FAT_PIXEL_COLOR);
269cb93a386Sopenharmony_ci    if (fUseClip) {
270cb93a386Sopenharmony_ci        fMinSurface->getCanvas()->save();
271cb93a386Sopenharmony_ci        SkRect r = fClipRect;
272cb93a386Sopenharmony_ci        r.inset(SK_Scalar1/3, SK_Scalar1/3);
273cb93a386Sopenharmony_ci        fMinSurface->getCanvas()->clipRect(r, SkClipOp::kIntersect, true);
274cb93a386Sopenharmony_ci    }
275cb93a386Sopenharmony_ci    fMinSurface->getCanvas()->drawLine(pts[0], pts[1], paint);
276cb93a386Sopenharmony_ci    if (fUseClip) {
277cb93a386Sopenharmony_ci        fMinSurface->getCanvas()->restore();
278cb93a386Sopenharmony_ci    }
279cb93a386Sopenharmony_ci    this->copyMinToMax();
280cb93a386Sopenharmony_ci
281cb93a386Sopenharmony_ci    SkCanvas* max = fMaxSurface->getCanvas();
282cb93a386Sopenharmony_ci
283cb93a386Sopenharmony_ci    fMatrix.mapPoints(pts, 2);
284cb93a386Sopenharmony_ci    this->drawLineSkeleton(max, pts);
285cb93a386Sopenharmony_ci
286cb93a386Sopenharmony_ci    fMaxSurface->draw(canvas, 0, 0);
287cb93a386Sopenharmony_ci}
288cb93a386Sopenharmony_ci
289cb93a386Sopenharmony_civoid FatBits::drawRect(SkCanvas* canvas, SkPoint pts[2]) {
290cb93a386Sopenharmony_ci    SkPaint paint;
291cb93a386Sopenharmony_ci
292cb93a386Sopenharmony_ci    fInverse.mapPoints(pts, 2);
293cb93a386Sopenharmony_ci
294cb93a386Sopenharmony_ci    if (fGrid) {
295cb93a386Sopenharmony_ci        apply_grid(pts, 2);
296cb93a386Sopenharmony_ci    }
297cb93a386Sopenharmony_ci
298cb93a386Sopenharmony_ci    SkRect r;
299cb93a386Sopenharmony_ci    r.setBounds(pts, 2);
300cb93a386Sopenharmony_ci
301cb93a386Sopenharmony_ci    erase(fMinSurface.get());
302cb93a386Sopenharmony_ci    this->setupPaint(&paint);
303cb93a386Sopenharmony_ci    paint.setColor(FAT_PIXEL_COLOR);
304cb93a386Sopenharmony_ci    {
305cb93a386Sopenharmony_ci        SkCanvas* c = fMinSurface->getCanvas();
306cb93a386Sopenharmony_ci        fRectAsOval ? c->drawOval(r, paint) : c->drawRect(r, paint);
307cb93a386Sopenharmony_ci    }
308cb93a386Sopenharmony_ci    this->copyMinToMax();
309cb93a386Sopenharmony_ci
310cb93a386Sopenharmony_ci    SkCanvas* max = fMaxSurface->getCanvas();
311cb93a386Sopenharmony_ci
312cb93a386Sopenharmony_ci    fMatrix.mapPoints(pts, 2);
313cb93a386Sopenharmony_ci    r.setBounds(pts, 2);
314cb93a386Sopenharmony_ci    this->drawRectSkeleton(max, r);
315cb93a386Sopenharmony_ci
316cb93a386Sopenharmony_ci    fMaxSurface->draw(canvas, 0, 0);
317cb93a386Sopenharmony_ci}
318cb93a386Sopenharmony_ci
319cb93a386Sopenharmony_civoid FatBits::drawTriangleSkeleton(SkCanvas* max, const SkPoint pts[]) {
320cb93a386Sopenharmony_ci    SkPaint paint;
321cb93a386Sopenharmony_ci    this->setupSkeletonPaint(&paint);
322cb93a386Sopenharmony_ci
323cb93a386Sopenharmony_ci    SkPath path;
324cb93a386Sopenharmony_ci    path.moveTo(pts[0]);
325cb93a386Sopenharmony_ci    path.lineTo(pts[1]);
326cb93a386Sopenharmony_ci    path.lineTo(pts[2]);
327cb93a386Sopenharmony_ci    path.close();
328cb93a386Sopenharmony_ci
329cb93a386Sopenharmony_ci    max->drawPath(path, paint);
330cb93a386Sopenharmony_ci}
331cb93a386Sopenharmony_ci
332cb93a386Sopenharmony_civoid FatBits::drawTriangle(SkCanvas* canvas, SkPoint pts[3]) {
333cb93a386Sopenharmony_ci    SkPaint paint;
334cb93a386Sopenharmony_ci
335cb93a386Sopenharmony_ci    fInverse.mapPoints(pts, 3);
336cb93a386Sopenharmony_ci
337cb93a386Sopenharmony_ci    if (fGrid) {
338cb93a386Sopenharmony_ci        apply_grid(pts, 3);
339cb93a386Sopenharmony_ci    }
340cb93a386Sopenharmony_ci
341cb93a386Sopenharmony_ci    SkPath path;
342cb93a386Sopenharmony_ci    path.moveTo(pts[0]);
343cb93a386Sopenharmony_ci    path.lineTo(pts[1]);
344cb93a386Sopenharmony_ci    path.lineTo(pts[2]);
345cb93a386Sopenharmony_ci    path.close();
346cb93a386Sopenharmony_ci
347cb93a386Sopenharmony_ci    erase(fMinSurface.get());
348cb93a386Sopenharmony_ci    this->setupPaint(&paint);
349cb93a386Sopenharmony_ci    paint.setColor(FAT_PIXEL_COLOR);
350cb93a386Sopenharmony_ci    fMinSurface->getCanvas()->drawPath(path, paint);
351cb93a386Sopenharmony_ci    this->copyMinToMax();
352cb93a386Sopenharmony_ci
353cb93a386Sopenharmony_ci    SkCanvas* max = fMaxSurface->getCanvas();
354cb93a386Sopenharmony_ci
355cb93a386Sopenharmony_ci    fMatrix.mapPoints(pts, 3);
356cb93a386Sopenharmony_ci    this->drawTriangleSkeleton(max, pts);
357cb93a386Sopenharmony_ci
358cb93a386Sopenharmony_ci    fMaxSurface->draw(canvas, 0, 0);
359cb93a386Sopenharmony_ci}
360cb93a386Sopenharmony_ci
361cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////////
362cb93a386Sopenharmony_ci
363cb93a386Sopenharmony_ciclass IndexClick : public Sample::Click {
364cb93a386Sopenharmony_ci    int fIndex;
365cb93a386Sopenharmony_cipublic:
366cb93a386Sopenharmony_ci    IndexClick(int index) : fIndex(index) {}
367cb93a386Sopenharmony_ci
368cb93a386Sopenharmony_ci    static int GetIndex(Sample::Click* click) {
369cb93a386Sopenharmony_ci        return ((IndexClick*)click)->fIndex;
370cb93a386Sopenharmony_ci    }
371cb93a386Sopenharmony_ci};
372cb93a386Sopenharmony_ci
373cb93a386Sopenharmony_ciclass DrawLineView : public Sample {
374cb93a386Sopenharmony_ci    FatBits fFB;
375cb93a386Sopenharmony_ci    SkPoint fPts[3];
376cb93a386Sopenharmony_ci    bool    fIsRect;
377cb93a386Sopenharmony_ci    int     fZoom = 64;
378cb93a386Sopenharmony_cipublic:
379cb93a386Sopenharmony_ci    DrawLineView() {
380cb93a386Sopenharmony_ci        fFB.setWHZ(24*2, 16*2, fZoom);
381cb93a386Sopenharmony_ci        fPts[0].set(1, 1);
382cb93a386Sopenharmony_ci        fPts[1].set(5, 4);
383cb93a386Sopenharmony_ci        fPts[2].set(2, 6);
384cb93a386Sopenharmony_ci        SkMatrix::Scale(fZoom, fZoom).mapPoints(fPts, 3);
385cb93a386Sopenharmony_ci        fIsRect = false;
386cb93a386Sopenharmony_ci    }
387cb93a386Sopenharmony_ci
388cb93a386Sopenharmony_ci    void setStyle(FatBits::Style s) {
389cb93a386Sopenharmony_ci        fFB.setStyle(s);
390cb93a386Sopenharmony_ci    }
391cb93a386Sopenharmony_ci
392cb93a386Sopenharmony_ciprotected:
393cb93a386Sopenharmony_ci    SkString name() override { return SkString("FatBits"); }
394cb93a386Sopenharmony_ci
395cb93a386Sopenharmony_ci    bool onChar(SkUnichar uni) override {
396cb93a386Sopenharmony_ci            switch (uni) {
397cb93a386Sopenharmony_ci                case 'c':
398cb93a386Sopenharmony_ci                    fFB.setUseClip(!fFB.getUseClip());
399cb93a386Sopenharmony_ci                    return true;
400cb93a386Sopenharmony_ci                case 'r':
401cb93a386Sopenharmony_ci                    fIsRect = !fIsRect;
402cb93a386Sopenharmony_ci                    return true;
403cb93a386Sopenharmony_ci                case 'o':
404cb93a386Sopenharmony_ci                    fFB.toggleRectAsOval();
405cb93a386Sopenharmony_ci                    return true;
406cb93a386Sopenharmony_ci                case 'x':
407cb93a386Sopenharmony_ci                    fFB.setGrid(!fFB.getGrid());
408cb93a386Sopenharmony_ci                    return true;
409cb93a386Sopenharmony_ci                case 's':
410cb93a386Sopenharmony_ci                    if (FatBits::kStroke_Style == fFB.getStyle()) {
411cb93a386Sopenharmony_ci                        this->setStyle(FatBits::kHair_Style);
412cb93a386Sopenharmony_ci                    } else {
413cb93a386Sopenharmony_ci                        this->setStyle(FatBits::kStroke_Style);
414cb93a386Sopenharmony_ci                    }
415cb93a386Sopenharmony_ci                    return true;
416cb93a386Sopenharmony_ci                case 'k': {
417cb93a386Sopenharmony_ci                    const SkPaint::Cap caps[] = {
418cb93a386Sopenharmony_ci                        SkPaint::kButt_Cap, SkPaint::kRound_Cap, SkPaint::kSquare_Cap,
419cb93a386Sopenharmony_ci                    };
420cb93a386Sopenharmony_ci                    fFB.fStrokeCap = caps[(fFB.fStrokeCap + 1) % 3];
421cb93a386Sopenharmony_ci                    return true;
422cb93a386Sopenharmony_ci                } break;
423cb93a386Sopenharmony_ci                case 'a':
424cb93a386Sopenharmony_ci                    fFB.setAA(!fFB.getAA());
425cb93a386Sopenharmony_ci                    return true;
426cb93a386Sopenharmony_ci                case 'w':
427cb93a386Sopenharmony_ci                    fFB.setShowSkeleton(!fFB.getShowSkeleton());
428cb93a386Sopenharmony_ci                    return true;
429cb93a386Sopenharmony_ci                case 'g':
430cb93a386Sopenharmony_ci                    fFB.togglePixelColors();
431cb93a386Sopenharmony_ci                    return true;
432cb93a386Sopenharmony_ci                case 't':
433cb93a386Sopenharmony_ci                    fFB.setTriangle(!fFB.getTriangle());
434cb93a386Sopenharmony_ci                    return true;
435cb93a386Sopenharmony_ci                case '-':
436cb93a386Sopenharmony_ci                    fFB.fStrokeWidth -= 0.125f;
437cb93a386Sopenharmony_ci                    return true;
438cb93a386Sopenharmony_ci                case '=':
439cb93a386Sopenharmony_ci                    fFB.fStrokeWidth += 0.125f;
440cb93a386Sopenharmony_ci                    return true;
441cb93a386Sopenharmony_ci            }
442cb93a386Sopenharmony_ci            return false;
443cb93a386Sopenharmony_ci    }
444cb93a386Sopenharmony_ci
445cb93a386Sopenharmony_ci    void onDrawContent(SkCanvas* canvas) override {
446cb93a386Sopenharmony_ci        fFB.drawBG(canvas);
447cb93a386Sopenharmony_ci        if (fFB.getTriangle()) {
448cb93a386Sopenharmony_ci            fFB.drawTriangle(canvas, fPts);
449cb93a386Sopenharmony_ci        }
450cb93a386Sopenharmony_ci        else if (fIsRect) {
451cb93a386Sopenharmony_ci            fFB.drawRect(canvas, fPts);
452cb93a386Sopenharmony_ci        } else {
453cb93a386Sopenharmony_ci            fFB.drawLine(canvas, fPts);
454cb93a386Sopenharmony_ci        }
455cb93a386Sopenharmony_ci        fFB.drawFG(canvas);
456cb93a386Sopenharmony_ci
457cb93a386Sopenharmony_ci        {
458cb93a386Sopenharmony_ci            SkString str;
459cb93a386Sopenharmony_ci            str.printf("%s %s %s",
460cb93a386Sopenharmony_ci                       fFB.getAA() ? "AA" : "BW",
461cb93a386Sopenharmony_ci                       FatBits::kHair_Style == fFB.getStyle() ? "Hair" : "Stroke",
462cb93a386Sopenharmony_ci                       fFB.getUseClip() ? "clip" : "noclip");
463cb93a386Sopenharmony_ci            SkPaint paint;
464cb93a386Sopenharmony_ci            paint.setColor(SK_ColorBLUE);
465cb93a386Sopenharmony_ci            SkFont font(nullptr, 16);
466cb93a386Sopenharmony_ci            canvas->drawString(str, 10, 16, font, paint);
467cb93a386Sopenharmony_ci        }
468cb93a386Sopenharmony_ci    }
469cb93a386Sopenharmony_ci
470cb93a386Sopenharmony_ci    Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
471cb93a386Sopenharmony_ci        SkPoint pt = { x, y };
472cb93a386Sopenharmony_ci        int index = -1;
473cb93a386Sopenharmony_ci        int count = fFB.getTriangle() ? 3 : 2;
474cb93a386Sopenharmony_ci        SkScalar tol = 12;
475cb93a386Sopenharmony_ci
476cb93a386Sopenharmony_ci        for (int i = 0; i < count; ++i) {
477cb93a386Sopenharmony_ci            if (SkPointPriv::EqualsWithinTolerance(fPts[i], pt, tol)) {
478cb93a386Sopenharmony_ci                index = i;
479cb93a386Sopenharmony_ci                break;
480cb93a386Sopenharmony_ci            }
481cb93a386Sopenharmony_ci        }
482cb93a386Sopenharmony_ci        return new IndexClick(index);
483cb93a386Sopenharmony_ci    }
484cb93a386Sopenharmony_ci
485cb93a386Sopenharmony_ci    bool onClick(Click* click) override {
486cb93a386Sopenharmony_ci        int index = IndexClick::GetIndex(click);
487cb93a386Sopenharmony_ci        if (index >= 0 && index <= 2) {
488cb93a386Sopenharmony_ci            fPts[index] = click->fCurr;
489cb93a386Sopenharmony_ci        } else {
490cb93a386Sopenharmony_ci            SkScalar dx = click->fCurr.fX - click->fPrev.fX;
491cb93a386Sopenharmony_ci            SkScalar dy = click->fCurr.fY - click->fPrev.fY;
492cb93a386Sopenharmony_ci            fPts[0].offset(dx, dy);
493cb93a386Sopenharmony_ci            fPts[1].offset(dx, dy);
494cb93a386Sopenharmony_ci            fPts[2].offset(dx, dy);
495cb93a386Sopenharmony_ci        }
496cb93a386Sopenharmony_ci        return true;
497cb93a386Sopenharmony_ci    }
498cb93a386Sopenharmony_ci
499cb93a386Sopenharmony_ciprivate:
500cb93a386Sopenharmony_ci
501cb93a386Sopenharmony_ci    using INHERITED = Sample;
502cb93a386Sopenharmony_ci};
503cb93a386Sopenharmony_ci
504cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
505cb93a386Sopenharmony_ci
506cb93a386Sopenharmony_ciDEF_SAMPLE( return new DrawLineView(); )
507