| /* | |
| * Copyright 2011 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "SampleCode.h" | |
| #include "SkAnimTimer.h" | |
| #include "SkView.h" | |
| #include "SkCanvas.h" | |
| #include "SkCornerPathEffect.h" | |
| #include "SkGradientShader.h" | |
| #include "SkGraphics.h" | |
| #include "SkImageDecoder.h" | |
| #include "SkPath.h" | |
| #include "SkRandom.h" | |
| #include "SkRegion.h" | |
| #include "SkShader.h" | |
| #include "SkUtils.h" | |
| #include "SkColorPriv.h" | |
| #include "SkColorFilter.h" | |
| #include "SkTime.h" | |
| #include "SkTypeface.h" | |
| #include "SkXfermode.h" | |
| #include "SkStream.h" | |
| #include "SkXMLParser.h" | |
| #include "SkColorPriv.h" | |
| #include "SkImageDecoder.h" | |
| static SkRandom gRand; | |
| static void generate_pts(SkPoint pts[], int count, int w, int h) { | |
| for (int i = 0; i < count; i++) { | |
| pts[i].set(gRand.nextUScalar1() * 3 * w - SkIntToScalar(w), | |
| gRand.nextUScalar1() * 3 * h - SkIntToScalar(h)); | |
| } | |
| } | |
| static bool check_zeros(const SkPMColor pixels[], int count, int skip) { | |
| for (int i = 0; i < count; i++) { | |
| if (*pixels) { | |
| return false; | |
| } | |
| pixels += skip; | |
| } | |
| return true; | |
| } | |
| static bool check_bitmap_margin(const SkBitmap& bm, int margin) { | |
| size_t rb = bm.rowBytes(); | |
| for (int i = 0; i < margin; i++) { | |
| if (!check_zeros(bm.getAddr32(0, i), bm.width(), 1)) { | |
| return false; | |
| } | |
| int bottom = bm.height() - i - 1; | |
| if (!check_zeros(bm.getAddr32(0, bottom), bm.width(), 1)) { | |
| return false; | |
| } | |
| // left column | |
| if (!check_zeros(bm.getAddr32(i, 0), bm.height(), SkToInt(rb >> 2))) { | |
| return false; | |
| } | |
| int right = bm.width() - margin + i; | |
| if (!check_zeros(bm.getAddr32(right, 0), bm.height(), | |
| SkToInt(rb >> 2))) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| #define WIDTH 620 | |
| #define HEIGHT 460 | |
| #define MARGIN 10 | |
| static void line_proc(SkCanvas* canvas, const SkPaint& paint, | |
| const SkBitmap& bm) { | |
| const int N = 2; | |
| SkPoint pts[N]; | |
| for (int i = 0; i < 400; i++) { | |
| generate_pts(pts, N, WIDTH, HEIGHT); | |
| canvas->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint); | |
| if (!check_bitmap_margin(bm, MARGIN)) { | |
| SkDebugf("---- hairline failure (%g %g) (%g %g)\n", | |
| pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY); | |
| break; | |
| } | |
| } | |
| } | |
| static void poly_proc(SkCanvas* canvas, const SkPaint& paint, | |
| const SkBitmap& bm) { | |
| const int N = 8; | |
| SkPoint pts[N]; | |
| for (int i = 0; i < 50; i++) { | |
| generate_pts(pts, N, WIDTH, HEIGHT); | |
| SkPath path; | |
| path.moveTo(pts[0]); | |
| for (int j = 1; j < N; j++) { | |
| path.lineTo(pts[j]); | |
| } | |
| canvas->drawPath(path, paint); | |
| } | |
| } | |
| static SkPoint ave(const SkPoint& a, const SkPoint& b) { | |
| SkPoint c = a + b; | |
| c.fX = SkScalarHalf(c.fX); | |
| c.fY = SkScalarHalf(c.fY); | |
| return c; | |
| } | |
| static void quad_proc(SkCanvas* canvas, const SkPaint& paint, | |
| const SkBitmap& bm) { | |
| const int N = 30; | |
| SkPoint pts[N]; | |
| for (int i = 0; i < 10; i++) { | |
| generate_pts(pts, N, WIDTH, HEIGHT); | |
| SkPath path; | |
| path.moveTo(pts[0]); | |
| for (int j = 1; j < N - 2; j++) { | |
| path.quadTo(pts[j], ave(pts[j], pts[j+1])); | |
| } | |
| path.quadTo(pts[N - 2], pts[N - 1]); | |
| canvas->drawPath(path, paint); | |
| } | |
| } | |
| static void add_cubic(SkPath* path, const SkPoint& mid, const SkPoint& end) { | |
| SkPoint start; | |
| path->getLastPt(&start); | |
| path->cubicTo(ave(start, mid), ave(mid, end), end); | |
| } | |
| static void cube_proc(SkCanvas* canvas, const SkPaint& paint, | |
| const SkBitmap& bm) { | |
| const int N = 30; | |
| SkPoint pts[N]; | |
| for (int i = 0; i < 10; i++) { | |
| generate_pts(pts, N, WIDTH, HEIGHT); | |
| SkPath path; | |
| path.moveTo(pts[0]); | |
| for (int j = 1; j < N - 2; j++) { | |
| add_cubic(&path, pts[j], ave(pts[j], pts[j+1])); | |
| } | |
| add_cubic(&path, pts[N - 2], pts[N - 1]); | |
| canvas->drawPath(path, paint); | |
| } | |
| } | |
| typedef void (*HairProc)(SkCanvas*, const SkPaint&, const SkBitmap&); | |
| static const struct { | |
| const char* fName; | |
| HairProc fProc; | |
| } gProcs[] = { | |
| { "line", line_proc }, | |
| { "poly", poly_proc }, | |
| { "quad", quad_proc }, | |
| { "cube", cube_proc }, | |
| }; | |
| static int cycle_hairproc_index(int index) { | |
| return (index + 1) % SK_ARRAY_COUNT(gProcs); | |
| } | |
| class HairlineView : public SampleView { | |
| SkMSec fNow; | |
| int fProcIndex; | |
| bool fDoAA; | |
| public: | |
| HairlineView() { | |
| fProcIndex = 0; | |
| fDoAA = true; | |
| fNow = 0; | |
| } | |
| protected: | |
| // overrides from SkEventSink | |
| bool onQuery(SkEvent* evt) override { | |
| if (SampleCode::TitleQ(*evt)) { | |
| SkString str; | |
| str.printf("Hair-%s", gProcs[fProcIndex].fName); | |
| SampleCode::TitleR(evt, str.c_str()); | |
| return true; | |
| } | |
| return this->INHERITED::onQuery(evt); | |
| } | |
| void show_bitmaps(SkCanvas* canvas, const SkBitmap& b0, const SkBitmap& b1, | |
| const SkIRect& inset) { | |
| canvas->drawBitmap(b0, 0, 0, NULL); | |
| canvas->drawBitmap(b1, SkIntToScalar(b0.width()), 0, NULL); | |
| } | |
| void onDrawContent(SkCanvas* canvas) override { | |
| gRand.setSeed(fNow); | |
| SkBitmap bm, bm2; | |
| bm.allocN32Pixels(WIDTH + MARGIN*2, HEIGHT + MARGIN*2); | |
| // this will erase our margin, which we want to always stay 0 | |
| bm.eraseColor(SK_ColorTRANSPARENT); | |
| bm2.installPixels(SkImageInfo::MakeN32Premul(WIDTH, HEIGHT), | |
| bm.getAddr32(MARGIN, MARGIN), bm.rowBytes()); | |
| SkCanvas c2(bm2); | |
| SkPaint paint; | |
| paint.setAntiAlias(fDoAA); | |
| paint.setStyle(SkPaint::kStroke_Style); | |
| bm2.eraseColor(SK_ColorTRANSPARENT); | |
| gProcs[fProcIndex].fProc(&c2, paint, bm); | |
| canvas->drawBitmap(bm2, SkIntToScalar(10), SkIntToScalar(10), NULL); | |
| } | |
| bool onAnimate(const SkAnimTimer&) override { | |
| if (fDoAA) { | |
| fProcIndex = cycle_hairproc_index(fProcIndex); | |
| // todo: signal that we want to rebuild our TITLE | |
| } | |
| fDoAA = !fDoAA; | |
| return true; | |
| } | |
| SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override { | |
| fDoAA = !fDoAA; | |
| this->inval(NULL); | |
| return this->INHERITED::onFindClickHandler(x, y, modi); | |
| } | |
| private: | |
| typedef SampleView INHERITED; | |
| }; | |
| ////////////////////////////////////////////////////////////////////////////// | |
| static SkView* MyFactory() { return new HairlineView; } | |
| static SkViewRegister reg(MyFactory); |