aboutsummaryrefslogtreecommitdiffstats
path: root/samplecode
diff options
context:
space:
mode:
authorDerek Sollenberger <djsollen@google.com>2011-06-06 17:02:24 -0400
committerDerek Sollenberger <djsollen@google.com>2011-06-07 14:00:04 -0400
commit0b15698a8c76bb8abc1b555c1d91892669b4118f (patch)
tree08732d5fbb7484ce7e10c65c96fb56294053073a /samplecode
parent9770b0f3d2b5d512daac50c2c9561d2c073cd8d2 (diff)
downloadexternal_skia-0b15698a8c76bb8abc1b555c1d91892669b4118f.zip
external_skia-0b15698a8c76bb8abc1b555c1d91892669b4118f.tar.gz
external_skia-0b15698a8c76bb8abc1b555c1d91892669b4118f.tar.bz2
Skia Merge (revision 1510)
This CL includes bug fixes and closely mirrors the version of Skia used in Chrome M13, which is likely to be our baseline for ICS. The CL also adds source files for the SampleApp which will allow us to execute basic skia tests. The SampleApp requires the utils/views directory in order to run. Finally, we have included the PDF backend for Skia in order to experiment with using it to generate PDF files for certain applications. Note: The SampleApp and PDF code are not built as part of libskia. Change-Id: I1895ccfbd8074e25f19148cc7bd1b4af571fb307
Diffstat (limited to 'samplecode')
-rw-r--r--samplecode/ClockFaceView.cpp255
-rw-r--r--samplecode/OverView.cpp94
-rw-r--r--samplecode/SampleAARects.cpp191
-rw-r--r--samplecode/SampleAll.cpp715
-rw-r--r--samplecode/SampleAnimatedGradient.cpp90
-rw-r--r--samplecode/SampleAnimator.cpp159
-rw-r--r--samplecode/SampleApp.cpp1647
-rw-r--r--samplecode/SampleArc.cpp184
-rw-r--r--samplecode/SampleAvoid.cpp99
-rw-r--r--samplecode/SampleBigGradient.cpp43
-rw-r--r--samplecode/SampleBitmapRect.cpp92
-rw-r--r--samplecode/SampleBlur.cpp131
-rw-r--r--samplecode/SampleBox.cpp48
-rw-r--r--samplecode/SampleCamera.cpp99
-rw-r--r--samplecode/SampleCircle.cpp126
-rw-r--r--samplecode/SampleClamp.cpp61
-rw-r--r--samplecode/SampleCode.h81
-rw-r--r--samplecode/SampleColorFilter.cpp210
-rw-r--r--samplecode/SampleComplexClip.cpp147
-rw-r--r--samplecode/SampleCull.cpp189
-rw-r--r--samplecode/SampleDash.cpp88
-rw-r--r--samplecode/SampleDecode.cpp69
-rw-r--r--samplecode/SampleDither.cpp178
-rw-r--r--samplecode/SampleDitherBitmap.cpp141
-rw-r--r--samplecode/SampleDraw.cpp373
-rw-r--r--samplecode/SampleDrawLooper.cpp92
-rw-r--r--samplecode/SampleEffects.cpp130
-rw-r--r--samplecode/SampleEmboss.cpp66
-rw-r--r--samplecode/SampleEncode.cpp224
-rw-r--r--samplecode/SampleExtractAlpha.cpp90
-rw-r--r--samplecode/SampleFillType.cpp90
-rw-r--r--samplecode/SampleFilter.cpp138
-rw-r--r--samplecode/SampleFilter2.cpp116
-rw-r--r--samplecode/SampleFontCache.cpp135
-rw-r--r--samplecode/SampleFontScalerTest.cpp117
-rw-r--r--samplecode/SampleFuzz.cpp363
-rw-r--r--samplecode/SampleGM.cpp114
-rw-r--r--samplecode/SampleGradients.cpp176
-rw-r--r--samplecode/SampleHairline.cpp272
-rw-r--r--samplecode/SampleImage.cpp156
-rw-r--r--samplecode/SampleImageDir.cpp310
-rw-r--r--samplecode/SampleLCD.cpp61
-rw-r--r--samplecode/SampleLayerMask.cpp68
-rw-r--r--samplecode/SampleLayers.cpp271
-rw-r--r--samplecode/SampleLineClipper.cpp255
-rw-r--r--samplecode/SampleLines.cpp109
-rw-r--r--samplecode/SampleMeasure.cpp115
-rw-r--r--samplecode/SampleMipMap.cpp143
-rw-r--r--samplecode/SampleMovie.cpp61
-rw-r--r--samplecode/SampleNinePatch.cpp114
-rw-r--r--samplecode/SampleOvalTest.cpp110
-rw-r--r--samplecode/SampleOverflow.cpp100
-rw-r--r--samplecode/SamplePageFlip.cpp167
-rw-r--r--samplecode/SamplePatch.cpp342
-rw-r--r--samplecode/SamplePath.cpp200
-rw-r--r--samplecode/SamplePathClip.cpp84
-rw-r--r--samplecode/SamplePathEffects.cpp184
-rw-r--r--samplecode/SamplePathFill.cpp140
-rw-r--r--samplecode/SamplePicture.cpp254
-rw-r--r--samplecode/SamplePoints.cpp78
-rw-r--r--samplecode/SamplePolyToPoly.cpp161
-rw-r--r--samplecode/SampleRegion.cpp273
-rw-r--r--samplecode/SampleRepeatTile.cpp86
-rw-r--r--samplecode/SampleShaderText.cpp195
-rw-r--r--samplecode/SampleShaders.cpp134
-rw-r--r--samplecode/SampleShapes.cpp160
-rw-r--r--samplecode/SampleSkLayer.cpp239
-rw-r--r--samplecode/SampleSlides.cpp804
-rw-r--r--samplecode/SampleSpiral.cpp56
-rw-r--r--samplecode/SampleStrokePath.cpp217
-rw-r--r--samplecode/SampleStrokeRect.cpp69
-rw-r--r--samplecode/SampleStrokeText.cpp140
-rw-r--r--samplecode/SampleTests.cpp111
-rw-r--r--samplecode/SampleText.cpp396
-rw-r--r--samplecode/SampleTextAlpha.cpp114
-rw-r--r--samplecode/SampleTextBox.cpp91
-rw-r--r--samplecode/SampleTextEffects.cpp397
-rw-r--r--samplecode/SampleTextOnPath.cpp284
-rwxr-xr-xsamplecode/SampleTextureDomain.cpp80
-rw-r--r--samplecode/SampleTiling.cpp162
-rw-r--r--samplecode/SampleTinyBitmap.cpp76
-rw-r--r--samplecode/SampleTriangles.cpp118
-rw-r--r--samplecode/SampleTypeface.cpp128
-rw-r--r--samplecode/SampleUnitMapper.cpp157
-rw-r--r--samplecode/SampleVertices.cpp230
-rw-r--r--samplecode/SampleWarp.cpp467
-rw-r--r--samplecode/SampleXfermodes.cpp250
-rw-r--r--samplecode/SampleXfermodesBlur.cpp182
-rw-r--r--samplecode/samplecode_files.mk69
-rw-r--r--samplecode/vertexdump.cpp88
90 files changed, 16889 insertions, 0 deletions
diff --git a/samplecode/ClockFaceView.cpp b/samplecode/ClockFaceView.cpp
new file mode 100644
index 0000000..c829b69
--- /dev/null
+++ b/samplecode/ClockFaceView.cpp
@@ -0,0 +1,255 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTypeface.h"
+#include "SkAvoidXfermode.h"
+
+static inline SkPMColor rgb2gray(SkPMColor c)
+{
+ unsigned r = SkGetPackedR32(c);
+ unsigned g = SkGetPackedG32(c);
+ unsigned b = SkGetPackedB32(c);
+
+ unsigned x = (r * 5 + g * 7 + b * 4) >> 4;
+
+ return SkPackARGB32(0, x, x, x) | (c & (SK_A32_MASK << SK_A32_SHIFT));
+}
+
+class SkGrayScaleColorFilter : public SkColorFilter {
+public:
+ virtual void filterSpan(const SkPMColor src[], int count, SkPMColor result[])
+ {
+ for (int i = 0; i < count; i++)
+ result[i] = rgb2gray(src[i]);
+ }
+};
+
+class SkChannelMaskColorFilter : public SkColorFilter {
+public:
+ SkChannelMaskColorFilter(U8CPU redMask, U8CPU greenMask, U8CPU blueMask)
+ {
+ fMask = SkPackARGB32(0xFF, redMask, greenMask, blueMask);
+ }
+
+ virtual void filterSpan(const SkPMColor src[], int count, SkPMColor result[])
+ {
+ SkPMColor mask = fMask;
+ for (int i = 0; i < count; i++)
+ result[i] = src[i] & mask;
+ }
+
+private:
+ SkPMColor fMask;
+};
+
+///////////////////////////////////////////////////////////
+
+#include "SkGradientShader.h"
+#include "SkLayerRasterizer.h"
+#include "SkBlurMaskFilter.h"
+
+#include "Sk2DPathEffect.h"
+
+class Dot2DPathEffect : public Sk2DPathEffect {
+public:
+ Dot2DPathEffect(SkScalar radius, const SkMatrix& matrix,
+ SkTDArray<SkPoint>* pts)
+ : Sk2DPathEffect(matrix), fRadius(radius), fPts(pts) {}
+
+ virtual void flatten(SkFlattenableWriteBuffer& buffer)
+ {
+ this->INHERITED::flatten(buffer);
+
+ buffer.writeScalar(fRadius);
+ }
+ virtual Factory getFactory() { return CreateProc; }
+
+protected:
+ virtual void begin(const SkIRect& uvBounds, SkPath* dst) {
+ if (fPts) {
+ fPts->reset();
+ }
+ this->INHERITED::begin(uvBounds, dst);
+ }
+// virtual void end(SkPath* dst) {}
+ virtual void next(const SkPoint& loc, int u, int v, SkPath* dst)
+ {
+ if (fPts) {
+ *fPts->append() = loc;
+ }
+ dst->addCircle(loc.fX, loc.fY, fRadius);
+ }
+
+ Dot2DPathEffect(SkFlattenableReadBuffer& buffer) : Sk2DPathEffect(buffer)
+ {
+ fRadius = buffer.readScalar();
+ fPts = NULL;
+ }
+private:
+ SkScalar fRadius;
+ SkTDArray<SkPoint>* fPts;
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer)
+ {
+ return new Dot2DPathEffect(buffer);
+ }
+
+ typedef Sk2DPathEffect INHERITED;
+};
+
+class InverseFillPE : public SkPathEffect {
+public:
+ InverseFillPE() {}
+ virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width) {
+ *dst = src;
+ dst->setFillType(SkPath::kInverseWinding_FillType);
+ return true;
+ }
+ virtual Factory getFactory() { return Factory; }
+protected:
+// InverseFillPE(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
+private:
+ static SkFlattenable* Factory(SkFlattenableReadBuffer& buffer) {
+ return new InverseFillPE;
+ }
+ typedef SkPathEffect INHERITED;
+};
+
+static SkPathEffect* makepe(float interp, SkTDArray<SkPoint>* pts) {
+ SkMatrix lattice;
+ SkScalar rad = 3 + SkIntToScalar(4) * (1 - interp);
+ lattice.setScale(rad*2, rad*2, 0, 0);
+ lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
+ return new Dot2DPathEffect(rad, lattice, pts);
+}
+
+static void r7(SkLayerRasterizer* rast, SkPaint& p, SkScalar interp) {
+ p.setPathEffect(makepe(interp, NULL))->unref();
+ rast->addLayer(p);
+#if 0
+ p.setPathEffect(new InverseFillPE())->unref();
+ p.setXfermodeMode(SkXfermode::kSrcIn_Mode);
+ p.setXfermodeMode(SkXfermode::kClear_Mode);
+ p.setAlpha((1 - interp) * 255);
+ rast->addLayer(p);
+#endif
+}
+
+typedef void (*raster_proc)(SkLayerRasterizer*, SkPaint&);
+
+#include "SkXfermode.h"
+
+static void apply_shader(SkPaint* paint, float scale)
+{
+ SkPaint p;
+ SkLayerRasterizer* rast = new SkLayerRasterizer;
+
+ p.setAntiAlias(true);
+ r7(rast, p, scale);
+ paint->setRasterizer(rast)->unref();
+
+ paint->setColor(SK_ColorBLUE);
+}
+
+class ClockFaceView : public SkView {
+ SkTypeface* fFace;
+ SkScalar fInterp;
+ SkScalar fDx;
+public:
+ ClockFaceView()
+ {
+ fFace = SkTypeface::CreateFromFile("/Users/reed/Downloads/p052024l.pfb");
+ fInterp = 0;
+ fDx = SK_Scalar1/64;
+ }
+
+ virtual ~ClockFaceView()
+ {
+ SkSafeUnref(fFace);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt)
+ {
+ if (SampleCode::TitleQ(*evt))
+ {
+ SampleCode::TitleR(evt, "Text Effects");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawBG(SkCanvas* canvas)
+ {
+// canvas->drawColor(0xFFDDDDDD);
+ canvas->drawColor(SK_ColorWHITE);
+ }
+
+ static void drawdots(SkCanvas* canvas, const SkPaint& orig) {
+ SkTDArray<SkPoint> pts;
+ SkPathEffect* pe = makepe(0, &pts);
+
+ SkScalar width = -1;
+ SkPath path, dstPath;
+ orig.getTextPath("9", 1, 0, 0, &path);
+ pe->filterPath(&dstPath, path, &width);
+
+ SkPaint p;
+ p.setAntiAlias(true);
+ p.setStrokeWidth(10);
+ p.setColor(SK_ColorRED);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, pts.count(), pts.begin(),
+ p);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ this->drawBG(canvas);
+
+ SkScalar x = SkIntToScalar(20);
+ SkScalar y = SkIntToScalar(300);
+ SkPaint paint;
+
+ paint.setAntiAlias(true);
+ paint.setTextSize(SkIntToScalar(240));
+ paint.setTypeface(SkTypeface::CreateFromName("sans-serif",
+ SkTypeface::kBold));
+
+ SkString str("9");
+
+ paint.setTypeface(fFace);
+
+ apply_shader(&paint, fInterp);
+ canvas->drawText(str.c_str(), str.size(), x, y, paint);
+
+ // drawdots(canvas, paint);
+
+ if (false) {
+ fInterp += fDx;
+ if (fInterp > 1) {
+ fInterp = 1;
+ fDx = -fDx;
+ } else if (fInterp < 0) {
+ fInterp = 0;
+ fDx = -fDx;
+ }
+ this->inval(NULL);
+ }
+ }
+
+private:
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new ClockFaceView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/OverView.cpp b/samplecode/OverView.cpp
new file mode 100644
index 0000000..2ae2119
--- /dev/null
+++ b/samplecode/OverView.cpp
@@ -0,0 +1,94 @@
+#include "SampleCode.h"
+#include "SkCanvas.h"
+#include "SkView.h"
+
+static const int N = 8;
+const SkScalar W = SkIntToScalar(640);
+const SkScalar H = SkIntToScalar(480);
+
+class OverView : public SkView {
+public:
+ OverView(int count, const SkViewFactory factories[]);
+ virtual ~OverView();
+
+protected:
+ virtual bool onEvent(const SkEvent&);
+ virtual void onSizeChange();
+
+ virtual void onDraw(SkCanvas* canvas) {
+ canvas->drawColor(SK_ColorLTGRAY);
+ }
+
+ virtual SkCanvas* beforeChildren(SkCanvas*);
+
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Overview");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual bool onSendClickToChildren(SkScalar x, SkScalar y) {
+ return false;
+ }
+
+ virtual Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ int ix = (int)(SkScalarDiv(x * N, W));
+ int iy = (int)(SkScalarDiv(y * N, H));
+ if (ix >= 0 && iy >= 0) {
+ SkEvent evt("set-curr-index");
+ evt.setFast32(iy * N + ix);
+ this->sendEventToParents(evt);
+ }
+ return NULL;
+ }
+
+private:
+ int fCount;
+ const SkViewFactory* fFactories;
+
+ typedef SkView INHERITED;
+};
+
+SkView* create_overview(int count, const SkViewFactory factories[]);
+SkView* create_overview(int count, const SkViewFactory factories[]) {
+ return SkNEW_ARGS(OverView, (count, factories));
+};
+
+OverView::OverView(int count, const SkViewFactory factories[]) {
+ fCount = count;
+ fFactories = factories;
+}
+
+OverView::~OverView() {
+}
+
+bool OverView::onEvent(const SkEvent& evt) {
+ return this->INHERITED::onEvent(evt);
+}
+
+void OverView::onSizeChange() {
+ this->detachAllChildren();
+
+ SkScalar locX = 0;
+ SkScalar locY = 0;
+ for (int i = 0; i < fCount; i++) {
+ SkView* view = fFactories[i]();
+ view->setVisibleP(true);
+ this->attachChildToBack(view)->unref();
+ view->setLoc(locX, locY);
+ view->setSize(W, H);
+ locX += W;
+ if ((i % N) == N - 1) {
+ locY += H;
+ locX = 0;
+ }
+ }
+}
+
+SkCanvas* OverView::beforeChildren(SkCanvas* canvas) {
+ canvas->scale(SK_Scalar1 / N, SK_Scalar1 / N);
+ return canvas;
+}
+
diff --git a/samplecode/SampleAARects.cpp b/samplecode/SampleAARects.cpp
new file mode 100644
index 0000000..34a33b0
--- /dev/null
+++ b/samplecode/SampleAARects.cpp
@@ -0,0 +1,191 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkPaint.h"
+#include "SkShader.h"
+
+static SkBitmap createBitmap(int n) {
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, n, n);
+ bitmap.allocPixels();
+ bitmap.eraseColor(SK_ColorGREEN);
+
+ SkCanvas canvas(bitmap);
+ SkRect r;
+ r.set(0, 0, SkIntToScalar(n), SkIntToScalar(n));
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ paint.setColor(SK_ColorRED);
+ canvas.drawOval(r, paint);
+ paint.setColor(SK_ColorBLUE);
+ paint.setStrokeWidth(SkIntToScalar(n)/15);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas.drawLine(0, 0, r.fRight, r.fBottom, paint);
+ canvas.drawLine(0, r.fBottom, r.fRight, 0, paint);
+
+ return bitmap;
+}
+
+class AARectView : public SampleView {
+ SkBitmap fBitmap;
+ enum {
+ N = 64
+ };
+public:
+ AARectView() {
+ fBitmap = createBitmap(N);
+
+ fWidth = N;
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "AA Rects");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
+
+ SkPaint bluePaint;
+ bluePaint.setARGB(0xff, 0x0, 0x0, 0xff);
+ SkPaint bmpPaint;
+ SkShader* bmpShader = SkShader::CreateBitmapShader(fBitmap, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
+ bmpPaint.setShader(bmpShader);
+ bmpShader->unref();
+
+ bluePaint.setStrokeWidth(3);
+ bmpPaint.setStrokeWidth(3);
+
+ SkPaint paints[] = { bluePaint, bmpPaint };
+
+ SkRect rect;
+
+ SkScalar dx = SkIntToScalar(80);
+ SkScalar dy = SkIntToScalar(100);
+ SkMatrix matrix;
+ for (size_t p = 0; p < SK_ARRAY_COUNT(paints); ++p) {
+ for (int stroke = 0; stroke < 2; ++stroke) {
+ paints[p].setStyle(stroke ? SkPaint::kStroke_Style : SkPaint::kFill_Style);
+ for (int a = 0; a < 3; ++ a) {
+ paints[p].setAntiAlias(a > 0);
+ paints[p].setAlpha(a > 1 ? 0x80 : 0xff);
+
+ canvas->save();
+ rect = SkRect::MakeLTRB(SkFloatToScalar(0.f),
+ SkFloatToScalar(0.f),
+ SkFloatToScalar(40.f),
+ SkFloatToScalar(40.f));
+ canvas->drawRect(rect, paints[p]);
+ canvas->translate(dx, 0);
+
+ rect = SkRect::MakeLTRB(SkFloatToScalar(0.5f),
+ SkFloatToScalar(0.5f),
+ SkFloatToScalar(40.5f),
+ SkFloatToScalar(40.5f));
+ canvas->drawRect(rect, paints[p]);
+ canvas->translate(dx, 0);
+
+ rect = SkRect::MakeLTRB(SkFloatToScalar(0.5f),
+ SkFloatToScalar(0.5f),
+ SkFloatToScalar(40.f),
+ SkFloatToScalar(40.f));
+ canvas->drawRect(rect, paints[p]);
+ canvas->translate(dx, 0);
+
+ rect = SkRect::MakeLTRB(SkFloatToScalar(0.75f),
+ SkFloatToScalar(0.75f),
+ SkFloatToScalar(40.75f),
+ SkFloatToScalar(40.75f));
+ canvas->drawRect(rect, paints[p]);
+ canvas->translate(dx, 0);
+
+ canvas->save();
+ canvas->translate(SkFloatToScalar(.33f), SkFloatToScalar(.67f));
+ rect = SkRect::MakeLTRB(SkFloatToScalar(0.0f),
+ SkFloatToScalar(0.0f),
+ SkFloatToScalar(40.0f),
+ SkFloatToScalar(40.0f));
+ canvas->drawRect(rect, paints[p]);
+ canvas->restore();
+ canvas->translate(dx, 0);
+
+ canvas->save();
+ matrix.setRotate(SkFloatToScalar(45.f));
+ canvas->concat(matrix);
+ canvas->translate(SkFloatToScalar(20.0f / sqrtf(2.f)),
+ SkFloatToScalar(20.0f / sqrtf(2.f)));
+ rect = SkRect::MakeLTRB(SkFloatToScalar(-20.0f),
+ SkFloatToScalar(-20.0f),
+ SkFloatToScalar(20.0f),
+ SkFloatToScalar(20.0f));
+ canvas->drawRect(rect, paints[p]);
+ canvas->restore();
+ canvas->translate(dx, 0);
+
+ canvas->save();
+ canvas->rotate(SkFloatToScalar(90.f));
+ rect = SkRect::MakeLTRB(SkFloatToScalar(0.0f),
+ SkFloatToScalar(0.0f),
+ SkFloatToScalar(40.0f),
+ SkFloatToScalar(-40.0f));
+ canvas->drawRect(rect, paints[p]);
+ canvas->restore();
+ canvas->translate(dx, 0);
+
+ canvas->save();
+ canvas->rotate(SkFloatToScalar(90.f));
+ rect = SkRect::MakeLTRB(SkFloatToScalar(0.5f),
+ SkFloatToScalar(0.5f),
+ SkFloatToScalar(40.5f),
+ SkFloatToScalar(-40.5f));
+ canvas->drawRect(rect, paints[p]);
+ canvas->restore();
+ canvas->translate(dx, 0);
+
+ canvas->save();
+ matrix.setScale(SkFloatToScalar(-1.f), SkFloatToScalar(-1.f));
+ canvas->concat(matrix);
+ rect = SkRect::MakeLTRB(SkFloatToScalar(0.5f),
+ SkFloatToScalar(0.5f),
+ SkFloatToScalar(-40.5f),
+ SkFloatToScalar(-40.5f));
+ canvas->drawRect(rect, paints[p]);
+ canvas->restore();
+ canvas->translate(dx, 0);
+
+ canvas->save();
+ matrix.setScale(SkFloatToScalar(2.1f), SkFloatToScalar(4.1f));
+ canvas->concat(matrix);
+ rect = SkRect::MakeLTRB(SkFloatToScalar(0.1f),
+ SkFloatToScalar(0.1f),
+ SkFloatToScalar(19.1f),
+ SkFloatToScalar(9.1f));
+ canvas->drawRect(rect, paints[p]);
+ canvas->restore();
+ canvas->translate(dx, 0);
+
+ canvas->restore();
+ canvas->translate(0, dy);
+ }
+ }
+ }
+ }
+
+private:
+ int fWidth;
+
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new AARectView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleAll.cpp b/samplecode/SampleAll.cpp
new file mode 100644
index 0000000..abbf8f9
--- /dev/null
+++ b/samplecode/SampleAll.cpp
@@ -0,0 +1,715 @@
+#include "SampleCode.h"
+#include "SkCanvas.h"
+#include "SkView.h"
+#include "Sk1DPathEffect.h"
+#include "Sk2DPathEffect.h"
+#include "SkAvoidXfermode.h"
+#include "SkBlurMaskFilter.h"
+#include "SkColorFilter.h"
+#include "SkColorPriv.h"
+#include "SkCornerPathEffect.h"
+#include "SkDashPathEffect.h"
+#include "SkDiscretePathEffect.h"
+#include "SkEmbossMaskFilter.h"
+#include "SkGradientShader.h"
+#include "SkImageDecoder.h"
+#include "SkLayerRasterizer.h"
+#include "SkMath.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkComposeShader.h"
+#include "SkCornerPathEffect.h"
+#include "SkPathMeasure.h"
+#include "SkPicture.h"
+#include "SkRandom.h"
+#include "SkTransparentShader.h"
+#include "SkTypeface.h"
+#include "SkUnitMappers.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+
+#include <math.h>
+
+static inline SkPMColor rgb2gray(SkPMColor c) {
+ unsigned r = SkGetPackedR32(c);
+ unsigned g = SkGetPackedG32(c);
+ unsigned b = SkGetPackedB32(c);
+
+ unsigned x = (r * 5 + g * 7 + b * 4) >> 4;
+
+ return SkPackARGB32(0, x, x, x) | (c & (SK_A32_MASK << SK_A32_SHIFT));
+}
+
+class SkGrayScaleColorFilter : public SkColorFilter {
+public:
+ virtual void filterSpan(const SkPMColor src[], int count, SkPMColor result[]) {
+ for (int i = 0; i < count; i++)
+ result[i] = rgb2gray(src[i]);
+ }
+};
+
+class SkChannelMaskColorFilter : public SkColorFilter {
+public:
+ SkChannelMaskColorFilter(U8CPU redMask, U8CPU greenMask, U8CPU blueMask) {
+ fMask = SkPackARGB32(0xFF, redMask, greenMask, blueMask);
+ }
+
+ virtual void filterSpan(const SkPMColor src[], int count, SkPMColor result[]) {
+ SkPMColor mask = fMask;
+ for (int i = 0; i < count; i++) {
+ result[i] = src[i] & mask;
+ }
+ }
+
+private:
+ SkPMColor fMask;
+};
+
+///////////////////////////////////////////////////////////
+
+static void r0(SkLayerRasterizer* rast, SkPaint& p) {
+ p.setMaskFilter(SkBlurMaskFilter::Create(SkIntToScalar(3),
+ SkBlurMaskFilter::kNormal_BlurStyle))->unref();
+ rast->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
+
+ p.setMaskFilter(NULL);
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(SK_Scalar1);
+ rast->addLayer(p);
+
+ p.setAlpha(0x11);
+ p.setStyle(SkPaint::kFill_Style);
+ p.setXfermodeMode(SkXfermode::kSrc_Mode);
+ rast->addLayer(p);
+}
+
+static void r1(SkLayerRasterizer* rast, SkPaint& p) {
+ rast->addLayer(p);
+
+ p.setAlpha(0x40);
+ p.setXfermodeMode(SkXfermode::kSrc_Mode);
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(SK_Scalar1*2);
+ rast->addLayer(p);
+}
+
+static void r2(SkLayerRasterizer* rast, SkPaint& p) {
+ p.setStyle(SkPaint::kStrokeAndFill_Style);
+ p.setStrokeWidth(SK_Scalar1*4);
+ rast->addLayer(p);
+
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(SK_Scalar1*3/2);
+ p.setXfermodeMode(SkXfermode::kClear_Mode);
+ rast->addLayer(p);
+}
+
+static void r3(SkLayerRasterizer* rast, SkPaint& p) {
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(SK_Scalar1*3);
+ rast->addLayer(p);
+
+ p.setAlpha(0x20);
+ p.setStyle(SkPaint::kFill_Style);
+ p.setXfermodeMode(SkXfermode::kSrc_Mode);
+ rast->addLayer(p);
+}
+
+static void r4(SkLayerRasterizer* rast, SkPaint& p) {
+ p.setAlpha(0x60);
+ rast->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
+
+ p.setAlpha(0xFF);
+ p.setXfermodeMode(SkXfermode::kClear_Mode);
+ rast->addLayer(p, SK_Scalar1*3/2, SK_Scalar1*3/2);
+
+ p.setXfermode(NULL);
+ rast->addLayer(p);
+}
+
+static void r5(SkLayerRasterizer* rast, SkPaint& p) {
+ rast->addLayer(p);
+
+ p.setPathEffect(new SkDiscretePathEffect(SK_Scalar1*4, SK_Scalar1*3))->unref();
+ p.setXfermodeMode(SkXfermode::kSrcOut_Mode);
+ rast->addLayer(p);
+}
+
+static void r6(SkLayerRasterizer* rast, SkPaint& p) {
+ rast->addLayer(p);
+
+ p.setAntiAlias(false);
+ SkLayerRasterizer* rast2 = new SkLayerRasterizer;
+ r5(rast2, p);
+ p.setRasterizer(rast2)->unref();
+ p.setXfermodeMode(SkXfermode::kClear_Mode);
+ rast->addLayer(p);
+}
+
+class Dot2DPathEffect : public Sk2DPathEffect {
+public:
+ Dot2DPathEffect(SkScalar radius, const SkMatrix& matrix)
+ : Sk2DPathEffect(matrix), fRadius(radius) {}
+
+ virtual void flatten(SkFlattenableWriteBuffer& buffer) {
+ this->INHERITED::flatten(buffer);
+
+ buffer.writeScalar(fRadius);
+ }
+ virtual Factory getFactory() { return CreateProc; }
+
+protected:
+ virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) {
+ dst->addCircle(loc.fX, loc.fY, fRadius);
+ }
+
+ Dot2DPathEffect(SkFlattenableReadBuffer& buffer) : Sk2DPathEffect(buffer) {
+ fRadius = buffer.readScalar();
+ }
+private:
+ SkScalar fRadius;
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return new Dot2DPathEffect(buffer);
+ }
+
+ typedef Sk2DPathEffect INHERITED;
+};
+
+static void r7(SkLayerRasterizer* rast, SkPaint& p) {
+ SkMatrix lattice;
+ lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
+ lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
+ p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*4, lattice))->unref();
+ rast->addLayer(p);
+}
+
+static void r8(SkLayerRasterizer* rast, SkPaint& p) {
+ rast->addLayer(p);
+
+ SkMatrix lattice;
+ lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
+ lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
+ p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*2, lattice))->unref();
+ p.setXfermodeMode(SkXfermode::kClear_Mode);
+ rast->addLayer(p);
+
+ p.setPathEffect(NULL);
+ p.setXfermode(NULL);
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(SK_Scalar1);
+ rast->addLayer(p);
+}
+
+class Line2DPathEffect : public Sk2DPathEffect {
+public:
+ Line2DPathEffect(SkScalar width, const SkMatrix& matrix)
+ : Sk2DPathEffect(matrix), fWidth(width) {}
+
+ virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width) {
+ if (this->INHERITED::filterPath(dst, src, width)) {
+ *width = fWidth;
+ return true;
+ }
+ return false;
+ }
+
+ virtual Factory getFactory() { return CreateProc; }
+ virtual void flatten(SkFlattenableWriteBuffer& buffer) {
+ this->INHERITED::flatten(buffer);
+ buffer.writeScalar(fWidth);
+ }
+protected:
+ virtual void nextSpan(int u, int v, int ucount, SkPath* dst) {
+ if (ucount > 1) {
+ SkPoint src[2], dstP[2];
+
+ src[0].set(SkIntToScalar(u) + SK_ScalarHalf,
+ SkIntToScalar(v) + SK_ScalarHalf);
+ src[1].set(SkIntToScalar(u+ucount) + SK_ScalarHalf,
+ SkIntToScalar(v) + SK_ScalarHalf);
+ this->getMatrix().mapPoints(dstP, src, 2);
+
+ dst->moveTo(dstP[0]);
+ dst->lineTo(dstP[1]);
+ }
+ }
+
+ Line2DPathEffect(SkFlattenableReadBuffer& buffer) : Sk2DPathEffect(buffer) {
+ fWidth = buffer.readScalar();
+ }
+
+private:
+ SkScalar fWidth;
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { return new Line2DPathEffect(buffer); }
+
+ typedef Sk2DPathEffect INHERITED;
+};
+
+static void r9(SkLayerRasterizer* rast, SkPaint& p) {
+ rast->addLayer(p);
+
+ SkMatrix lattice;
+ lattice.setScale(SK_Scalar1, SK_Scalar1*6, 0, 0);
+ lattice.postRotate(SkIntToScalar(30), 0, 0);
+ p.setPathEffect(new Line2DPathEffect(SK_Scalar1*2, lattice))->unref();
+ p.setXfermodeMode(SkXfermode::kClear_Mode);
+ rast->addLayer(p);
+
+ p.setPathEffect(NULL);
+ p.setXfermode(NULL);
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(SK_Scalar1);
+ rast->addLayer(p);
+}
+
+typedef void (*raster_proc)(SkLayerRasterizer*, SkPaint&);
+
+static const raster_proc gRastProcs[] = {
+ r0, r1, r2, r3, r4, r5, r6, r7, r8, r9
+};
+
+static const struct {
+ SkColor fMul, fAdd;
+} gLightingColors[] = {
+ { 0x808080, 0x800000 }, // general case
+ { 0x707070, 0x707070 }, // no-pin case
+ { 0xFFFFFF, 0x800000 }, // just-add case
+ { 0x808080, 0x000000 }, // just-mul case
+ { 0xFFFFFF, 0x000000 } // identity case
+};
+
+static unsigned color_dist16(uint16_t a, uint16_t b) {
+ unsigned dr = SkAbs32(SkPacked16ToR32(a) - SkPacked16ToR32(b));
+ unsigned dg = SkAbs32(SkPacked16ToG32(a) - SkPacked16ToG32(b));
+ unsigned db = SkAbs32(SkPacked16ToB32(a) - SkPacked16ToB32(b));
+
+ return SkMax32(dr, SkMax32(dg, db));
+}
+
+static unsigned scale_dist(unsigned dist, unsigned scale) {
+ dist >>= 6;
+ dist = (dist << 2) | dist;
+ dist = (dist << 4) | dist;
+ return dist;
+
+// return SkAlphaMul(dist, scale);
+}
+
+static void apply_shader(SkPaint* paint, int index) {
+ raster_proc proc = gRastProcs[index];
+ if (proc) {
+ SkPaint p;
+ SkLayerRasterizer* rast = new SkLayerRasterizer;
+
+ p.setAntiAlias(true);
+ proc(rast, p);
+ paint->setRasterizer(rast)->unref();
+ }
+
+#if 1
+ SkScalar dir[] = { SK_Scalar1, SK_Scalar1, SK_Scalar1 };
+ paint->setMaskFilter(SkBlurMaskFilter::CreateEmboss(dir, SK_Scalar1/4, SkIntToScalar(4), SkIntToScalar(3)))->unref();
+ paint->setColor(SK_ColorBLUE);
+#endif
+}
+
+class DemoView : public SampleView {
+public:
+ DemoView() {}
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Demo");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual bool onClick(Click* click) {
+ return this->INHERITED::onClick(click);
+ }
+
+ void makePath(SkPath& path) {
+ path.addCircle(SkIntToScalar(20), SkIntToScalar(20), SkIntToScalar(20),
+ SkPath::kCCW_Direction);
+ for (int index = 0; index < 10; index++) {
+ SkScalar x = SkFloatToScalar(cos(index / 10.0f * 2 * 3.1415925358f));
+ SkScalar y = SkFloatToScalar(sin(index / 10.0f * 2 * 3.1415925358f));
+ x *= index & 1 ? 7 : 14;
+ y *= index & 1 ? 7 : 14;
+ x += SkIntToScalar(20);
+ y += SkIntToScalar(20);
+ if (index == 0)
+ path.moveTo(x, y);
+ else
+ path.lineTo(x, y);
+ }
+ path.close();
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ canvas->save();
+ drawPicture(canvas, 0);
+ canvas->restore();
+
+ {
+ SkPicture picture;
+ SkCanvas* record = picture.beginRecording(320, 480);
+ drawPicture(record, 120);
+ canvas->translate(0, SkIntToScalar(120));
+
+ SkRect clip;
+ clip.set(0, 0, SkIntToScalar(160), SkIntToScalar(160));
+ do {
+ canvas->save();
+ canvas->clipRect(clip);
+ picture.draw(canvas);
+ canvas->restore();
+ if (clip.fRight < SkIntToScalar(320))
+ clip.offset(SkIntToScalar(160), 0);
+ else if (clip.fBottom < SkIntToScalar(480))
+ clip.offset(-SkIntToScalar(320), SkIntToScalar(160));
+ else
+ break;
+ } while (true);
+ }
+ }
+
+ void drawPicture(SkCanvas* canvas, int spriteOffset) {
+ SkMatrix matrix; matrix.reset();
+ SkPaint paint;
+ SkPath path;
+ SkPoint start = {0, 0};
+ SkPoint stop = { SkIntToScalar(40), SkIntToScalar(40) };
+ SkRect rect = {0, 0, SkIntToScalar(40), SkIntToScalar(40) };
+ SkRect rect2 = {0, 0, SkIntToScalar(65), SkIntToScalar(20) };
+ SkScalar left = 0, top = 0, x = 0, y = 0;
+ size_t index;
+
+ char ascii[] = "ascii...";
+ size_t asciiLength = sizeof(ascii) - 1;
+ char utf8[] = "utf8" "\xe2\x80\xa6";
+ short utf16[] = {'u', 't', 'f', '1', '6', 0x2026 };
+ short utf16simple[] = {'u', 't', 'f', '1', '6', '!' };
+
+ makePath(path);
+ SkTDArray<SkPoint>(pos);
+ pos.setCount(asciiLength);
+ for (index = 0; index < asciiLength; index++)
+ pos[index].set(SkIntToScalar(index * 10), SkIntToScalar(index * 2));
+ SkTDArray<SkPoint>(pos2);
+ pos2.setCount(asciiLength);
+ for (index = 0; index < asciiLength; index++)
+ pos2[index].set(SkIntToScalar(index * 10), SkIntToScalar(20));
+
+ // shaders
+ SkPoint linearPoints[] = { { 0, 0, }, { SkIntToScalar(40), SkIntToScalar(40) } };
+ SkColor linearColors[] = { SK_ColorRED, SK_ColorBLUE };
+ SkScalar* linearPos = NULL;
+ int linearCount = 2;
+ SkShader::TileMode linearMode = SkShader::kMirror_TileMode;
+ SkUnitMapper* linearMapper = new SkDiscreteMapper(3);
+ SkAutoUnref unmapLinearMapper(linearMapper);
+ SkShader* linear = SkGradientShader::CreateLinear(linearPoints,
+ linearColors, linearPos, linearCount, linearMode, linearMapper);
+
+ SkPoint radialCenter = { SkIntToScalar(25), SkIntToScalar(25) };
+ SkScalar radialRadius = SkIntToScalar(25);
+ SkColor radialColors[] = { SK_ColorGREEN, SK_ColorGRAY, SK_ColorRED };
+ SkScalar radialPos[] = { 0, SkIntToScalar(3) / 5, SkIntToScalar(1)};
+ int radialCount = 3;
+ SkShader::TileMode radialMode = SkShader::kRepeat_TileMode;
+ SkUnitMapper* radialMapper = new SkCosineMapper();
+ SkAutoUnref unmapRadialMapper(radialMapper);
+ SkShader* radial = SkGradientShader::CreateRadial(radialCenter,
+ radialRadius, radialColors, radialPos, radialCount,
+ radialMode, radialMapper);
+
+ SkTransparentShader* transparentShader = new SkTransparentShader();
+ SkEmbossMaskFilter::Light light;
+ light.fDirection[0] = SK_Scalar1/2;
+ light.fDirection[1] = SK_Scalar1/2;
+ light.fDirection[2] = SK_Scalar1/3;
+ light.fAmbient = 0x48;
+ light.fSpecular = 0x80;
+ SkScalar radius = SkIntToScalar(12)/5;
+ SkEmbossMaskFilter* embossFilter = new SkEmbossMaskFilter(light,
+ radius);
+
+ SkXfermode* xfermode = SkXfermode::Create(SkXfermode::kXor_Mode);
+ SkColorFilter* lightingFilter = SkColorFilter::CreateLightingFilter(
+ 0xff89bc45, 0xff112233);
+
+ canvas->save();
+ canvas->translate(SkIntToScalar(0), SkIntToScalar(5));
+ paint.setFlags(SkPaint::kAntiAlias_Flag | SkPaint::kFilterBitmap_Flag);
+ // !!! draw through a clip
+ paint.setColor(SK_ColorLTGRAY);
+ paint.setStyle(SkPaint::kFill_Style);
+ SkRect clip = {0, 0, SkIntToScalar(320), SkIntToScalar(120)};
+ canvas->clipRect(clip);
+ paint.setShader(SkShader::CreateBitmapShader(fTx,
+ SkShader::kMirror_TileMode, SkShader::kRepeat_TileMode))->unref();
+ canvas->drawPaint(paint);
+ canvas->save();
+
+ // line (exercises xfermode, colorShader, colorFilter, filterShader)
+ paint.setColor(SK_ColorGREEN);
+ paint.setStrokeWidth(SkIntToScalar(10));
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setXfermode(xfermode)->unref();
+ paint.setColorFilter(lightingFilter)->unref();
+ canvas->drawLine(start.fX, start.fY, stop.fX, stop.fY, paint); // should not be green
+ paint.setXfermode(NULL);
+ paint.setColorFilter(NULL);
+
+ // rectangle
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas->translate(SkIntToScalar(50), 0);
+ paint.setColor(SK_ColorYELLOW);
+ paint.setShader(linear)->unref();
+ paint.setPathEffect(pathEffectTest())->unref();
+ canvas->drawRect(rect, paint);
+ paint.setPathEffect(NULL);
+
+ // circle w/ emboss & transparent (exercises 3dshader)
+ canvas->translate(SkIntToScalar(50), 0);
+ paint.setMaskFilter(embossFilter)->unref();
+ canvas->drawOval(rect, paint);
+ canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
+ paint.setShader(transparentShader)->unref();
+ canvas->drawOval(rect, paint);
+ canvas->translate(0, SkIntToScalar(-10));
+
+ // path
+ canvas->translate(SkIntToScalar(50), 0);
+ paint.setColor(SK_ColorRED);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkIntToScalar(5));
+ paint.setShader(radial)->unref();
+ paint.setMaskFilter(NULL);
+ canvas->drawPath(path, paint);
+
+ paint.setShader(NULL);
+ // bitmap, sprite
+ canvas->translate(SkIntToScalar(50), 0);
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas->drawBitmap(fBug, left, top, &paint);
+ canvas->translate(SkIntToScalar(30), 0);
+ canvas->drawSprite(fTb,
+ SkScalarRound(canvas->getTotalMatrix().getTranslateX()),
+ spriteOffset + 10, &paint);
+
+ canvas->translate(-SkIntToScalar(30), SkIntToScalar(30));
+ paint.setShader(shaderTest())->unref(); // test compose shader
+ canvas->drawRect(rect2, paint);
+ paint.setShader(NULL);
+
+ canvas->restore();
+ // text
+ canvas->translate(0, SkIntToScalar(60));
+ canvas->save();
+ paint.setColor(SK_ColorGRAY);
+ canvas->drawPosText(ascii, asciiLength, pos.begin(), paint);
+ canvas->drawPosText(ascii, asciiLength, pos2.begin(), paint);
+
+ canvas->translate(SkIntToScalar(50), 0);
+ paint.setColor(SK_ColorCYAN);
+ canvas->drawText(utf8, sizeof(utf8) - 1, x, y, paint);
+
+ canvas->translate(SkIntToScalar(30), 0);
+ paint.setColor(SK_ColorMAGENTA);
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ matrix.setTranslate(SkIntToScalar(10), SkIntToScalar(10));
+ canvas->drawTextOnPath((void*) utf16, sizeof(utf16), path, &matrix, paint);
+ canvas->translate(0, SkIntToScalar(20));
+ canvas->drawTextOnPath((void*) utf16simple, sizeof(utf16simple), path, &matrix, paint);
+ canvas->restore();
+
+ canvas->translate(0, SkIntToScalar(60));
+ paint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
+ canvas->restore();
+ }
+
+ /*
+./SkColorFilter.h:25:class SkColorFilter : public SkFlattenable { -- abstract
+ static SkColorFilter* CreatXfermodeFilter() *** untested ***
+ static SkColorFilter* CreatePorterDuffFilter() *** untested ***
+ static SkColorFilter* CreateLightingFilter() -- tested
+./SkDrawLooper.h:9:class SkDrawLooper : public SkFlattenable { -- virtually abstract
+ ./SkBlurDrawLooper.h:9:class SkBlurDrawLooper : public SkDrawLooper { *** untested ***
+./SkMaskFilter.h:41:class SkMaskFilter : public SkFlattenable { -- abstract chmod +w .h
+ ./SkEmbossMaskFilter.h:27:class SkEmbossMaskFilter : public SkMaskFilter { -- tested
+./SkPathEffect.h:33:class SkPathEffect : public SkFlattenable { -- abstract
+ ./Sk1DPathEffect.h:27:class Sk1DPathEffect : public SkPathEffect { -- abstract
+ ./Sk1DPathEffect.h:48:class SkPath1DPathEffect : public Sk1DPathEffect { -- tested
+ ./Sk2DPathEffect.h:25:class Sk2DPathEffect : public SkPathEffect { *** untested ***
+ ./SkCornerPathEffect.h:28:class SkCornerPathEffect : public SkPathEffect { *** untested ***
+ ./SkDashPathEffect.h:27:class SkDashPathEffect : public SkPathEffect {
+ ./SkDiscretePathEffect.h:27:class SkDiscretePathEffect : public SkPathEffect {
+ ./SkPaint.h:760:class SkStrokePathEffect : public SkPathEffect {
+ ./SkPathEffect.h:58:class SkPairPathEffect : public SkPathEffect {
+ ./SkPathEffect.h:78:class SkComposePathEffect : public SkPairPathEffect {
+ ./SkPathEffect.h:114:class SkSumPathEffect : public SkPairPathEffect {
+./SkRasterizer.h:29:class SkRasterizer : public SkFlattenable {
+ ./SkLayerRasterizer.h:27:class SkLayerRasterizer : public SkRasterizer {
+./SkShader.h:36:class SkShader : public SkFlattenable {
+ ./SkColorFilter.h:59:class SkFilterShader : public SkShader {
+ ./SkColorShader.h:26:class SkColorShader : public SkShader {
+ ./SkShaderExtras.h:31:class SkComposeShader : public SkShader {
+ ./SkTransparentShader.h:23:class SkTransparentShader : public SkShader {
+./SkUnitMapper.h:24:class SkUnitMapper : public SkFlattenable {
+ ./SkUnitMapper.h:33:class SkDiscreteMapper : public SkUnitMapper {
+ ./SkUnitMapper.h:51:class SkFlipCosineMapper : public SkUnitMapper {
+./SkXfermode.h:32:class SkXfermode : public SkFlattenable {
+ ./SkAvoidXfermode.h:28:class SkAvoidXfermode : public SkXfermode { *** not done *** chmod +w .h .cpp
+ ./SkXfermode.h:54:class SkProcXfermode : public SkXfermode {
+ */
+
+ /*
+./SkBlurMaskFilter.h:25:class SkBlurMaskFilter {
+ chmod +w SkBlurMaskFilter.cpp
+./SkGradientShader.h:30:class SkGradientShader {
+ */
+ // save layer, bounder, looper
+ // matrix
+ // clip /path/region
+ // bitmap proc shader ?
+
+/* untested:
+SkCornerPathEffect.h:28:class SkCornerPathEffect : public SkPathEffect {
+*/
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ fClickPt.set(x, y);
+ this->inval(NULL);
+ return this->INHERITED::onFindClickHandler(x, y);
+ }
+
+ SkPathEffect* pathEffectTest() {
+ static const int gXY[] = { 1, 0, 0, -1, 2, -1, 3, 0, 2, 1, 0, 1 };
+ SkScalar gPhase = 0;
+ SkPath path;
+ path.moveTo(SkIntToScalar(gXY[0]), SkIntToScalar(gXY[1]));
+ for (unsigned i = 2; i < SK_ARRAY_COUNT(gXY); i += 2)
+ path.lineTo(SkIntToScalar(gXY[i]), SkIntToScalar(gXY[i+1]));
+ path.close();
+ path.offset(SkIntToScalar(-6), 0);
+ SkPathEffect* outer = new SkPath1DPathEffect(path, SkIntToScalar(12),
+ gPhase, SkPath1DPathEffect::kRotate_Style);
+ SkPathEffect* inner = new SkDiscretePathEffect(SkIntToScalar(2),
+ SkIntToScalar(1)/10); // SkCornerPathEffect(SkIntToScalar(2));
+ SkPathEffect* result = new SkComposePathEffect(outer, inner);
+ outer->unref();
+ inner->unref();
+ return result;
+ }
+
+ SkPathEffect* pathEffectTest2() { // unsure this works (has no visible effect)
+ SkPathEffect* outer = new SkStrokePathEffect(SkIntToScalar(4),
+ SkPaint::kStroke_Style, SkPaint::kMiter_Join, SkPaint::kButt_Cap);
+ static const SkScalar intervals[] = {SkIntToScalar(1), SkIntToScalar(2),
+ SkIntToScalar(2), SkIntToScalar(1)};
+ SkPathEffect* inner = new SkDashPathEffect(intervals,
+ sizeof(intervals) / sizeof(intervals[0]), 0);
+ SkPathEffect* result = new SkSumPathEffect(outer, inner);
+ outer->unref();
+ inner->unref();
+ return result;
+ }
+
+ SkShader* shaderTest() {
+ SkPoint pts[] = { { 0, 0, }, { SkIntToScalar(100), 0 } };
+ SkColor colors[] = { SK_ColorRED, SK_ColorBLUE };
+ SkShader* shaderA = SkGradientShader::CreateLinear(pts, colors, NULL,
+ 2, SkShader::kClamp_TileMode);
+ pts[1].set(0, SkIntToScalar(100));
+ SkColor colors2[] = {SK_ColorBLACK, SkColorSetARGB(0x80, 0, 0, 0)};
+ SkShader* shaderB = SkGradientShader::CreateLinear(pts, colors2, NULL,
+ 2, SkShader::kClamp_TileMode);
+ SkXfermode* mode = SkXfermode::Create(SkXfermode::kDstIn_Mode);
+ SkShader* result = new SkComposeShader(shaderA, shaderB, mode);
+ shaderA->unref();
+ shaderB->unref();
+ mode->unref();
+ return result;
+ }
+
+ virtual void startTest() {
+ SkImageDecoder::DecodeFile("/Users/caryclark/Desktop/bugcirc.gif", &fBug);
+ SkImageDecoder::DecodeFile("/Users/caryclark/Desktop/tbcirc.gif", &fTb);
+ SkImageDecoder::DecodeFile("/Users/caryclark/Desktop/05psp04.gif", &fTx);
+ }
+
+ void drawRaster(SkCanvas* canvas) {
+ for (size_t index = 0; index < SK_ARRAY_COUNT(gRastProcs); index++)
+ drawOneRaster(canvas);
+ }
+
+ void drawOneRaster(SkCanvas* canvas) {
+ canvas->save();
+
+ SkScalar x = SkIntToScalar(20);
+ SkScalar y = SkIntToScalar(40);
+ SkPaint paint;
+
+ paint.setAntiAlias(true);
+ paint.setTextSize(SkIntToScalar(48));
+ paint.setTypeface(SkTypeface::CreateFromName("sans-serif",
+ SkTypeface::kBold));
+
+ SkString str("GOOGLE");
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRastProcs); i++) {
+ apply_shader(&paint, i);
+
+ // paint.setMaskFilter(NULL);
+ // paint.setColor(SK_ColorBLACK);
+
+#if 01
+ int index = i % SK_ARRAY_COUNT(gLightingColors);
+ paint.setColorFilter(SkColorFilter::CreateLightingFilter(
+ gLightingColors[index].fMul,
+ gLightingColors[index].fAdd))->unref();
+#endif
+
+ canvas->drawText(str.c_str(), str.size(), x, y, paint);
+ SkRect oval = { x, y - SkIntToScalar(40), x + SkIntToScalar(40), y };
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawOval(oval, paint);
+ paint.setStyle(SkPaint::kFill_Style);
+
+ y += paint.getFontSpacing();
+ }
+
+ canvas->restore();
+
+ if (1) {
+ SkAvoidXfermode mode(SK_ColorWHITE, 0xFF,
+ SkAvoidXfermode::kTargetColor_Mode);
+ SkPaint paint;
+ x += SkIntToScalar(20);
+ SkRect r = { x, 0, x + SkIntToScalar(360), SkIntToScalar(700) };
+ paint.setXfermode(&mode);
+ paint.setColor(SK_ColorGREEN);
+ paint.setAntiAlias(true);
+ canvas->drawOval(r, paint);
+ }
+ }
+
+private:
+ SkPoint fClickPt;
+ SkBitmap fBug, fTb, fTx;
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new DemoView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleAnimatedGradient.cpp b/samplecode/SampleAnimatedGradient.cpp
new file mode 100644
index 0000000..a7b2a46
--- /dev/null
+++ b/samplecode/SampleAnimatedGradient.cpp
@@ -0,0 +1,90 @@
+#include "SampleCode.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+
+class GradientView : public SampleView {
+public:
+ GradientView() {
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ struct GradData {
+ int fCount;
+ const SkColor* fColors;
+ const SkScalar* fPos;
+ };
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Gradients");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkScalarHalf(SkIntToScalar(3)));
+ paint.setStyle(SkPaint::kFill_Style);
+
+ SkPoint p = SkPoint::Make(0,0);
+ SkPoint q = SkPoint::Make(100,100);
+ SkPoint pts[] = {p, q};
+
+ SkScalar t, temp, x, y;
+ SkColor gColors[] = {
+ SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
+ };
+ t = SampleCode::GetAnimScalar(SkIntToScalar(2), SkIntToScalar(20));
+ temp = SampleCode::GetAnimScalar(SkIntToScalar(1), SkIntToScalar(8));
+ SkScalar step = SK_ScalarPI / (10);
+ SkScalar angle = t * step;
+ x = SkScalarSinCos(angle, &y);
+ SkScalar colorPositions[] = { 0, 0.1 + x, 0.4 + y, 0.9 - x + y, 1.0};
+ GradData data = { 5, gColors, colorPositions };
+
+
+ SkRect r = { 0, 0, SkIntToScalar(200), SkIntToScalar(200) };
+ SkShader* shader1 = SkGradientShader::CreateLinear(
+ pts, data.fColors, data.fPos,data.fCount,
+ SkShader::kMirror_TileMode);
+ paint.setShader(shader1)->unref();
+
+ canvas->drawRect(r, paint);
+
+
+ SkPoint s = SkPoint::Make(100,100);
+ SkShader* shader2 = SkGradientShader::CreateRadial(
+ s, 100, data.fColors, data.fPos, data.fCount,
+ SkShader::kMirror_TileMode);
+ paint.setShader(shader2)->unref();
+ canvas->translate(250, 0);
+ canvas->drawRect(r, paint);
+
+ SkShader* shader3 = SkGradientShader::CreateTwoPointRadial(
+ p, 0, q, 100, data.fColors, data.fPos, data.fCount,
+ SkShader::kMirror_TileMode);
+ paint.setShader(shader3)->unref();
+ canvas->translate(0, 250);
+ canvas->drawRect(r, paint);
+
+ SkShader* shader4 = SkGradientShader::CreateSweep(
+ 100, 100, data.fColors, data.fPos, data.fCount);
+
+ paint.setShader(shader4)->unref();
+ canvas->translate(-250, 0);
+ canvas->drawRect(r, paint);
+
+ this->inval(NULL);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new GradientView; }
+static SkViewRegister reg(MyFactory); \ No newline at end of file
diff --git a/samplecode/SampleAnimator.cpp b/samplecode/SampleAnimator.cpp
new file mode 100644
index 0000000..99173fc
--- /dev/null
+++ b/samplecode/SampleAnimator.cpp
@@ -0,0 +1,159 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+
+#include "SkAnimator.h"
+#include "SkStream.h"
+#include "SkDOM.h"
+
+///////////////////////////////////////////////////////////////////////////////
+
+class SkAnimatorView : public SkView {
+public:
+ SkAnimatorView();
+ virtual ~SkAnimatorView();
+
+ void setURIBase(const char dir[]);
+
+ SkAnimator* getAnimator() const { return fAnimator; }
+
+ bool decodeFile(const char path[]);
+ bool decodeMemory(const void* buffer, size_t size);
+ bool decodeStream(SkStream* stream);
+
+protected:
+ // overrides
+ virtual void onDraw(SkCanvas*);
+
+private:
+ SkString fBaseURI;
+ SkAnimator* fAnimator;
+
+ typedef SkView INHERITED;
+};
+
+SkAnimatorView::SkAnimatorView() : fAnimator(NULL) {}
+
+SkAnimatorView::~SkAnimatorView() {
+ delete fAnimator;
+}
+
+void SkAnimatorView::setURIBase(const char dir[]) {
+ fBaseURI.set(dir);
+}
+
+bool SkAnimatorView::decodeFile(const char path[]) {
+ SkFILEStream* is = new SkFILEStream(path);
+ SkAutoUnref aur(is);
+ return is->isValid() && this->decodeStream(is);
+}
+
+bool SkAnimatorView::decodeMemory(const void* buffer, size_t size) {
+ SkMemoryStream* is = new SkMemoryStream(buffer, size);
+ SkAutoUnref aur(is);
+ return this->decodeStream(is);
+}
+
+static const SkDOMNode* find_nodeID(const SkDOM& dom,
+ const SkDOMNode* node, const char name[]) {
+ if (NULL == node) {
+ node = dom.getRootNode();
+ }
+ do {
+ const char* idval = dom.findAttr(node, "id");
+ if (idval && !strcmp(idval, name)) {
+ return node;
+ }
+ const SkDOMNode* child = dom.getFirstChild(node);
+ if (child) {
+ const SkDOMNode* found = find_nodeID(dom, child, name);
+ if (found) {
+ return found;
+ }
+ }
+ } while ((node = dom.getNextSibling(node)) != NULL);
+ return NULL;
+}
+
+bool SkAnimatorView::decodeStream(SkStream* stream) {
+ delete fAnimator;
+ fAnimator = new SkAnimator;
+ fAnimator->setURIBase(fBaseURI.c_str());
+#if 0
+ if (!fAnimator->decodeStream(stream)) {
+ delete fAnimator;
+ fAnimator = NULL;
+ return false;
+ }
+#else
+ size_t len = stream->getLength();
+ char* text = (char*)sk_malloc_throw(len);
+ stream->read(text, len);
+ SkDOM dom;
+ const SkDOM::Node* root = dom.build(text, len);
+ if (NULL == root) {
+ return false;
+ }
+ if (!fAnimator->decodeDOM(dom, root)) {
+ delete fAnimator;
+ fAnimator = NULL;
+ return false;
+ }
+ for (int i = 0; i <= 10; i++) {
+ SkString name("glyph");
+ name.appendS32(i);
+ const SkDOM::Node* node = find_nodeID(dom, NULL, name.c_str());
+ SkASSERT(node);
+ SkRect r;
+ dom.findScalar(node, "left", &r.fLeft);
+ dom.findScalar(node, "top", &r.fTop);
+ dom.findScalar(node, "width", &r.fRight); r.fRight += r.fLeft;
+ dom.findScalar(node, "height", &r.fBottom); r.fBottom += r.fTop;
+ SkDebugf("--- %s [%g %g %g %g]\n", name.c_str(),
+ r.fLeft, r.fTop, r.fRight, r.fBottom);
+ }
+#endif
+ return true;
+}
+
+#include "SkTime.h"
+
+void SkAnimatorView::onDraw(SkCanvas* canvas) {
+ if (fAnimator) {
+ canvas->drawColor(SK_ColorWHITE);
+ fAnimator->draw(canvas, 0);
+#if 0
+ canvas->save();
+ canvas->translate(120, 30);
+ canvas->scale(0.5, 0.5);
+ fAnimator->draw(canvas, 0);
+ canvas->restore();
+
+ canvas->save();
+ canvas->translate(190, 40);
+ canvas->scale(0.25, 0.25);
+ fAnimator->draw(canvas, 0);
+ canvas->restore();
+
+ this->inval(NULL);
+#endif
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() {
+ SkAnimatorView* av = new SkAnimatorView;
+// av->decodeFile("/skimages/test.xml");
+#if 0
+ av->setURIBase("/skia/trunk/animations/");
+ av->decodeFile("/skia/trunk/animations/checkbox.xml");
+#else
+ av->setURIBase("/");
+ av->decodeFile("/testanim.txt");
+#endif
+ return av;
+}
+
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
new file mode 100644
index 0000000..3efffe6
--- /dev/null
+++ b/samplecode/SampleApp.cpp
@@ -0,0 +1,1647 @@
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkGpuCanvas.h"
+#include "SkGraphics.h"
+#include "SkImageEncoder.h"
+#include "SkPaint.h"
+#include "SkPicture.h"
+#include "SkStream.h"
+#include "SkTime.h"
+#include "SkWindow.h"
+
+#include "SampleCode.h"
+#include "GrContext.h"
+#include "SkTouchGesture.h"
+#include "SkTypeface.h"
+
+#define TEST_GPIPEx
+
+#ifdef TEST_GPIPE
+#define PIPE_FILE
+#define FILE_PATH "/path/to/drawing.data"
+#endif
+
+#define USE_ARROWS_FOR_ZOOM true
+//#define DEFAULT_TO_GPU
+
+extern SkView* create_overview(int, const SkViewFactory[]);
+
+#define SK_SUPPORT_GL
+
+#define ANIMATING_EVENTTYPE "nextSample"
+#define ANIMATING_DELAY 750
+
+#ifdef SK_DEBUG
+ #define FPS_REPEAT_MULTIPLIER 1
+#else
+ #define FPS_REPEAT_MULTIPLIER 10
+#endif
+#define FPS_REPEAT_COUNT (10 * FPS_REPEAT_MULTIPLIER)
+
+#ifdef SK_SUPPORT_GL
+ #include "GrGLConfig.h"
+#endif
+
+///////////////
+static const char view_inval_msg[] = "view-inval-msg";
+
+static void postInvalDelay(SkEventSinkID sinkID) {
+ SkEvent* evt = new SkEvent(view_inval_msg);
+ evt->post(sinkID, 1);
+}
+
+static bool isInvalEvent(const SkEvent& evt) {
+ return evt.isType(view_inval_msg);
+}
+//////////////////
+
+SkViewRegister* SkViewRegister::gHead;
+SkViewRegister::SkViewRegister(SkViewFactory fact) : fFact(fact) {
+ static bool gOnce;
+ if (!gOnce) {
+ gHead = NULL;
+ gOnce = true;
+ }
+
+ fChain = gHead;
+ gHead = this;
+}
+
+#if defined(SK_SUPPORT_GL)
+ #define SK_USE_SHADERS
+#endif
+
+#ifdef SK_BUILD_FOR_MAC
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreFoundation/CFURLAccess.h>
+
+static void testpdf() {
+ CFStringRef path = CFStringCreateWithCString(NULL, "/test.pdf",
+ kCFStringEncodingUTF8);
+ CFURLRef url = CFURLCreateWithFileSystemPath(NULL, path,
+ kCFURLPOSIXPathStyle,
+ false);
+ CFRelease(path);
+ CGRect box = CGRectMake(0, 0, 8*72, 10*72);
+ CGContextRef cg = CGPDFContextCreateWithURL(url, &box, NULL);
+ CFRelease(url);
+
+ CGContextBeginPage(cg, &box);
+ CGRect r = CGRectMake(10, 10, 40 + 0.5, 50 + 0.5);
+ CGContextFillEllipseInRect(cg, r);
+ CGContextEndPage(cg);
+ CGContextRelease(cg);
+
+ if (false) {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kA8_Config, 64, 64);
+ bm.allocPixels();
+ bm.eraseColor(0);
+
+ SkCanvas canvas(bm);
+
+ }
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+
+enum FlipAxisEnum {
+ kFlipAxis_X = (1 << 0),
+ kFlipAxis_Y = (1 << 1)
+};
+
+enum SkTriState {
+ kFalse_SkTriState,
+ kTrue_SkTriState,
+ kUnknown_SkTriState,
+};
+
+static SkTriState cycle_tristate(SkTriState state) {
+ static const SkTriState gCycle[] = {
+ /* kFalse_SkTriState -> */ kUnknown_SkTriState,
+ /* kTrue_SkTriState -> */ kFalse_SkTriState,
+ /* kUnknown_SkTriState -> */ kTrue_SkTriState,
+ };
+ return gCycle[state];
+}
+
+#include "SkDrawFilter.h"
+
+class FlagsDrawFilter : public SkDrawFilter {
+public:
+ FlagsDrawFilter(SkTriState lcd, SkTriState aa, SkTriState filter,
+ SkTriState hinting) :
+ fLCDState(lcd), fAAState(aa), fFilterState(filter), fHintingState(hinting) {}
+
+ virtual void filter(SkPaint* paint, Type t) {
+ if (kText_Type == t && kUnknown_SkTriState != fLCDState) {
+ paint->setLCDRenderText(kTrue_SkTriState == fLCDState);
+ }
+ if (kUnknown_SkTriState != fAAState) {
+ paint->setAntiAlias(kTrue_SkTriState == fAAState);
+ }
+ if (kUnknown_SkTriState != fFilterState) {
+ paint->setFilterBitmap(kTrue_SkTriState == fFilterState);
+ }
+ if (kUnknown_SkTriState != fHintingState) {
+ paint->setHinting(kTrue_SkTriState == fHintingState ?
+ SkPaint::kNormal_Hinting :
+ SkPaint::kSlight_Hinting);
+ }
+ }
+
+private:
+ SkTriState fLCDState;
+ SkTriState fAAState;
+ SkTriState fFilterState;
+ SkTriState fHintingState;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+#define MAX_ZOOM_LEVEL 8
+#define MIN_ZOOM_LEVEL -8
+
+static const char gCharEvtName[] = "SampleCode_Char_Event";
+static const char gKeyEvtName[] = "SampleCode_Key_Event";
+static const char gTitleEvtName[] = "SampleCode_Title_Event";
+static const char gPrefSizeEvtName[] = "SampleCode_PrefSize_Event";
+static const char gFastTextEvtName[] = "SampleCode_FastText_Event";
+
+bool SampleCode::CharQ(const SkEvent& evt, SkUnichar* outUni) {
+ if (evt.isType(gCharEvtName, sizeof(gCharEvtName) - 1)) {
+ if (outUni) {
+ *outUni = evt.getFast32();
+ }
+ return true;
+ }
+ return false;
+}
+
+bool SampleCode::KeyQ(const SkEvent& evt, SkKey* outKey) {
+ if (evt.isType(gKeyEvtName, sizeof(gKeyEvtName) - 1)) {
+ if (outKey) {
+ *outKey = (SkKey)evt.getFast32();
+ }
+ return true;
+ }
+ return false;
+}
+
+bool SampleCode::TitleQ(const SkEvent& evt) {
+ return evt.isType(gTitleEvtName, sizeof(gTitleEvtName) - 1);
+}
+
+void SampleCode::TitleR(SkEvent* evt, const char title[]) {
+ SkASSERT(evt && TitleQ(*evt));
+ evt->setString(gTitleEvtName, title);
+}
+
+bool SampleCode::PrefSizeQ(const SkEvent& evt) {
+ return evt.isType(gPrefSizeEvtName, sizeof(gPrefSizeEvtName) - 1);
+}
+
+void SampleCode::PrefSizeR(SkEvent* evt, SkScalar width, SkScalar height) {
+ SkASSERT(evt && PrefSizeQ(*evt));
+ SkScalar size[2];
+ size[0] = width;
+ size[1] = height;
+ evt->setScalars(gPrefSizeEvtName, 2, size);
+}
+
+bool SampleCode::FastTextQ(const SkEvent& evt) {
+ return evt.isType(gFastTextEvtName, sizeof(gFastTextEvtName) - 1);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkMSec gAnimTime;
+static SkMSec gAnimTimePrev;
+
+SkMSec SampleCode::GetAnimTime() { return gAnimTime; }
+SkMSec SampleCode::GetAnimTimeDelta() { return gAnimTime - gAnimTimePrev; }
+SkScalar SampleCode::GetAnimSecondsDelta() {
+ return SkDoubleToScalar(GetAnimTimeDelta() / 1000.0);
+}
+
+SkScalar SampleCode::GetAnimScalar(SkScalar speed, SkScalar period) {
+ // since gAnimTime can be up to 32 bits, we can't convert it to a float
+ // or we'll lose the low bits. Hence we use doubles for the intermediate
+ // calculations
+ double seconds = (double)gAnimTime / 1000.0;
+ double value = SkScalarToDouble(speed) * seconds;
+ if (period) {
+ value = ::fmod(value, SkScalarToDouble(period));
+ }
+ return SkDoubleToScalar(value);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* curr_view(SkWindow* wind) {
+ SkView::F2BIter iter(wind);
+ return iter.next();
+}
+
+class SampleWindow : public SkOSWindow {
+ SkTDArray<SkViewFactory> fSamples;
+public:
+ SampleWindow(void* hwnd);
+ virtual ~SampleWindow();
+
+ virtual void draw(SkCanvas* canvas);
+
+protected:
+ virtual void onDraw(SkCanvas* canvas);
+ virtual bool onHandleKey(SkKey key);
+ virtual bool onHandleChar(SkUnichar);
+ virtual void onSizeChange();
+
+ virtual SkCanvas* beforeChildren(SkCanvas*);
+ virtual void afterChildren(SkCanvas*);
+ virtual void beforeChild(SkView* child, SkCanvas* canvas);
+ virtual void afterChild(SkView* child, SkCanvas* canvas);
+
+ virtual bool onEvent(const SkEvent& evt);
+ virtual bool onQuery(SkEvent* evt);
+
+ virtual bool onDispatchClick(int x, int y, Click::State);
+ virtual bool onClick(Click* click);
+ virtual Click* onFindClickHandler(SkScalar x, SkScalar y);
+
+#if 0
+ virtual bool handleChar(SkUnichar uni);
+ virtual bool handleEvent(const SkEvent& evt);
+ virtual bool handleKey(SkKey key);
+ virtual bool handleKeyUp(SkKey key);
+ virtual bool onHandleKeyUp(SkKey key);
+#endif
+
+private:
+ int fCurrIndex;
+
+ SkPicture* fPicture;
+ SkGpuCanvas* fGpuCanvas;
+ GrContext* fGrContext;
+ SkPath fClipPath;
+
+ SkTouchGesture fGesture;
+ int fZoomLevel;
+ SkScalar fZoomScale;
+
+ enum CanvasType {
+ kRaster_CanvasType,
+ kPicture_CanvasType,
+ kGPU_CanvasType
+ };
+ CanvasType fCanvasType;
+
+ bool fUseClip;
+ bool fNClip;
+ bool fRepeatDrawing;
+ bool fAnimating;
+ bool fRotate;
+ bool fScale;
+ bool fRequestGrabImage;
+ bool fUsePipe;
+ bool fMeasureFPS;
+ SkMSec fMeasureFPS_Time;
+
+ // The following are for the 'fatbits' drawing
+ // Latest position of the mouse.
+ int fMouseX, fMouseY;
+ int fFatBitsScale;
+ // Used by the text showing position and color values.
+ SkTypeface* fTypeface;
+ bool fShowZoomer;
+
+ SkTriState fLCDState;
+ SkTriState fAAState;
+ SkTriState fFilterState;
+ SkTriState fHintingState;
+ unsigned fFlipAxis;
+
+ int fScrollTestX, fScrollTestY;
+
+ bool make3DReady();
+ void changeZoomLevel(int delta);
+
+ void loadView(SkView*);
+ void updateTitle();
+ bool nextSample();
+
+ void toggleZoomer();
+ bool zoomIn();
+ bool zoomOut();
+ void updatePointer(int x, int y);
+ void showZoomer(SkCanvas* canvas);
+
+ void postAnimatingEvent() {
+ if (fAnimating) {
+ SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE);
+ evt->post(this->getSinkID(), ANIMATING_DELAY);
+ }
+ }
+
+
+ static CanvasType cycle_canvastype(CanvasType);
+
+ typedef SkOSWindow INHERITED;
+};
+
+bool SampleWindow::zoomIn()
+{
+ // Arbitrarily decided
+ if (fFatBitsScale == 25) return false;
+ fFatBitsScale++;
+ this->inval(NULL);
+ return true;
+}
+
+bool SampleWindow::zoomOut()
+{
+ if (fFatBitsScale == 1) return false;
+ fFatBitsScale--;
+ this->inval(NULL);
+ return true;
+}
+
+void SampleWindow::toggleZoomer()
+{
+ fShowZoomer = !fShowZoomer;
+ this->inval(NULL);
+}
+
+void SampleWindow::updatePointer(int x, int y)
+{
+ fMouseX = x;
+ fMouseY = y;
+ if (fShowZoomer) {
+ this->inval(NULL);
+ }
+}
+
+bool SampleWindow::make3DReady() {
+
+#if defined(SK_SUPPORT_GL)
+ if (attachGL()) {
+ if (NULL != fGrContext) {
+ // various gr lifecycle tests
+ #if 0
+ fGrContext->freeGpuResources();
+ #elif 0
+ // this will leak resources.
+ fGrContext->contextLost();
+ #elif 0
+ GrAssert(1 == fGrContext->refcnt());
+ fGrContext->unref();
+ fGrContext = NULL;
+ #endif
+ }
+
+ if (NULL == fGrContext) {
+ #if defined(SK_USE_SHADERS)
+ fGrContext = GrContext::Create(kOpenGL_Shaders_GrEngine, NULL);
+ #else
+ fGrContext = GrContext::Create(kOpenGL_Fixed_GrEngine, NULL);
+ #endif
+ SkDebugf("---- constructor\n");
+ }
+
+ if (NULL != fGrContext) {
+ return true;
+ } else {
+ detachGL();
+ }
+ }
+#endif
+ SkDebugf("Failed to setup 3D");
+ return false;
+}
+
+SampleWindow::CanvasType SampleWindow::cycle_canvastype(CanvasType ct) {
+ static const CanvasType gCT[] = {
+ kPicture_CanvasType,
+ kGPU_CanvasType,
+ kRaster_CanvasType
+ };
+ return gCT[ct];
+}
+
+SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
+#ifdef PIPE_FILE
+ //Clear existing file or create file if it doesn't exist
+ FILE* f = fopen(FILE_PATH, "wb");
+ fclose(f);
+#endif
+
+ fPicture = NULL;
+ fGpuCanvas = NULL;
+
+ fGrContext = NULL;
+
+#ifdef DEFAULT_TO_GPU
+ fCanvasType = kGPU_CanvasType;
+#else
+ fCanvasType = kRaster_CanvasType;
+#endif
+ fUseClip = false;
+ fNClip = false;
+ fRepeatDrawing = false;
+ fAnimating = false;
+ fRotate = false;
+ fScale = false;
+ fRequestGrabImage = false;
+ fUsePipe = false;
+ fMeasureFPS = false;
+ fLCDState = kUnknown_SkTriState;
+ fAAState = kUnknown_SkTriState;
+ fFilterState = kUnknown_SkTriState;
+ fHintingState = kUnknown_SkTriState;
+ fFlipAxis = 0;
+ fScrollTestX = fScrollTestY = 0;
+
+ fMouseX = fMouseY = 0;
+ fFatBitsScale = 8;
+ fTypeface = SkTypeface::CreateFromTypeface(NULL, SkTypeface::kBold);
+ fShowZoomer = false;
+
+ fZoomLevel = 0;
+ fZoomScale = SK_Scalar1;
+
+// this->setConfig(SkBitmap::kRGB_565_Config);
+ this->setConfig(SkBitmap::kARGB_8888_Config);
+ this->setVisibleP(true);
+ this->setClipToBounds(false);
+
+ {
+ const SkViewRegister* reg = SkViewRegister::Head();
+ while (reg) {
+ *fSamples.append() = reg->factory();
+ reg = reg->next();
+ }
+ }
+ fCurrIndex = 0;
+ this->loadView(fSamples[fCurrIndex]());
+
+#ifdef SK_BUILD_FOR_MAC
+ testpdf();
+#endif
+}
+
+SampleWindow::~SampleWindow() {
+ delete fPicture;
+ delete fGpuCanvas;
+ if (NULL != fGrContext) {
+ fGrContext->unref();
+ }
+ fTypeface->unref();
+}
+
+static SkBitmap capture_bitmap(SkCanvas* canvas) {
+ SkBitmap bm;
+ const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
+ src.copyTo(&bm, src.config());
+ return bm;
+}
+
+static bool bitmap_diff(SkCanvas* canvas, const SkBitmap& orig,
+ SkBitmap* diff) {
+ const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
+
+ SkAutoLockPixels alp0(src);
+ SkAutoLockPixels alp1(orig);
+ for (int y = 0; y < src.height(); y++) {
+ const void* srcP = src.getAddr(0, y);
+ const void* origP = orig.getAddr(0, y);
+ size_t bytes = src.width() * src.bytesPerPixel();
+ if (memcmp(srcP, origP, bytes)) {
+ SkDebugf("---------- difference on line %d\n", y);
+ return true;
+ }
+ }
+ return false;
+}
+
+static void drawText(SkCanvas* canvas, SkString string, SkScalar left, SkScalar top, SkPaint& paint)
+{
+ SkColor desiredColor = paint.getColor();
+ paint.setColor(SK_ColorWHITE);
+ const char* c_str = string.c_str();
+ size_t size = string.size();
+ SkRect bounds;
+ paint.measureText(c_str, size, &bounds);
+ bounds.offset(left, top);
+ SkScalar inset = SkIntToScalar(-2);
+ bounds.inset(inset, inset);
+ canvas->drawRect(bounds, paint);
+ if (desiredColor != SK_ColorBLACK) {
+ paint.setColor(SK_ColorBLACK);
+ canvas->drawText(c_str, size, left + SK_Scalar1, top + SK_Scalar1, paint);
+ }
+ paint.setColor(desiredColor);
+ canvas->drawText(c_str, size, left, top, paint);
+}
+
+#define XCLIP_N 8
+#define YCLIP_N 8
+
+void SampleWindow::draw(SkCanvas* canvas) {
+ // update the animation time
+ gAnimTimePrev = gAnimTime;
+ gAnimTime = SkTime::GetMSecs();
+
+ SkScalar cx = SkScalarHalf(this->width());
+ SkScalar cy = SkScalarHalf(this->height());
+
+ if (fZoomLevel) {
+ SkMatrix m;
+ SkPoint center;
+ m = canvas->getTotalMatrix();//.invert(&m);
+ m.mapXY(cx, cy, &center);
+ cx = center.fX;
+ cy = center.fY;
+
+ m.setTranslate(-cx, -cy);
+ m.postScale(fZoomScale, fZoomScale);
+ m.postTranslate(cx, cy);
+
+ canvas->concat(m);
+ }
+
+ if (fFlipAxis) {
+ SkMatrix m;
+ m.setTranslate(cx, cy);
+ if (fFlipAxis & kFlipAxis_X) {
+ m.preScale(-SK_Scalar1, SK_Scalar1);
+ }
+ if (fFlipAxis & kFlipAxis_Y) {
+ m.preScale(SK_Scalar1, -SK_Scalar1);
+ }
+ m.preTranslate(-cx, -cy);
+ canvas->concat(m);
+ }
+
+ // Apply any gesture matrix
+ if (true) {
+ const SkMatrix& localM = fGesture.localM();
+ if (localM.getType() & SkMatrix::kScale_Mask) {
+ canvas->setExternalMatrix(&localM);
+ }
+ canvas->concat(localM);
+ canvas->concat(fGesture.globalM());
+
+ if (fGesture.isActive()) {
+ this->inval(NULL);
+ }
+ }
+
+ if (fNClip) {
+ this->INHERITED::draw(canvas);
+ SkBitmap orig = capture_bitmap(canvas);
+
+ const SkScalar w = this->width();
+ const SkScalar h = this->height();
+ const SkScalar cw = w / XCLIP_N;
+ const SkScalar ch = h / YCLIP_N;
+ for (int y = 0; y < YCLIP_N; y++) {
+ SkRect r;
+ r.fTop = y * ch;
+ r.fBottom = (y + 1) * ch;
+ if (y == YCLIP_N - 1) {
+ r.fBottom = h;
+ }
+ for (int x = 0; x < XCLIP_N; x++) {
+ SkAutoCanvasRestore acr(canvas, true);
+ r.fLeft = x * cw;
+ r.fRight = (x + 1) * cw;
+ if (x == XCLIP_N - 1) {
+ r.fRight = w;
+ }
+ canvas->clipRect(r);
+ this->INHERITED::draw(canvas);
+ }
+ }
+
+ SkBitmap diff;
+ if (bitmap_diff(canvas, orig, &diff)) {
+ }
+ } else {
+ this->INHERITED::draw(canvas);
+ }
+ if (fShowZoomer && fCanvasType != kGPU_CanvasType) {
+ // In the GPU case, INHERITED::draw calls beforeChildren, which
+ // creates an SkGpuCanvas. All further draw calls are directed
+ // at that canvas, which is deleted in afterChildren (which is
+ // also called by draw), so we cannot show the zoomer here.
+ // Instead, we call it inside afterChildren.
+ showZoomer(canvas);
+ }
+}
+
+void SampleWindow::showZoomer(SkCanvas* canvas) {
+ int count = canvas->save();
+ canvas->resetMatrix();
+ // Ensure the mouse position is on screen.
+ int width = SkScalarRound(this->width());
+ int height = SkScalarRound(this->height());
+ if (fMouseX >= width) fMouseX = width - 1;
+ else if (fMouseX < 0) fMouseX = 0;
+ if (fMouseY >= height) fMouseY = height - 1;
+ else if (fMouseY < 0) fMouseY = 0;
+
+ SkBitmap bitmap = capture_bitmap(canvas);
+ bitmap.lockPixels();
+
+ // Find the size of the zoomed in view, forced to be odd, so the examined pixel is in the middle.
+ int zoomedWidth = (width >> 1) | 1;
+ int zoomedHeight = (height >> 1) | 1;
+ SkIRect src;
+ src.set(0, 0, zoomedWidth / fFatBitsScale, zoomedHeight / fFatBitsScale);
+ src.offset(fMouseX - (src.width()>>1), fMouseY - (src.height()>>1));
+ SkRect dest;
+ dest.set(0, 0, SkIntToScalar(zoomedWidth), SkIntToScalar(zoomedHeight));
+ dest.offset(SkIntToScalar(width - zoomedWidth), SkIntToScalar(height - zoomedHeight));
+ SkPaint paint;
+ // Clear the background behind our zoomed in view
+ paint.setColor(SK_ColorWHITE);
+ canvas->drawRect(dest, paint);
+ canvas->drawBitmapRect(bitmap, &src, dest);
+ paint.setColor(SK_ColorBLACK);
+ paint.setStyle(SkPaint::kStroke_Style);
+ // Draw a border around the pixel in the middle
+ SkRect originalPixel;
+ originalPixel.set(SkIntToScalar(fMouseX), SkIntToScalar(fMouseY), SkIntToScalar(fMouseX + 1), SkIntToScalar(fMouseY + 1));
+ SkMatrix matrix;
+ SkRect scalarSrc;
+ scalarSrc.set(src);
+ SkColor color = bitmap.getColor(fMouseX, fMouseY);
+ if (matrix.setRectToRect(scalarSrc, dest, SkMatrix::kFill_ScaleToFit)) {
+ SkRect pixel;
+ matrix.mapRect(&pixel, originalPixel);
+ // TODO Perhaps measure the values and make the outline white if it's "dark"
+ if (color == SK_ColorBLACK) {
+ paint.setColor(SK_ColorWHITE);
+ }
+ canvas->drawRect(pixel, paint);
+ }
+ paint.setColor(SK_ColorBLACK);
+ // Draw a border around the destination rectangle
+ canvas->drawRect(dest, paint);
+ paint.setStyle(SkPaint::kStrokeAndFill_Style);
+ // Identify the pixel and its color on screen
+ paint.setTypeface(fTypeface);
+ paint.setAntiAlias(true);
+ SkScalar lineHeight = paint.getFontMetrics(NULL);
+ SkString string;
+ string.appendf("(%i, %i)", fMouseX, fMouseY);
+ SkScalar left = dest.fLeft + SkIntToScalar(3);
+ SkScalar i = SK_Scalar1;
+ drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
+ // Alpha
+ i += SK_Scalar1;
+ string.reset();
+ string.appendf("A: %X", SkColorGetA(color));
+ drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
+ // Red
+ i += SK_Scalar1;
+ string.reset();
+ string.appendf("R: %X", SkColorGetR(color));
+ paint.setColor(SK_ColorRED);
+ drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
+ // Green
+ i += SK_Scalar1;
+ string.reset();
+ string.appendf("G: %X", SkColorGetG(color));
+ paint.setColor(SK_ColorGREEN);
+ drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
+ // Blue
+ i += SK_Scalar1;
+ string.reset();
+ string.appendf("B: %X", SkColorGetB(color));
+ paint.setColor(SK_ColorBLUE);
+ drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
+ canvas->restoreToCount(count);
+}
+
+void SampleWindow::onDraw(SkCanvas* canvas) {
+ if (fRepeatDrawing) {
+ this->inval(NULL);
+ }
+}
+
+#include "SkColorPriv.h"
+
+static void reverseRedAndBlue(const SkBitmap& bm) {
+ SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config);
+ uint8_t* p = (uint8_t*)bm.getPixels();
+ uint8_t* stop = p + bm.getSize();
+ while (p < stop) {
+ // swap red/blue (to go from ARGB(int) to RGBA(memory) and premultiply
+ unsigned scale = SkAlpha255To256(p[3]);
+ unsigned r = p[2];
+ unsigned b = p[0];
+ p[0] = SkAlphaMul(r, scale);
+ p[1] = SkAlphaMul(p[1], scale);
+ p[2] = SkAlphaMul(b, scale);
+ p += 4;
+ }
+}
+
+SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
+ if (kGPU_CanvasType != fCanvasType) {
+#ifdef SK_SUPPORT_GL
+ detachGL();
+#endif
+ }
+
+ switch (fCanvasType) {
+ case kRaster_CanvasType:
+ canvas = this->INHERITED::beforeChildren(canvas);
+ break;
+ case kPicture_CanvasType:
+ fPicture = new SkPicture;
+ canvas = fPicture->beginRecording(9999, 9999);
+ break;
+ case kGPU_CanvasType: {
+ if (make3DReady()) {
+ SkDevice* device = canvas->getDevice();
+ const SkBitmap& bitmap = device->accessBitmap(true);
+
+ GrRenderTarget* renderTarget;
+ renderTarget = fGrContext->createRenderTargetFrom3DApiState();
+ fGpuCanvas = new SkGpuCanvas(fGrContext, renderTarget);
+ renderTarget->unref();
+
+ device = fGpuCanvas->createDevice(SkBitmap::kARGB_8888_Config,
+ bitmap.width(), bitmap.height(),
+ false, false);
+ fGpuCanvas->setDevice(device)->unref();
+
+ fGpuCanvas->concat(canvas->getTotalMatrix());
+ canvas = fGpuCanvas;
+
+ } else {
+ canvas = this->INHERITED::beforeChildren(canvas);
+ }
+ break;
+ }
+ }
+
+ if (fUseClip) {
+ canvas->drawColor(0xFFFF88FF);
+ canvas->clipPath(fClipPath);
+ }
+
+ return canvas;
+}
+
+static void paint_rgn(const SkBitmap& bm, const SkIRect& r,
+ const SkRegion& rgn) {
+ SkCanvas canvas(bm);
+ SkRegion inval(rgn);
+
+ inval.translate(r.fLeft, r.fTop);
+ canvas.clipRegion(inval);
+ canvas.drawColor(0xFFFF8080);
+}
+
+void SampleWindow::afterChildren(SkCanvas* orig) {
+ if (fRequestGrabImage) {
+ fRequestGrabImage = false;
+
+ SkCanvas* canvas = fGpuCanvas ? fGpuCanvas : orig;
+ SkDevice* device = canvas->getDevice();
+ SkBitmap bmp;
+ if (device->accessBitmap(false).copyTo(&bmp, SkBitmap::kARGB_8888_Config)) {
+ static int gSampleGrabCounter;
+ SkString name;
+ name.printf("sample_grab_%d", gSampleGrabCounter++);
+ SkImageEncoder::EncodeFile(name.c_str(), bmp,
+ SkImageEncoder::kPNG_Type, 100);
+ }
+ }
+
+ switch (fCanvasType) {
+ case kRaster_CanvasType:
+ break;
+ case kPicture_CanvasType:
+ if (true) {
+ SkPicture* pict = new SkPicture(*fPicture);
+ fPicture->unref();
+ orig->drawPicture(*pict);
+ pict->unref();
+ } else if (true) {
+ SkDynamicMemoryWStream ostream;
+ fPicture->serialize(&ostream);
+ fPicture->unref();
+
+ SkMemoryStream istream(ostream.getStream(), ostream.getOffset());
+ SkPicture pict(&istream);
+ orig->drawPicture(pict);
+ } else {
+ fPicture->draw(orig);
+ fPicture->unref();
+ }
+ fPicture = NULL;
+ break;
+#ifdef SK_SUPPORT_GL
+ case kGPU_CanvasType:
+ if (fShowZoomer) {
+ this->showZoomer(fGpuCanvas);
+ }
+ delete fGpuCanvas;
+ fGpuCanvas = NULL;
+ presentGL();
+ break;
+#endif
+ }
+
+ // Do this after presentGL and other finishing, rather than in afterChild
+ if (fMeasureFPS && fMeasureFPS_Time) {
+ fMeasureFPS_Time = SkTime::GetMSecs() - fMeasureFPS_Time;
+ this->updateTitle();
+ postInvalDelay(this->getSinkID());
+ }
+
+ // if ((fScrollTestX | fScrollTestY) != 0)
+ if (false) {
+ const SkBitmap& bm = orig->getDevice()->accessBitmap(true);
+ int dx = fScrollTestX * 7;
+ int dy = fScrollTestY * 7;
+ SkIRect r;
+ SkRegion inval;
+
+ r.set(50, 50, 50+100, 50+100);
+ bm.scrollRect(&r, dx, dy, &inval);
+ paint_rgn(bm, r, inval);
+ }
+}
+
+void SampleWindow::beforeChild(SkView* child, SkCanvas* canvas) {
+ if (fScale) {
+ SkScalar scale = SK_Scalar1 * 7 / 10;
+ SkScalar cx = this->width() / 2;
+ SkScalar cy = this->height() / 2;
+ canvas->translate(cx, cy);
+ canvas->scale(scale, scale);
+ canvas->translate(-cx, -cy);
+ }
+ if (fRotate) {
+ SkScalar cx = this->width() / 2;
+ SkScalar cy = this->height() / 2;
+ canvas->translate(cx, cy);
+ canvas->rotate(SkIntToScalar(30));
+ canvas->translate(-cx, -cy);
+ }
+
+ canvas->setDrawFilter(new FlagsDrawFilter(fLCDState, fAAState,
+ fFilterState, fHintingState))->unref();
+
+ if (fMeasureFPS) {
+ fMeasureFPS_Time = 0; // 0 means the child is not aware of repeat-draw
+ if (SampleView::SetRepeatDraw(child, FPS_REPEAT_COUNT)) {
+ fMeasureFPS_Time = SkTime::GetMSecs();
+ }
+ } else {
+ (void)SampleView::SetRepeatDraw(child, 1);
+ }
+ (void)SampleView::SetUsePipe(child, fUsePipe);
+}
+
+void SampleWindow::afterChild(SkView* child, SkCanvas* canvas) {
+ canvas->setDrawFilter(NULL);
+}
+
+static SkBitmap::Config gConfigCycle[] = {
+ SkBitmap::kNo_Config, // none -> none
+ SkBitmap::kNo_Config, // a1 -> none
+ SkBitmap::kNo_Config, // a8 -> none
+ SkBitmap::kNo_Config, // index8 -> none
+ SkBitmap::kARGB_4444_Config, // 565 -> 4444
+ SkBitmap::kARGB_8888_Config, // 4444 -> 8888
+ SkBitmap::kRGB_565_Config // 8888 -> 565
+};
+
+static SkBitmap::Config cycle_configs(SkBitmap::Config c) {
+ return gConfigCycle[c];
+}
+
+void SampleWindow::changeZoomLevel(int delta) {
+ fZoomLevel += delta;
+ if (fZoomLevel > 0) {
+ fZoomLevel = SkMin32(fZoomLevel, MAX_ZOOM_LEVEL);
+ fZoomScale = SkIntToScalar(fZoomLevel + 1);
+ } else if (fZoomLevel < 0) {
+ fZoomLevel = SkMax32(fZoomLevel, MIN_ZOOM_LEVEL);
+ fZoomScale = SK_Scalar1 / (1 - fZoomLevel);
+ } else {
+ fZoomScale = SK_Scalar1;
+ }
+
+ this->inval(NULL);
+}
+
+bool SampleWindow::nextSample() {
+ fCurrIndex = (fCurrIndex + 1) % fSamples.count();
+ this->loadView(fSamples[fCurrIndex]());
+ return true;
+}
+
+bool SampleWindow::onEvent(const SkEvent& evt) {
+ if (evt.isType(ANIMATING_EVENTTYPE)) {
+ if (fAnimating) {
+ this->nextSample();
+ this->postAnimatingEvent();
+ }
+ return true;
+ }
+ if (evt.isType("set-curr-index")) {
+ fCurrIndex = evt.getFast32() % fSamples.count();
+ this->loadView(fSamples[fCurrIndex]());
+ return true;
+ }
+ if (isInvalEvent(evt)) {
+ this->inval(NULL);
+ return true;
+ }
+ return this->INHERITED::onEvent(evt);
+}
+
+bool SampleWindow::onQuery(SkEvent* query) {
+ if (query->isType("get-slide-count")) {
+ query->setFast32(fSamples.count());
+ return true;
+ }
+ if (query->isType("get-slide-title")) {
+ SkView* view = fSamples[query->getFast32()]();
+ SkEvent evt(gTitleEvtName);
+ if (view->doQuery(&evt)) {
+ query->setString("title", evt.findString(gTitleEvtName));
+ }
+ SkSafeUnref(view);
+ return true;
+ }
+ if (query->isType("use-fast-text")) {
+ SkEvent evt(gFastTextEvtName);
+ return curr_view(this)->doQuery(&evt);
+ }
+ return this->INHERITED::onQuery(query);
+}
+
+static void cleanup_for_filename(SkString* name) {
+ char* str = name->writable_str();
+ for (size_t i = 0; i < name->size(); i++) {
+ switch (str[i]) {
+ case ':': str[i] = '-'; break;
+ case '/': str[i] = '-'; break;
+ case ' ': str[i] = '_'; break;
+ default: break;
+ }
+ }
+}
+
+bool SampleWindow::onHandleChar(SkUnichar uni) {
+ {
+ SkView* view = curr_view(this);
+ if (view) {
+ SkEvent evt(gCharEvtName);
+ evt.setFast32(uni);
+ if (view->doQuery(&evt)) {
+ return true;
+ }
+ }
+ }
+
+ int dx = 0xFF;
+ int dy = 0xFF;
+
+ switch (uni) {
+ case '5': dx = 0; dy = 0; break;
+ case '8': dx = 0; dy = -1; break;
+ case '6': dx = 1; dy = 0; break;
+ case '2': dx = 0; dy = 1; break;
+ case '4': dx = -1; dy = 0; break;
+ case '7': dx = -1; dy = -1; break;
+ case '9': dx = 1; dy = -1; break;
+ case '3': dx = 1; dy = 1; break;
+ case '1': dx = -1; dy = 1; break;
+
+ default:
+ break;
+ }
+
+ if (0xFF != dx && 0xFF != dy) {
+ if ((dx | dy) == 0) {
+ fScrollTestX = fScrollTestY = 0;
+ } else {
+ fScrollTestX += dx;
+ fScrollTestY += dy;
+ }
+ this->inval(NULL);
+ return true;
+ }
+
+ switch (uni) {
+ case 'a':
+ fAnimating = !fAnimating;
+ this->postAnimatingEvent();
+ this->updateTitle();
+ return true;
+ case 'b':
+ fAAState = cycle_tristate(fAAState);
+ this->updateTitle();
+ this->inval(NULL);
+ break;
+ case 'c':
+ fUseClip = !fUseClip;
+ this->inval(NULL);
+ this->updateTitle();
+ return true;
+ case 'd':
+ SkGraphics::SetFontCacheUsed(0);
+ return true;
+ case 'f':
+ fMeasureFPS = !fMeasureFPS;
+ this->inval(NULL);
+ break;
+ case 'g':
+ fRequestGrabImage = true;
+ this->inval(NULL);
+ break;
+ case 'h':
+ fHintingState = cycle_tristate(fHintingState);
+ this->updateTitle();
+ this->inval(NULL);
+ break;
+ case 'i':
+ this->zoomIn();
+ break;
+ case 'l':
+ fLCDState = cycle_tristate(fLCDState);
+ this->updateTitle();
+ this->inval(NULL);
+ break;
+ case 'n':
+ fFilterState = cycle_tristate(fFilterState);
+ this->updateTitle();
+ this->inval(NULL);
+ break;
+ case 'o':
+ this->zoomOut();
+ break;
+ case 'p':
+ fUsePipe = !fUsePipe;
+ this->updateTitle();
+ this->inval(NULL);
+ break;
+ case 'r':
+ fRotate = !fRotate;
+ this->inval(NULL);
+ this->updateTitle();
+ return true;
+ case 's':
+ fScale = !fScale;
+ this->inval(NULL);
+ this->updateTitle();
+ return true;
+ case 'x':
+ fFlipAxis ^= kFlipAxis_X;
+ this->updateTitle();
+ this->inval(NULL);
+ break;
+ case 'y':
+ fFlipAxis ^= kFlipAxis_Y;
+ this->updateTitle();
+ this->inval(NULL);
+ break;
+ case 'z':
+ this->toggleZoomer();
+ break;
+ default:
+ break;
+ }
+
+ return this->INHERITED::onHandleChar(uni);
+}
+
+#include "SkDumpCanvas.h"
+
+bool SampleWindow::onHandleKey(SkKey key) {
+ {
+ SkView* view = curr_view(this);
+ if (view) {
+ SkEvent evt(gKeyEvtName);
+ evt.setFast32(key);
+ if (view->doQuery(&evt)) {
+ return true;
+ }
+ }
+ }
+
+ switch (key) {
+ case kRight_SkKey:
+ if (this->nextSample()) {
+ return true;
+ }
+ break;
+ case kLeft_SkKey:
+ fCanvasType = cycle_canvastype(fCanvasType);
+ this->updateTitle();
+ this->inval(NULL);
+ return true;
+ case kUp_SkKey:
+ if (USE_ARROWS_FOR_ZOOM) {
+ this->changeZoomLevel(1);
+ } else {
+ fNClip = !fNClip;
+ this->inval(NULL);
+ }
+ this->updateTitle();
+ return true;
+ case kDown_SkKey:
+ if (USE_ARROWS_FOR_ZOOM) {
+ this->changeZoomLevel(-1);
+ } else {
+ this->setConfig(cycle_configs(this->getBitmap().config()));
+ }
+ this->updateTitle();
+ return true;
+ case kOK_SkKey:
+ if (false) {
+ SkDebugfDumper dumper;
+ SkDumpCanvas dc(&dumper);
+ this->draw(&dc);
+ } else {
+ fRepeatDrawing = !fRepeatDrawing;
+ if (fRepeatDrawing) {
+ this->inval(NULL);
+ }
+ }
+ return true;
+ case kBack_SkKey:
+ this->loadView(NULL);
+ return true;
+ default:
+ break;
+ }
+ return this->INHERITED::onHandleKey(key);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static const char gGestureClickType[] = "GestureClickType";
+
+bool SampleWindow::onDispatchClick(int x, int y, Click::State state) {
+ if (Click::kMoved_State == state) {
+ updatePointer(x, y);
+ }
+ int w = SkScalarRound(this->width());
+ int h = SkScalarRound(this->height());
+
+ // check for the resize-box
+ if (w - x < 16 && h - y < 16) {
+ return false; // let the OS handle the click
+ } else {
+ return this->INHERITED::onDispatchClick(x, y, state);
+ }
+}
+
+class GestureClick : public SkView::Click {
+public:
+ GestureClick(SkView* target) : SkView::Click(target) {
+ this->setType(gGestureClickType);
+ }
+
+ static bool IsGesture(Click* click) {
+ return click->isType(gGestureClickType);
+ }
+};
+
+SkView::Click* SampleWindow::onFindClickHandler(SkScalar x, SkScalar y) {
+ return new GestureClick(this);
+}
+
+bool SampleWindow::onClick(Click* click) {
+ if (GestureClick::IsGesture(click)) {
+ float x = SkScalarToFloat(click->fCurr.fX);
+ float y = SkScalarToFloat(click->fCurr.fY);
+ switch (click->fState) {
+ case SkView::Click::kDown_State:
+ fGesture.touchBegin(click, x, y);
+ break;
+ case SkView::Click::kMoved_State:
+ fGesture.touchMoved(click, x, y);
+ this->inval(NULL);
+ break;
+ case SkView::Click::kUp_State:
+ fGesture.touchEnd(click);
+ this->inval(NULL);
+ break;
+ }
+ return true;
+ }
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SampleWindow::loadView(SkView* view) {
+ SkView::F2BIter iter(this);
+ SkView* prev = iter.next();
+ if (prev) {
+ prev->detachFromParent();
+ }
+
+ if (NULL == view) {
+ view = create_overview(fSamples.count(), fSamples.begin());
+ }
+ view->setVisibleP(true);
+ view->setClipToBounds(false);
+ this->attachChildToFront(view)->unref();
+ view->setSize(this->width(), this->height());
+
+ this->updateTitle();
+}
+
+static const char* gConfigNames[] = {
+ "unknown config",
+ "A1",
+ "A8",
+ "Index8",
+ "565",
+ "4444",
+ "8888"
+};
+
+static const char* configToString(SkBitmap::Config c) {
+ return gConfigNames[c];
+}
+
+static const char* gCanvasTypePrefix[] = {
+ "raster: ",
+ "picture: ",
+ "opengl: "
+};
+
+static const char* trystate_str(SkTriState state,
+ const char trueStr[], const char falseStr[]) {
+ if (kTrue_SkTriState == state) {
+ return trueStr;
+ } else if (kFalse_SkTriState == state) {
+ return falseStr;
+ }
+ return NULL;
+}
+
+void SampleWindow::updateTitle() {
+ SkString title;
+
+ SkView::F2BIter iter(this);
+ SkView* view = iter.next();
+ SkEvent evt(gTitleEvtName);
+ if (view->doQuery(&evt)) {
+ title.set(evt.findString(gTitleEvtName));
+ }
+ if (title.size() == 0) {
+ title.set("<unknown>");
+ }
+
+ title.prepend(gCanvasTypePrefix[fCanvasType]);
+
+ title.prepend(" ");
+ title.prepend(configToString(this->getBitmap().config()));
+
+ if (fAnimating) {
+ title.prepend("<A> ");
+ }
+ if (fScale) {
+ title.prepend("<S> ");
+ }
+ if (fRotate) {
+ title.prepend("<R> ");
+ }
+ if (fNClip) {
+ title.prepend("<C> ");
+ }
+
+ title.prepend(trystate_str(fLCDState, "LCD ", "lcd "));
+ title.prepend(trystate_str(fAAState, "AA ", "aa "));
+ title.prepend(trystate_str(fFilterState, "H ", "h "));
+ title.prepend(fFlipAxis & kFlipAxis_X ? "X " : NULL);
+ title.prepend(fFlipAxis & kFlipAxis_Y ? "Y " : NULL);
+
+ if (fZoomLevel) {
+ title.prependf("{%d} ", fZoomLevel);
+ }
+
+ if (fMeasureFPS) {
+ title.appendf(" %6.1f ms", fMeasureFPS_Time / (float)FPS_REPEAT_MULTIPLIER);
+ }
+ if (fUsePipe && SampleView::IsSampleView(view)) {
+ title.prepend("<P> ");
+ }
+ if (SampleView::IsSampleView(view)) {
+ title.prepend("! ");
+ }
+
+ this->setTitle(title.c_str());
+}
+
+void SampleWindow::onSizeChange() {
+ this->INHERITED::onSizeChange();
+
+ SkView::F2BIter iter(this);
+ SkView* view = iter.next();
+ view->setSize(this->width(), this->height());
+
+ // rebuild our clippath
+ {
+ const SkScalar W = this->width();
+ const SkScalar H = this->height();
+
+ fClipPath.reset();
+#if 0
+ for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) {
+ SkRect r;
+ r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30));
+ for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0))
+ fClipPath.addRect(r);
+ }
+#else
+ SkRect r;
+ r.set(0, 0, W, H);
+ fClipPath.addRect(r, SkPath::kCCW_Direction);
+ r.set(W/4, H/4, W*3/4, H*3/4);
+ fClipPath.addRect(r, SkPath::kCW_Direction);
+#endif
+ }
+
+ this->updateTitle(); // to refresh our config
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static const char is_sample_view_tag[] = "sample-is-sample-view";
+static const char repeat_count_tag[] = "sample-set-repeat-count";
+static const char set_use_pipe_tag[] = "sample-set-use-pipe";
+
+bool SampleView::IsSampleView(SkView* view) {
+ SkEvent evt(is_sample_view_tag);
+ return view->doQuery(&evt);
+}
+
+bool SampleView::SetRepeatDraw(SkView* view, int count) {
+ SkEvent evt(repeat_count_tag);
+ evt.setFast32(count);
+ return view->doEvent(evt);
+}
+
+bool SampleView::SetUsePipe(SkView* view, bool pred) {
+ SkEvent evt(set_use_pipe_tag);
+ evt.setFast32(pred);
+ return view->doEvent(evt);
+}
+
+bool SampleView::onEvent(const SkEvent& evt) {
+ if (evt.isType(repeat_count_tag)) {
+ fRepeatCount = evt.getFast32();
+ return true;
+ }
+ if (evt.isType(set_use_pipe_tag)) {
+ fUsePipe = !!evt.getFast32();
+ return true;
+ }
+ return this->INHERITED::onEvent(evt);
+}
+
+bool SampleView::onQuery(SkEvent* evt) {
+ if (evt->isType(is_sample_view_tag)) {
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+}
+
+#ifdef TEST_GPIPE
+ #include "SkGPipe.h"
+
+class SimplePC : public SkGPipeController {
+public:
+ SimplePC(SkCanvas* target);
+ ~SimplePC();
+
+ virtual void* requestBlock(size_t minRequest, size_t* actual);
+ virtual void notifyWritten(size_t bytes);
+
+private:
+ SkGPipeReader fReader;
+ void* fBlock;
+ size_t fBlockSize;
+ size_t fBytesWritten;
+ int fAtomsWritten;
+ SkGPipeReader::Status fStatus;
+
+ size_t fTotalWritten;
+};
+
+SimplePC::SimplePC(SkCanvas* target) : fReader(target) {
+ fBlock = NULL;
+ fBlockSize = fBytesWritten = 0;
+ fStatus = SkGPipeReader::kDone_Status;
+ fTotalWritten = 0;
+ fAtomsWritten = 0;
+}
+
+SimplePC::~SimplePC() {
+// SkASSERT(SkGPipeReader::kDone_Status == fStatus);
+ sk_free(fBlock);
+
+ if (fTotalWritten) {
+ SkDebugf("--- %d bytes %d atoms, status %d\n", fTotalWritten,
+ fAtomsWritten, fStatus);
+ }
+}
+
+void* SimplePC::requestBlock(size_t minRequest, size_t* actual) {
+ sk_free(fBlock);
+
+ fBlockSize = minRequest * 4;
+ fBlock = sk_malloc_throw(fBlockSize);
+ fBytesWritten = 0;
+ *actual = fBlockSize;
+ return fBlock;
+}
+
+void SimplePC::notifyWritten(size_t bytes) {
+ SkASSERT(fBytesWritten + bytes <= fBlockSize);
+
+#ifdef PIPE_FILE
+ //File is open in append mode
+ FILE* f = fopen(FILE_PATH, "ab");
+ SkASSERT(f != NULL);
+ fwrite((const char*)fBlock + fBytesWritten, 1, bytes, f);
+ fclose(f);
+#endif
+
+ fStatus = fReader.playback((const char*)fBlock + fBytesWritten, bytes);
+ SkASSERT(SkGPipeReader::kError_Status != fStatus);
+ fBytesWritten += bytes;
+ fTotalWritten += bytes;
+
+ fAtomsWritten += 1;
+}
+
+#endif
+
+
+void SampleView::onDraw(SkCanvas* canvas) {
+#ifdef TEST_GPIPE
+ SimplePC controller(canvas);
+ SkGPipeWriter writer;
+ if (fUsePipe) {
+ uint32_t flags = SkGPipeWriter::kCrossProcess_Flag;
+// flags = 0;
+ canvas = writer.startRecording(&controller, flags);
+ }
+#endif
+
+ this->onDrawBackground(canvas);
+
+ for (int i = 0; i < fRepeatCount; i++) {
+ SkAutoCanvasRestore acr(canvas, true);
+ this->onDrawContent(canvas);
+ }
+}
+
+void SampleView::onDrawBackground(SkCanvas* canvas) {
+ canvas->drawColor(fBGColor);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename T> void SkTBSort(T array[], int count) {
+ for (int i = 1; i < count - 1; i++) {
+ bool didSwap = false;
+ for (int j = count - 1; j > i; --j) {
+ if (array[j] < array[j-1]) {
+ T tmp(array[j-1]);
+ array[j-1] = array[j];
+ array[j] = tmp;
+ didSwap = true;
+ }
+ }
+ if (!didSwap) {
+ break;
+ }
+ }
+
+ for (int k = 0; k < count - 1; k++) {
+ SkASSERT(!(array[k+1] < array[k]));
+ }
+}
+
+#include "SkRandom.h"
+
+static void rand_rect(SkIRect* rect, SkRandom& rand) {
+ int bits = 8;
+ int shift = 32 - bits;
+ rect->set(rand.nextU() >> shift, rand.nextU() >> shift,
+ rand.nextU() >> shift, rand.nextU() >> shift);
+ rect->sort();
+}
+
+static void dumpRect(const SkIRect& r) {
+ SkDebugf(" { %d, %d, %d, %d },\n",
+ r.fLeft, r.fTop,
+ r.fRight, r.fBottom);
+}
+
+static void test_rects(const SkIRect rect[], int count) {
+ SkRegion rgn0, rgn1;
+
+ for (int i = 0; i < count; i++) {
+ rgn0.op(rect[i], SkRegion::kUnion_Op);
+ // dumpRect(rect[i]);
+ }
+ rgn1.setRects(rect, count);
+
+ if (rgn0 != rgn1) {
+ SkDebugf("\n");
+ for (int i = 0; i < count; i++) {
+ dumpRect(rect[i]);
+ }
+ SkDebugf("\n");
+ }
+}
+
+static void test() {
+ size_t i;
+
+ const SkIRect r0[] = {
+ { 0, 0, 1, 1 },
+ { 2, 2, 3, 3 },
+ };
+ const SkIRect r1[] = {
+ { 0, 0, 1, 3 },
+ { 1, 1, 2, 2 },
+ { 2, 0, 3, 3 },
+ };
+ const SkIRect r2[] = {
+ { 0, 0, 1, 2 },
+ { 2, 1, 3, 3 },
+ { 4, 0, 5, 1 },
+ { 6, 0, 7, 4 },
+ };
+
+ static const struct {
+ const SkIRect* fRects;
+ int fCount;
+ } gRecs[] = {
+ { r0, SK_ARRAY_COUNT(r0) },
+ { r1, SK_ARRAY_COUNT(r1) },
+ { r2, SK_ARRAY_COUNT(r2) },
+ };
+
+ for (i = 0; i < SK_ARRAY_COUNT(gRecs); i++) {
+ test_rects(gRecs[i].fRects, gRecs[i].fCount);
+ }
+
+ SkRandom rand;
+ for (i = 0; i < 10000; i++) {
+ SkRegion rgn0, rgn1;
+
+ const int N = 8;
+ SkIRect rect[N];
+ for (int j = 0; j < N; j++) {
+ rand_rect(&rect[j], rand);
+ }
+ test_rects(rect, N);
+ }
+}
+
+SkOSWindow* create_sk_window(void* hwnd) {
+// test();
+ return new SampleWindow(hwnd);
+}
+
+void get_preferred_size(int* x, int* y, int* width, int* height) {
+ *x = 10;
+ *y = 50;
+ *width = 640;
+ *height = 480;
+}
+
+void application_init() {
+// setenv("ANDROID_ROOT", "../../../data", 0);
+#ifdef SK_BUILD_FOR_MAC
+ setenv("ANDROID_ROOT", "/android/device/data", 0);
+#endif
+ SkGraphics::Init();
+ SkEvent::Init();
+}
+
+void application_term() {
+ SkEvent::Term();
+ SkGraphics::Term();
+}
diff --git a/samplecode/SampleArc.cpp b/samplecode/SampleArc.cpp
new file mode 100644
index 0000000..8e3ad88
--- /dev/null
+++ b/samplecode/SampleArc.cpp
@@ -0,0 +1,184 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkComposeShader.h"
+#include "Sk1DPathEffect.h"
+#include "SkCornerPathEffect.h"
+#include "SkPathMeasure.h"
+#include "SkRandom.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkLayerRasterizer.h"
+
+#include "SkParsePath.h"
+static void testparse() {
+ SkRect r;
+ r.set(0, 0, SkFloatToScalar(10), SkFloatToScalar(10.5));
+ SkPath p, p2;
+ SkString str, str2;
+
+ p.addRect(r);
+ SkParsePath::ToSVGString(p, &str);
+ SkParsePath::FromSVGString(str.c_str(), &p2);
+ SkParsePath::ToSVGString(p2, &str2);
+}
+
+class ArcsView : public SampleView {
+public:
+ ArcsView() {
+ testparse();
+ fSweep = SkIntToScalar(100);
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Arcs");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ static void drawRectWithLines(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
+ canvas->drawRect(r, p);
+ canvas->drawLine(r.fLeft, r.fTop, r.fRight, r.fBottom, p);
+ canvas->drawLine(r.fLeft, r.fBottom, r.fRight, r.fTop, p);
+ canvas->drawLine(r.fLeft, r.centerY(), r.fRight, r.centerY(), p);
+ canvas->drawLine(r.centerX(), r.fTop, r.centerX(), r.fBottom, p);
+ }
+
+ static void draw_label(SkCanvas* canvas, const SkRect& rect,
+ int start, int sweep) {
+ SkPaint paint;
+
+ paint.setAntiAlias(true);
+ paint.setTextAlign(SkPaint::kCenter_Align);
+
+ SkString str;
+
+ str.appendS32(start);
+ str.append(", ");
+ str.appendS32(sweep);
+ canvas->drawText(str.c_str(), str.size(), rect.centerX(),
+ rect.fBottom + paint.getTextSize() * 5/4, paint);
+ }
+
+ static void drawArcs(SkCanvas* canvas) {
+ SkPaint paint;
+ SkRect r;
+ SkScalar w = SkIntToScalar(75);
+ SkScalar h = SkIntToScalar(50);
+
+ r.set(0, 0, w, h);
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+
+ canvas->save();
+ canvas->translate(SkIntToScalar(10), SkIntToScalar(300));
+
+ paint.setStrokeWidth(SkIntToScalar(1));
+
+ static const int gAngles[] = {
+ 0, 360,
+ 0, 45,
+ 0, -45,
+ 720, 135,
+ -90, 269,
+ -90, 270,
+ -90, 271,
+ -180, -270,
+ 225, 90
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gAngles); i += 2) {
+ paint.setColor(SK_ColorBLACK);
+ drawRectWithLines(canvas, r, paint);
+
+ paint.setColor(SK_ColorRED);
+ canvas->drawArc(r, SkIntToScalar(gAngles[i]),
+ SkIntToScalar(gAngles[i+1]), false, paint);
+
+ draw_label(canvas, r, gAngles[i], gAngles[i+1]);
+
+ canvas->translate(w * 8 / 7, 0);
+ }
+
+ canvas->restore();
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ fSweep = SampleCode::GetAnimScalar(SkIntToScalar(360)/24,
+ SkIntToScalar(360));
+// fSweep = SkFloatToScalar(359.99f);
+
+ SkRect r;
+ SkPaint paint;
+
+ paint.setAntiAlias(true);
+ paint.setStrokeWidth(SkIntToScalar(2));
+ paint.setStyle(SkPaint::kStroke_Style);
+
+ r.set(0, 0, SkIntToScalar(200), SkIntToScalar(200));
+ r.offset(SkIntToScalar(20), SkIntToScalar(20));
+
+ if (false) {
+ const SkScalar d = SkIntToScalar(3);
+ const SkScalar rad[] = { d, d, d, d, d, d, d, d };
+ SkPath path;
+ path.addRoundRect(r, rad);
+ canvas->drawPath(path, paint);
+ return;
+ }
+
+ drawRectWithLines(canvas, r, paint);
+
+ // printf("----- sweep %g %X\n", SkScalarToFloat(fSweep), SkDegreesToRadians(fSweep));
+
+
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(0x800000FF);
+ canvas->drawArc(r, 0, fSweep, true, paint);
+
+ paint.setColor(0x800FF000);
+ canvas->drawArc(r, 0, fSweep, false, paint);
+
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setColor(SK_ColorRED);
+ canvas->drawArc(r, 0, fSweep, true, paint);
+
+ paint.setStrokeWidth(0);
+ paint.setColor(SK_ColorBLUE);
+ canvas->drawArc(r, 0, fSweep, false, paint);
+
+ drawArcs(canvas);
+ this->inval(NULL);
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ // fSweep += SK_Scalar1;
+ this->inval(NULL);
+ return this->INHERITED::onFindClickHandler(x, y);
+ }
+
+ virtual bool onClick(Click* click) {
+ return this->INHERITED::onClick(click);
+ }
+
+private:
+ SkScalar fSweep;
+
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new ArcsView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleAvoid.cpp b/samplecode/SampleAvoid.cpp
new file mode 100644
index 0000000..868a67c
--- /dev/null
+++ b/samplecode/SampleAvoid.cpp
@@ -0,0 +1,99 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkAvoidXfermode.h"
+
+///////////////////////////////////////////////////////////////////////////////
+
+class AvoidView : public SampleView {
+ SkShader* fShader;
+
+ enum {
+ W = 480,
+ H = 320
+ };
+public:
+ AvoidView() {
+ SkColor colors[] = { SK_ColorRED, SK_ColorYELLOW, SK_ColorGREEN, SK_ColorCYAN, SK_ColorBLUE };
+
+#if 0
+ SkPoint pts[] = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
+ fShader = SkGradientShader::CreateLinear(pts, colors, NULL,
+ SK_ARRAY_COUNT(colors),
+ SkShader::kMirror_TileMode);
+#else
+ SkPoint pts[] = { { SkIntToScalar(W)/2, SkIntToScalar(H)/2 } };
+ fShader = SkGradientShader::CreateRadial(pts[0], SkIntToScalar(H)/5,
+ colors, NULL,
+ SK_ARRAY_COUNT(colors),
+ SkShader::kMirror_TileMode);
+#endif
+ }
+
+ virtual ~AvoidView() {
+ fShader->unref();
+ }
+
+protected:
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "AvoidXfermode");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+ SkRect r = { 0, 0, SkIntToScalar(W), SkIntToScalar(H) };
+
+ canvas->translate(r.width() / 6, r.height() / 6);
+
+ paint.setShader(fShader);
+ canvas->drawRect(r, paint);
+
+ static const struct {
+ int fTolerance;
+ SkAvoidXfermode::Mode fMode;
+ float fDX, fDY;
+ } gData[] = {
+ { 16, SkAvoidXfermode::kAvoidColor_Mode, 0, 0 },
+ { 255-16, SkAvoidXfermode::kAvoidColor_Mode, 1, 0 },
+ { 16, SkAvoidXfermode::kTargetColor_Mode, 0, 1 },
+ { 255-16, SkAvoidXfermode::kTargetColor_Mode, 1, 1 },
+ };
+
+ paint.setShader(NULL);
+ paint.setColor(SK_ColorMAGENTA);
+
+ SkPaint frameP;
+ frameP.setStyle(SkPaint::kStroke_Style);
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gData); i++) {
+ SkAvoidXfermode mode(SK_ColorGREEN, gData[i].fTolerance,
+ gData[i].fMode);
+ paint.setXfermode(&mode);
+ int div = 3;
+ SkRect rr = { 0, 0, r.width()/div, r.height()/div };
+ rr.offset(r.width()/4 - rr.width()/2, r.height()/4 - rr.height()/2);
+ rr.offset(r.width() * gData[i].fDX/2, r.height() * gData[i].fDY/2);
+ canvas->drawRect(rr, paint);
+ paint.setXfermode(NULL);
+
+ canvas->drawRect(rr, frameP);
+ }
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() {
+ return new AvoidView;
+}
+
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleBigGradient.cpp b/samplecode/SampleBigGradient.cpp
new file mode 100644
index 0000000..5ebb516
--- /dev/null
+++ b/samplecode/SampleBigGradient.cpp
@@ -0,0 +1,43 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+
+static SkShader* make_grad(SkScalar w, SkScalar h) {
+ SkColor colors[] = { 0xFF000000, 0xFF333333 };
+ SkPoint pts[] = { { 0, 0 }, { w, h } };
+ return SkGradientShader::CreateLinear(pts, colors, NULL, 2,
+ SkShader::kClamp_TileMode);
+}
+
+class BigGradientView : public SampleView {
+public:
+ BigGradientView() {}
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "BigGradient");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkRect r;
+ r.set(0, 0, this->width(), this->height());
+ SkPaint p;
+ p.setShader(make_grad(this->width(), this->height()))->unref();
+ canvas->drawRect(r, p);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new BigGradientView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleBitmapRect.cpp b/samplecode/SampleBitmapRect.cpp
new file mode 100644
index 0000000..002b2b9
--- /dev/null
+++ b/samplecode/SampleBitmapRect.cpp
@@ -0,0 +1,92 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+
+#include "SkOSFile.h"
+#include "SkStream.h"
+
+static SkBitmap make_bitmap() {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, 64, 64);
+ bm.allocPixels();
+ SkCanvas canvas(bm);
+ canvas.drawColor(SK_ColorRED);
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ const SkPoint pts[] = { { 0, 0 }, { 64, 64 } };
+ const SkColor colors[] = { SK_ColorWHITE, SK_ColorBLUE };
+ paint.setShader(SkGradientShader::CreateLinear(pts, colors, NULL, 2,
+ SkShader::kClamp_TileMode))->unref();
+ canvas.drawCircle(32, 32, 32, paint);
+ return bm;
+}
+
+class BitmapRectView : public SampleView {
+public:
+ SkBitmap fBitmap;
+
+ BitmapRectView() {
+ fBitmap = make_bitmap();
+ this->setBGColor(SK_ColorGRAY);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "BitmapRect");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ const SkIRect src[] = {
+ { 0, 0, 32, 32 },
+ { 0, 0, 80, 80 },
+ { 32, 32, 96, 96 },
+ { -32, -32, 32, 32, }
+ };
+
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setColor(SK_ColorGREEN);
+
+ SkRect dstR = { 0, 200, 128, 380 };
+
+ canvas->translate(16, 40);
+ for (size_t i = 0; i < SK_ARRAY_COUNT(src); i++) {
+ SkRect srcR;
+ srcR.set(src[i]);
+
+ canvas->drawBitmap(fBitmap, 0, 0, &paint);
+ canvas->drawBitmapRect(fBitmap, &src[i], dstR, &paint);
+
+ canvas->drawRect(dstR, paint);
+ canvas->drawRect(srcR, paint);
+
+ canvas->translate(160, 0);
+ }
+ }
+
+private:
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new BitmapRectView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleBlur.cpp b/samplecode/SampleBlur.cpp
new file mode 100644
index 0000000..d2ea2b0
--- /dev/null
+++ b/samplecode/SampleBlur.cpp
@@ -0,0 +1,131 @@
+#include "SampleCode.h"
+#include "SkBlurMaskFilter.h"
+#include "SkColorPriv.h"
+#include "SkGradientShader.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkUtils.h"
+
+static SkBitmap make_bitmap() {
+ SkBitmap bm;
+ SkColorTable* ctable = new SkColorTable(256);
+
+ SkPMColor* c = ctable->lockColors();
+ for (int i = 0; i < 256; i++) {
+ c[i] = SkPackARGB32(255 - i, 0, 0, 0);
+ }
+ ctable->unlockColors(true);
+ bm.setConfig(SkBitmap::kIndex8_Config, 256, 256);
+ bm.allocPixels(ctable);
+ ctable->unref();
+
+ bm.lockPixels();
+ const float cx = bm.width() * 0.5f;
+ const float cy = bm.height() * 0.5f;
+ for (int y = 0; y < bm.height(); y++) {
+ float dy = y - cy;
+ dy *= dy;
+ uint8_t* p = bm.getAddr8(0, y);
+ for (int x = 0; x < 256; x++) {
+ float dx = x - cx;
+ dx *= dx;
+ float d = (dx + dy) / (cx/2);
+ int id = (int)d;
+ if (id > 255) {
+ id = 255;
+ }
+ p[x] = id;
+ }
+ }
+ bm.unlockPixels();
+ return bm;
+}
+
+class BlurView : public SkView {
+ SkBitmap fBM;
+public:
+ BlurView() {
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Blur");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(0xFFDDDDDD);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ drawBG(canvas);
+
+ SkBlurMaskFilter::BlurStyle NONE = SkBlurMaskFilter::BlurStyle(-999);
+ static const struct {
+ SkBlurMaskFilter::BlurStyle fStyle;
+ int fCx, fCy;
+ } gRecs[] = {
+ { NONE, 0, 0 },
+ { SkBlurMaskFilter::kInner_BlurStyle, -1, 0 },
+ { SkBlurMaskFilter::kNormal_BlurStyle, 0, 1 },
+ { SkBlurMaskFilter::kSolid_BlurStyle, 0, -1 },
+ { SkBlurMaskFilter::kOuter_BlurStyle, 1, 0 },
+ };
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setTextSize(25);
+ canvas->translate(-40, 0);
+
+ SkBlurMaskFilter::BlurFlags flags = SkBlurMaskFilter::kNone_BlurFlag;
+ for (int j = 0; j < 2; j++) {
+ canvas->save();
+ paint.setColor(SK_ColorBLUE);
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRecs); i++) {
+ if (gRecs[i].fStyle != NONE) {
+ SkMaskFilter* mf = SkBlurMaskFilter::Create(20,
+ gRecs[i].fStyle,
+ flags);
+ paint.setMaskFilter(mf)->unref();
+ } else {
+ paint.setMaskFilter(NULL);
+ }
+ canvas->drawCircle(200 + gRecs[i].fCx*100.f,
+ 200 + gRecs[i].fCy*100.f, 50, paint);
+ }
+ // draw text
+ {
+ SkMaskFilter* mf = SkBlurMaskFilter::Create(4,
+ SkBlurMaskFilter::kNormal_BlurStyle,
+ flags);
+ paint.setMaskFilter(mf)->unref();
+ SkScalar x = SkIntToScalar(70);
+ SkScalar y = SkIntToScalar(400);
+ paint.setColor(SK_ColorBLACK);
+ canvas->drawText("Hamburgefons Style", 18, x, y, paint);
+ canvas->drawText("Hamburgefons Style", 18, x, y + SkIntToScalar(50), paint);
+ paint.setMaskFilter(NULL);
+ paint.setColor(SK_ColorWHITE);
+ x -= SkIntToScalar(2);
+ y -= SkIntToScalar(2);
+ canvas->drawText("Hamburgefons Style", 18, x, y, paint);
+ }
+ canvas->restore();
+ flags = SkBlurMaskFilter::kHighQuality_BlurFlag;
+ canvas->translate(350, 0);
+ }
+ }
+
+private:
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new BlurView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleBox.cpp b/samplecode/SampleBox.cpp
new file mode 100644
index 0000000..d445df7
--- /dev/null
+++ b/samplecode/SampleBox.cpp
@@ -0,0 +1,48 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+
+class SimpleView : public SampleView {
+public:
+ SimpleView() {
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Box Gradient");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkScalarHalf(SkIntToScalar(3)));
+ paint.setStyle(SkPaint::kFill_Style);
+
+ SkRect r;
+ SkScalar x,y;
+ x = 10;
+ y = 10;
+
+ r.set(x, y, x + SkIntToScalar(100), y + SkIntToScalar(100));
+ for (int i = 0; i < 256; ++i) {
+ canvas->translate(1, 1);
+ paint.setColor(0xFF000000 + i * 0x00010000);
+ canvas->drawRect(r, paint);
+ }
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new SimpleView; }
+static SkViewRegister reg(MyFactory); \ No newline at end of file
diff --git a/samplecode/SampleCamera.cpp b/samplecode/SampleCamera.cpp
new file mode 100644
index 0000000..2db3968
--- /dev/null
+++ b/samplecode/SampleCamera.cpp
@@ -0,0 +1,99 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkCamera.h"
+#include "SkEmbossMaskFilter.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkRandom.h"
+#include "SkImageDecoder.h"
+
+class CameraView : public SampleView {
+ SkTDArray<SkShader*> fShaders;
+ int fShaderIndex;
+ bool fFrontFace;
+public:
+ CameraView() {
+ fRX = fRY = fRZ = 0;
+ fShaderIndex = 0;
+ fFrontFace = false;
+
+ for (int i = 0;; i++) {
+ SkString str;
+ str.printf("/skimages/elephant%d.jpeg", i);
+ SkBitmap bm;
+ if (SkImageDecoder::DecodeFile(str.c_str(), &bm)) {
+ SkShader* s = SkShader::CreateBitmapShader(bm,
+ SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode);
+
+ SkRect src = { 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) };
+ SkRect dst = { -150, -150, 150, 150 };
+ SkMatrix matrix;
+ matrix.setRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
+ s->setLocalMatrix(matrix);
+ *fShaders.append() = s;
+ } else {
+ break;
+ }
+ }
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+ virtual ~CameraView() {
+ fShaders.unrefAll();
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt))
+ {
+ SampleCode::TitleR(evt, "Camera");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ canvas->translate(this->width()/2, this->height()/2);
+
+ Sk3DView view;
+ view.rotateX(fRX);
+ view.rotateY(fRY);
+ view.applyToCanvas(canvas);
+
+ SkPaint paint;
+ if (fShaders.count() > 0) {
+ bool frontFace = view.dotWithNormal(0, 0, SK_Scalar1) < 0;
+ if (frontFace != fFrontFace) {
+ fFrontFace = frontFace;
+ fShaderIndex = (fShaderIndex + 1) % fShaders.count();
+ }
+
+ paint.setAntiAlias(true);
+ paint.setShader(fShaders[fShaderIndex]);
+ SkRect r = { -150, -150, 150, 150 };
+ canvas->drawRoundRect(r, 30, 30, paint);
+ }
+
+ fRY += SampleCode::GetAnimSecondsDelta() * 90;
+ if (fRY >= SkIntToScalar(360)) {
+ fRY = 0;
+ }
+ this->inval(NULL);
+ }
+
+private:
+ SkScalar fRX, fRY, fRZ;
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new CameraView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleCircle.cpp b/samplecode/SampleCircle.cpp
new file mode 100644
index 0000000..2abc28d
--- /dev/null
+++ b/samplecode/SampleCircle.cpp
@@ -0,0 +1,126 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkPaint.h"
+
+// ensure that we don't accidentally screw up the bounds when the oval is
+// fractional, and the impl computes the center and radii, and uses them to
+// reconstruct the edges of the circle.
+// see bug# 1504910
+static void test_circlebounds(SkCanvas* canvas) {
+#ifdef SK_SCALAR_IS_FLOAT
+ SkRect r = { 1.39999998f, 1, 21.3999996f, 21 };
+ SkPath p;
+ p.addOval(r);
+ SkASSERT(r == p.getBounds());
+#endif
+}
+
+class CircleView : public SampleView {
+public:
+ static const SkScalar ANIM_DX;
+ static const SkScalar ANIM_DY;
+ static const SkScalar ANIM_RAD;
+ SkScalar fDX, fDY, fRAD;
+
+ CircleView() {
+ fDX = fDY = fRAD = 0;
+ fN = 3;
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Circles");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void circle(SkCanvas* canvas, int width, bool aa) {
+ SkPaint paint;
+
+ paint.setAntiAlias(aa);
+ if (width < 0) {
+ paint.setStyle(SkPaint::kFill_Style);
+ } else {
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkIntToScalar(width));
+ }
+ canvas->drawCircle(0, 0, SkIntToScalar(9) + fRAD, paint);
+ }
+
+ void drawSix(SkCanvas* canvas, SkScalar dx, SkScalar dy) {
+ for (int width = -1; width <= 1; width++) {
+ canvas->save();
+ circle(canvas, width, false);
+ canvas->translate(0, dy);
+ circle(canvas, width, true);
+ canvas->restore();
+ canvas->translate(dx, 0);
+ }
+ }
+
+ static void blowup(SkCanvas* canvas, const SkIRect& src, const SkRect& dst) {
+ SkDevice* device = canvas->getDevice();
+ const SkBitmap& bm = device->accessBitmap(false);
+ canvas->drawBitmapRect(bm, &src, dst, NULL);
+ }
+
+ static void make_poly(SkPath* path, int n) {
+ if (n <= 0) {
+ return;
+ }
+ path->incReserve(n + 1);
+ path->moveTo(SK_Scalar1, 0);
+ SkScalar step = SK_ScalarPI * 2 / n;
+ SkScalar angle = 0;
+ for (int i = 1; i < n; i++) {
+ angle += step;
+ SkScalar c, s = SkScalarSinCos(angle, &c);
+ path->lineTo(c, s);
+ }
+ path->close();
+ }
+
+ static void rotate(SkCanvas* canvas, SkScalar angle, SkScalar px, SkScalar py) {
+ canvas->translate(-px, -py);
+ canvas->rotate(angle);
+ canvas->translate(px, py);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+// canvas->drawCircle(250, 250, 220, paint);
+ SkMatrix matrix;
+ matrix.setScale(SkIntToScalar(100), SkIntToScalar(100));
+ matrix.postTranslate(SkIntToScalar(200), SkIntToScalar(200));
+ canvas->concat(matrix);
+ for (int n = 3; n < 20; n++) {
+ SkPath path;
+ make_poly(&path, n);
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->rotate(SkIntToScalar(10) * (n - 3));
+ canvas->translate(-SK_Scalar1, 0);
+ canvas->drawPath(path, paint);
+ }
+ }
+
+private:
+ int fN;
+ typedef SampleView INHERITED;
+};
+
+const SkScalar CircleView::ANIM_DX(SK_Scalar1 / 67);
+const SkScalar CircleView::ANIM_DY(SK_Scalar1 / 29);
+const SkScalar CircleView::ANIM_RAD(SK_Scalar1 / 19);
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new CircleView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleClamp.cpp b/samplecode/SampleClamp.cpp
new file mode 100644
index 0000000..88c1b91
--- /dev/null
+++ b/samplecode/SampleClamp.cpp
@@ -0,0 +1,61 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGraphics.h"
+#include "SkRandom.h"
+#include "SkGradientShader.h"
+#include "SkPicture.h"
+
+static SkShader* make_linear() {
+ SkPoint pts[] = { 0, 0, SK_Scalar1/500, SK_Scalar1/500 };
+ SkColor colors[] = { SK_ColorRED, SK_ColorBLUE };
+ return SkGradientShader::CreateLinear(pts, colors, NULL, 2,
+ SkShader::kClamp_TileMode);
+}
+
+class ClampView : public SampleView {
+ SkShader* fGrad;
+
+public:
+ ClampView() {
+ fGrad = make_linear();
+ }
+
+ virtual ~ClampView() {
+ fGrad->unref();
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Clamp");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setShader(fGrad);
+
+// canvas->translate(this->width()/2, this->height()/2);
+ canvas->translate(64, 64);
+ canvas->drawPaint(paint);
+
+ SkPicture pic;
+ SkCanvas* c = pic.beginRecording(100, 100, 0);
+ SkCanvas::LayerIter layerIterator(c, false);
+ layerIterator.next();
+ layerIterator.done();
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new ClampView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleCode.h b/samplecode/SampleCode.h
new file mode 100644
index 0000000..c42ee25
--- /dev/null
+++ b/samplecode/SampleCode.h
@@ -0,0 +1,81 @@
+#ifndef SampleCode_DEFINED
+#define SampleCode_DEFINED
+
+#include "SkColor.h"
+#include "SkEvent.h"
+#include "SkKey.h"
+#include "SkView.h"
+
+class SampleCode {
+public:
+ static bool KeyQ(const SkEvent&, SkKey* outKey);
+ static bool CharQ(const SkEvent&, SkUnichar* outUni);
+
+ static bool TitleQ(const SkEvent&);
+ static void TitleR(SkEvent*, const char title[]);
+
+ static bool PrefSizeQ(const SkEvent&);
+ static void PrefSizeR(SkEvent*, SkScalar width, SkScalar height);
+
+ static bool FastTextQ(const SkEvent&);
+
+ static SkMSec GetAnimTime();
+ static SkMSec GetAnimTimeDelta();
+ static SkScalar GetAnimSecondsDelta();
+ static SkScalar GetAnimScalar(SkScalar speedPerSec, SkScalar period = 0);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+typedef SkView* (*SkViewFactory)();
+
+class SkViewRegister : SkNoncopyable {
+public:
+ explicit SkViewRegister(SkViewFactory);
+
+ static const SkViewRegister* Head() { return gHead; }
+
+ SkViewRegister* next() const { return fChain; }
+ SkViewFactory factory() const { return fFact; }
+
+private:
+ SkViewFactory fFact;
+ SkViewRegister* fChain;
+
+ static SkViewRegister* gHead;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class SampleView : public SkView {
+public:
+ SampleView() : fRepeatCount(1), fBGColor(SK_ColorWHITE) {
+ fUsePipe = false;
+ }
+
+ void setBGColor(SkColor color) { fBGColor = color; }
+
+ static bool IsSampleView(SkView*);
+ static bool SetRepeatDraw(SkView*, int count);
+ static bool SetUsePipe(SkView*, bool);
+
+protected:
+ virtual void onDrawBackground(SkCanvas*);
+ virtual void onDrawContent(SkCanvas*) = 0;
+
+ // overrides
+ virtual bool onEvent(const SkEvent& evt);
+ virtual bool onQuery(SkEvent* evt);
+ virtual void onDraw(SkCanvas*);
+
+private:
+ int fRepeatCount;
+ SkColor fBGColor;
+
+ bool fUsePipe;
+
+ typedef SkView INHERITED;
+};
+
+#endif
+
diff --git a/samplecode/SampleColorFilter.cpp b/samplecode/SampleColorFilter.cpp
new file mode 100644
index 0000000..0e1fb11
--- /dev/null
+++ b/samplecode/SampleColorFilter.cpp
@@ -0,0 +1,210 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkColorFilter.h"
+#include "SkDevice.h"
+#include "SkPaint.h"
+#include "SkShader.h"
+
+static int inflate5To8(int x) {
+ return (x << 3) | (x >> 2);
+}
+
+static int trunc5(int x) {
+ return x >> 3;
+}
+
+#define SK_R16_BITS 5
+
+static int round5_slow(int x) {
+ int orig = x & 7;
+ int fake = x >> 5;
+ int trunc = x >> 3;
+
+ int diff = fake - orig;
+
+ int bias = 0;
+ if (diff > 4) {
+ bias = -1;
+ } else if (diff < -4) {
+ bias = 1;
+ }
+ return trunc + bias;
+}
+
+static int round5_fast(int x) {
+ int result = x + 3 - (x >> 5) + (x >> 7);
+ result >>= 3;
+
+ {
+ int r2 = round5_slow(x);
+ SkASSERT(r2 == result);
+ }
+ return result;
+}
+
+static void test_5bits() {
+ int e0 = 0;
+ int e1 = 0;
+ int e2 = 0;
+ int ae0 = 0;
+ int ae1 = 0;
+ int ae2 = 0;
+ for (int i = 0; i < 256; i++) {
+ int t0 = trunc5(i);
+ int t1 = round5_fast(i);
+ int t2 = trunc5(i);
+ int v0 = inflate5To8(t0);
+ int v1 = inflate5To8(t1);
+ int v2 = inflate5To8(t2);
+ int err0 = i - v0;
+ int err1 = i - v1;
+ int err2 = i - v2;
+ SkDebugf("--- %3d : trunc=%3d (%2d) round:%3d (%2d) \n"/*new:%d (%2d)\n"*/, i,
+ v0, err0, v1, err1, v2, err2);
+
+
+ e0 += err0;
+ e1 += err1;
+ e2 += err2;
+ ae0 += SkAbs32(err0);
+ ae1 += SkAbs32(err1);
+ ae2 += SkAbs32(err2);
+ }
+ SkDebugf("--- trunc: %d %d round: %d %d new: %d %d\n", e0, ae0, e1, ae1, e2, ae2);
+}
+
+static SkShader* createChecker() {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
+ bm.allocPixels();
+ bm.lockPixels();
+ *bm.getAddr32(0, 0) = *bm.getAddr32(1, 1) = SkPreMultiplyColor(0xFFFFFFFF);
+ *bm.getAddr32(0, 1) = *bm.getAddr32(1, 0) = SkPreMultiplyColor(0xFFCCCCCC);
+ SkShader* s = SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+
+ SkMatrix m;
+ m.setScale(12, 12);
+ s->setLocalMatrix(m);
+ return s;
+}
+
+static SkBitmap createBitmap(int n) {
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, n, n);
+ bitmap.allocPixels();
+ bitmap.eraseColor(0);
+
+ SkCanvas canvas(bitmap);
+ SkRect r;
+ r.set(0, 0, SkIntToScalar(n), SkIntToScalar(n));
+ r.inset(SK_Scalar1, SK_Scalar1);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ paint.setColor(SK_ColorRED);
+ canvas.drawOval(r, paint);
+
+ r.inset(SK_Scalar1*n/4, SK_Scalar1*n/4);
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ paint.setColor(0x800000FF);
+ canvas.drawOval(r, paint);
+
+ return bitmap;
+}
+
+class ColorFilterView : public SampleView {
+ SkBitmap fBitmap;
+ SkShader* fShader;
+ enum {
+ N = 64
+ };
+public:
+ ColorFilterView() {
+ fBitmap = createBitmap(N);
+ fShader = createChecker();
+
+// test_5bits();
+ }
+
+ virtual ~ColorFilterView() {
+ fShader->unref();
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "ColorFilter");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawBackground(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setShader(fShader);
+ canvas->drawPaint(paint);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ if (false) {
+ SkPaint p;
+ p.setAntiAlias(true);
+ SkRect r = { 20.4f, 10, 20.6f, 20 };
+ canvas->drawRect(r, p);
+ r.set(30.9f, 10, 31.1f, 20);
+ canvas->drawRect(r, p);
+ return;
+ }
+
+ static const SkXfermode::Mode gModes[] = {
+ SkXfermode::kClear_Mode,
+ SkXfermode::kSrc_Mode,
+ SkXfermode::kDst_Mode,
+ SkXfermode::kSrcOver_Mode,
+ SkXfermode::kDstOver_Mode,
+ SkXfermode::kSrcIn_Mode,
+ SkXfermode::kDstIn_Mode,
+ SkXfermode::kSrcOut_Mode,
+ SkXfermode::kDstOut_Mode,
+ SkXfermode::kSrcATop_Mode,
+ SkXfermode::kDstATop_Mode,
+ SkXfermode::kXor_Mode,
+ SkXfermode::kPlus_Mode,
+ SkXfermode::kMultiply_Mode,
+ };
+
+ static const SkColor gColors[] = {
+ 0xFF000000,
+ 0x80000000,
+ 0xFF00FF00,
+ 0x8000FF00,
+ 0x00000000,
+ };
+
+ float scale = 1.5f;
+ SkPaint paint;
+ canvas->translate(N / 8, N / 8);
+
+ for (size_t y = 0; y < SK_ARRAY_COUNT(gColors); y++) {
+ for (size_t x = 0; x < SK_ARRAY_COUNT(gModes); x++) {
+ SkColorFilter* cf = SkColorFilter::CreateModeFilter(gColors[y], gModes[x]);
+ SkSafeUnref(paint.setColorFilter(cf));
+ canvas->drawBitmap(fBitmap, x * N * 1.25f, y * N * scale, &paint);
+ }
+ }
+
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new ColorFilterView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleComplexClip.cpp b/samplecode/SampleComplexClip.cpp
new file mode 100644
index 0000000..672d055
--- /dev/null
+++ b/samplecode/SampleComplexClip.cpp
@@ -0,0 +1,147 @@
+#include "SampleCode.h"
+#include "SkCanvas.h"
+#include "SkPath.h"
+#include "SkView.h"
+
+class ComplexClipView : public SampleView {
+public:
+ ComplexClipView() {
+ this->setBGColor(0xFFA0DDA0);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "ComplexClip");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPath path;
+ path.moveTo(SkIntToScalar(0), SkIntToScalar(50));
+ path.quadTo(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(50), SkIntToScalar(0));
+ path.lineTo(SkIntToScalar(175), SkIntToScalar(0));
+ path.quadTo(SkIntToScalar(200), SkIntToScalar(0), SkIntToScalar(200), SkIntToScalar(25));
+ path.lineTo(SkIntToScalar(200), SkIntToScalar(150));
+ path.quadTo(SkIntToScalar(200), SkIntToScalar(200), SkIntToScalar(150), SkIntToScalar(200));
+ path.lineTo(SkIntToScalar(0), SkIntToScalar(200));
+ path.close();
+ path.moveTo(SkIntToScalar(50), SkIntToScalar(50));
+ path.lineTo(SkIntToScalar(150), SkIntToScalar(50));
+ path.lineTo(SkIntToScalar(150), SkIntToScalar(125));
+ path.quadTo(SkIntToScalar(150), SkIntToScalar(150), SkIntToScalar(125), SkIntToScalar(150));
+ path.lineTo(SkIntToScalar(50), SkIntToScalar(150));
+ path.close();
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ SkColor pathColor = SK_ColorBLACK;
+ SkPaint pathPaint;
+ pathPaint.setAntiAlias(true);
+ pathPaint.setColor(pathColor);
+
+ SkPath clipA;
+ clipA.moveTo(SkIntToScalar(10), SkIntToScalar(20));
+ clipA.lineTo(SkIntToScalar(165), SkIntToScalar(22));
+ clipA.lineTo(SkIntToScalar(70), SkIntToScalar(105));
+ clipA.lineTo(SkIntToScalar(165), SkIntToScalar(177));
+ clipA.lineTo(SkIntToScalar(-5), SkIntToScalar(180));
+ clipA.close();
+ SkColor colorA = SK_ColorCYAN;
+
+ SkPath clipB;
+ clipB.moveTo(SkIntToScalar(40), SkIntToScalar(10));
+ clipB.lineTo(SkIntToScalar(190), SkIntToScalar(15));
+ clipB.lineTo(SkIntToScalar(195), SkIntToScalar(190));
+ clipB.lineTo(SkIntToScalar(40), SkIntToScalar(185));
+ clipB.lineTo(SkIntToScalar(155), SkIntToScalar(100));
+ clipB.close();
+ SkColor colorB = SK_ColorRED;
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(0);
+
+ canvas->translate(SkIntToScalar(10),SkIntToScalar(10));
+ canvas->drawPath(path, pathPaint);
+ paint.setColor(colorA);
+ canvas->drawPath(clipA, paint);
+ paint.setColor(colorB);
+ canvas->drawPath(clipB, paint);
+
+ static const struct {
+ SkRegion::Op fOp;
+ const char* fName;
+ } gOps[] = { //extra spaces in names for measureText
+ {SkRegion::kIntersect_Op, "Isect "},
+ {SkRegion::kDifference_Op, "Diff " },
+ {SkRegion::kUnion_Op, "Union "},
+ {SkRegion::kXOR_Op, "Xor " },
+ {SkRegion::kReverseDifference_Op, "RDiff "}
+ };
+
+ canvas->translate(0, SkIntToScalar(40));
+ canvas->scale(3 * SK_Scalar1 / 4, 3 * SK_Scalar1 / 4);
+ canvas->save();
+
+ for (int invA = 0; invA < 2; ++invA) {
+ for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); ++op) {
+ int idx = invA * SK_ARRAY_COUNT(gOps) + op;
+ if (!(idx % 3)) {
+ canvas->restore();
+ canvas->translate(0, SkIntToScalar(250));
+ canvas->save();
+ }
+ canvas->save();
+ // set clip
+ clipA.setFillType(invA ? SkPath::kInverseEvenOdd_FillType :
+ SkPath::kEvenOdd_FillType);
+ canvas->clipPath(clipA);
+ canvas->clipPath(clipB, gOps[op].fOp);
+
+ // draw path clipped
+ canvas->drawPath(path, pathPaint);
+ canvas->restore();
+
+ // draw path in hairline
+ paint.setColor(pathColor);
+ canvas->drawPath(path, paint);
+
+ // draw clips in hair line
+ paint.setColor(colorA);
+ canvas->drawPath(clipA, paint);
+ paint.setColor(colorB);
+ canvas->drawPath(clipB, paint);
+
+ paint.setTextSize(SkIntToScalar(20));
+
+ SkScalar txtX = SkIntToScalar(55);
+ paint.setColor(colorA);
+ const char* aTxt = invA ? "InverseA " : "A ";
+ canvas->drawText(aTxt, strlen(aTxt), txtX, SkIntToScalar(220), paint);
+ txtX += paint.measureText(aTxt, strlen(aTxt));
+ paint.setColor(SK_ColorBLACK);
+ canvas->drawText(gOps[op].fName, strlen(gOps[op].fName),
+ txtX, SkIntToScalar(220), paint);
+ txtX += paint.measureText(gOps[op].fName, strlen(gOps[op].fName));
+ paint.setColor(colorB);
+ canvas->drawText("B", 1, txtX, SkIntToScalar(220), paint);
+
+ canvas->translate(SkIntToScalar(250),0);
+ }
+ }
+ canvas->restore();
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new ComplexClipView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleCull.cpp b/samplecode/SampleCull.cpp
new file mode 100644
index 0000000..7b4eab6
--- /dev/null
+++ b/samplecode/SampleCull.cpp
@@ -0,0 +1,189 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkCornerPathEffect.h"
+#include "SkCullPoints.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkRandom.h"
+
+static void addbump(SkPath* path, const SkPoint pts[2], SkScalar bump) {
+ SkVector tang;
+
+ tang.setLength(pts[1].fX - pts[0].fX, pts[1].fY - pts[0].fY, bump);
+
+ path->lineTo(SkScalarHalf(pts[0].fX + pts[1].fX) - tang.fY,
+ SkScalarHalf(pts[0].fY + pts[1].fY) + tang.fX);
+ path->lineTo(pts[1]);
+}
+
+static void subdivide(SkPath* path, SkScalar bump) {
+ SkPath::Iter iter(*path, false);
+ SkPoint pts[4];
+ SkPath tmp;
+
+ for (;;)
+ switch (iter.next(pts)) {
+ case SkPath::kMove_Verb:
+ tmp.moveTo(pts[0]);
+ break;
+ case SkPath::kLine_Verb:
+ addbump(&tmp, pts, bump);
+ bump = -bump;
+ break;
+ case SkPath::kDone_Verb:
+ goto FINISH;
+ default:
+ break;
+ }
+
+FINISH:
+ path->swap(tmp);
+}
+
+static SkIPoint* getpts(const SkPath& path, int* count) {
+ SkPoint pts[4];
+ int n = 1;
+ SkIPoint* array;
+
+ {
+ SkPath::Iter iter(path, false);
+ for (;;)
+ switch (iter.next(pts)) {
+ case SkPath::kLine_Verb:
+ n += 1;
+ break;
+ case SkPath::kDone_Verb:
+ goto FINISHED;
+ default:
+ break;
+ }
+ }
+
+FINISHED:
+ array = new SkIPoint[n];
+ n = 0;
+
+ {
+ SkPath::Iter iter(path, false);
+ for (;;)
+ switch (iter.next(pts)) {
+ case SkPath::kMove_Verb:
+ array[n++].set(SkScalarRound(pts[0].fX), SkScalarRound(pts[0].fY));
+ break;
+ case SkPath::kLine_Verb:
+ array[n++].set(SkScalarRound(pts[1].fX), SkScalarRound(pts[1].fY));
+ break;
+ case SkPath::kDone_Verb:
+ goto FINISHED2;
+ default:
+ break;
+ }
+ }
+
+FINISHED2:
+ *count = n;
+ return array;
+}
+
+static SkScalar nextScalarRange(SkRandom& rand, SkScalar min, SkScalar max) {
+ return min + SkScalarMul(rand.nextUScalar1(), max - min);
+}
+
+class CullView : public SampleView {
+public:
+ CullView() {
+ fClip.set(0, 0, SkIntToScalar(160), SkIntToScalar(160));
+
+ SkRandom rand;
+
+ for (int i = 0; i < 50; i++) {
+ SkScalar x = nextScalarRange(rand, -fClip.width()*1, fClip.width()*2);
+ SkScalar y = nextScalarRange(rand, -fClip.height()*1, fClip.height()*2);
+ if (i == 0)
+ fPath.moveTo(x, y);
+ else
+ fPath.lineTo(x, y);
+ }
+
+ SkScalar bump = fClip.width()/8;
+ subdivide(&fPath, bump);
+ subdivide(&fPath, bump);
+ subdivide(&fPath, bump);
+ fPoints = getpts(fPath, &fPtCount);
+
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+ virtual ~CullView() {
+ delete[] fPoints;
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Culling");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkAutoCanvasRestore ar(canvas, true);
+
+ canvas->translate( SkScalarHalf(this->width() - fClip.width()),
+ SkScalarHalf(this->height() - fClip.height()));
+
+ // canvas->scale(SK_Scalar1*3, SK_Scalar1*3, 0, 0);
+
+ SkPaint paint;
+
+ // paint.setAntiAliasOn(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+
+ canvas->drawRect(fClip, paint);
+
+#if 1
+ paint.setColor(0xFF555555);
+ paint.setStrokeWidth(SkIntToScalar(2));
+// paint.setPathEffect(new SkCornerPathEffect(SkIntToScalar(30)))->unref();
+ canvas->drawPath(fPath, paint);
+// paint.setPathEffect(NULL);
+#endif
+
+ SkPath tmp;
+ SkIRect iclip;
+ fClip.round(&iclip);
+
+ SkCullPointsPath cpp(iclip, &tmp);
+
+ cpp.moveTo(fPoints[0].fX, fPoints[0].fY);
+ for (int i = 0; i < fPtCount; i++)
+ cpp.lineTo(fPoints[i].fX, fPoints[i].fY);
+
+ paint.setColor(SK_ColorRED);
+ paint.setStrokeWidth(SkIntToScalar(3));
+ paint.setStrokeJoin(SkPaint::kRound_Join);
+ canvas->drawPath(tmp, paint);
+
+ this->inval(NULL);
+ }
+
+private:
+ SkRect fClip;
+ SkIPoint* fPoints;
+ SkPath fPath;
+ int fPtCount;
+
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new CullView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleDash.cpp b/samplecode/SampleDash.cpp
new file mode 100644
index 0000000..4cef07f
--- /dev/null
+++ b/samplecode/SampleDash.cpp
@@ -0,0 +1,88 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGraphics.h"
+#include "SkRandom.h"
+#include "SkDashPathEffect.h"
+#include "SkShader.h"
+
+static void setBitmapDash(SkPaint* paint, int width) {
+ SkColor c = paint->getColor();
+
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, 2, 1);
+ bm.allocPixels();
+ bm.lockPixels();
+ *bm.getAddr32(0, 0) = SkPreMultiplyARGB(0xFF, SkColorGetR(c),
+ SkColorGetG(c), SkColorGetB(c));
+ *bm.getAddr32(1, 0) = 0;
+ bm.unlockPixels();
+
+ SkMatrix matrix;
+ matrix.setScale(SkIntToScalar(width), SK_Scalar1);
+
+ SkShader* s = SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode,
+ SkShader::kClamp_TileMode);
+ s->setLocalMatrix(matrix);
+
+ paint->setShader(s)->unref();
+}
+
+class DashView : public SampleView {
+public:
+ DashView() {
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Dash");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ static const char* gStr[] = {
+ "11",
+ "44",
+ "112233",
+ "411327463524",
+ };
+
+ SkPaint paint;
+ paint.setStrokeWidth(SkIntToScalar(1));
+
+ SkScalar x0 = SkIntToScalar(10);
+ SkScalar y0 = SkIntToScalar(10);
+ SkScalar x1 = x0 + SkIntToScalar(1000);
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gStr); i++) {
+ SkScalar interval[12];
+ size_t len = SkMin32(strlen(gStr[i]), SK_ARRAY_COUNT(interval));
+ for (size_t j = 0; j < len; j++) {
+ interval[j] = SkIntToScalar(gStr[i][j] - '0');
+ }
+
+ SkDashPathEffect dash(interval, len, 0);
+ paint.setPathEffect(&dash);
+ canvas->drawLine(x0, y0, x1, y0, paint);
+ paint.setPathEffect(NULL);
+
+ y0 += paint.getStrokeWidth() * 3;
+ }
+
+ setBitmapDash(&paint, 3);
+ canvas->drawLine(x0, y0, x1, y0, paint);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new DashView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleDecode.cpp b/samplecode/SampleDecode.cpp
new file mode 100644
index 0000000..b192c5d
--- /dev/null
+++ b/samplecode/SampleDecode.cpp
@@ -0,0 +1,69 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkImageDecoder.h"
+#include "SkStream.h"
+
+static const struct {
+ SkBitmap::Config fPrefConfig;
+ bool fDither;
+} gRec[] = {
+ { SkBitmap::kIndex8_Config, false },
+ { SkBitmap::kARGB_8888_Config, false },
+ { SkBitmap::kARGB_4444_Config, false },
+ { SkBitmap::kARGB_4444_Config, true },
+ { SkBitmap::kRGB_565_Config, false },
+ { SkBitmap::kRGB_565_Config, true },
+};
+
+class DecodeView : public SkView {
+public:
+ SkBitmap fBitmap[SK_ARRAY_COUNT(gRec)];
+
+ DecodeView() {
+ SkFILEStream stream("/skimages/index.png");
+ SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
+ if (codec) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) {
+ stream.rewind();
+ codec->setDitherImage(gRec[i].fDither);
+ codec->decode(&stream, &fBitmap[i], gRec[i].fPrefConfig,
+ SkImageDecoder::kDecodePixels_Mode);
+ }
+ }
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "ImageDecoder");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(0xFFDDDDDD);
+// canvas->drawColor(SK_ColorWHITE);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ this->drawBG(canvas);
+
+ canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(fBitmap); i++) {
+ canvas->drawBitmap(fBitmap[i], 0, 0);
+ canvas->translate(SkIntToScalar(fBitmap[i].width()), 0);
+ }
+ }
+private:
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new DecodeView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleDither.cpp b/samplecode/SampleDither.cpp
new file mode 100644
index 0000000..3e77a5d
--- /dev/null
+++ b/samplecode/SampleDither.cpp
@@ -0,0 +1,178 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "Sk1DPathEffect.h"
+#include "SkCornerPathEffect.h"
+#include "SkPathMeasure.h"
+#include "SkRandom.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkDither.h"
+
+static void draw_sweep(SkCanvas* c, int width, int height, SkScalar angle) {
+ SkRect r;
+ SkPaint p;
+
+ p.setAntiAlias(true);
+// p.setDither(true);
+ p.setStrokeWidth(SkIntToScalar(width/10));
+ p.setStyle(SkPaint::kStroke_Style);
+
+ r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height));
+
+ // SkColor colors[] = { SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN, SK_ColorCYAN };
+ SkColor colors[] = { 0x4c737373, 0x4c737373, 0xffffd300 };
+ SkShader* s = SkGradientShader::CreateSweep(r.centerX(), r.centerY(),
+ colors, NULL, SK_ARRAY_COUNT(colors));
+ p.setShader(s)->unref();
+
+ SkAutoCanvasRestore acr(c, true);
+
+ c->translate(r.centerX(), r.centerY());
+ c->rotate(angle);
+ c->translate(-r.centerX(), -r.centerY());
+
+ SkRect bounds = r;
+ r.inset(p.getStrokeWidth(), p.getStrokeWidth());
+ SkRect innerBounds = r;
+
+ if (true) {
+ c->drawOval(r, p);
+ } else {
+ SkScalar x = r.centerX();
+ SkScalar y = r.centerY();
+ SkScalar radius = r.width() / 2;
+ SkScalar thickness = p.getStrokeWidth();
+ SkScalar sweep = SkFloatToScalar(360.0f);
+ SkPath path;
+
+ path.moveTo(x + radius, y);
+ // outer top
+ path.lineTo(x + radius + thickness, y);
+ // outer arc
+ path.arcTo(bounds, 0, sweep, false);
+ // inner arc
+ path.arcTo(innerBounds, sweep, -sweep, false);
+ path.close();
+ }
+}
+
+static void make_bm(SkBitmap* bm) {
+ bm->setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
+ bm->allocPixels();
+#if 0
+ bm->eraseColor(SK_ColorBLUE);
+ return;
+#else
+ bm->eraseColor(0);
+#endif
+
+ SkCanvas c(*bm);
+ draw_sweep(&c, bm->width(), bm->height(), 0);
+}
+
+static void pre_dither(const SkBitmap& bm) {
+ SkAutoLockPixels alp(bm);
+
+ for (int y = 0; y < bm.height(); y++) {
+ DITHER_4444_SCAN(y);
+
+ SkPMColor* p = bm.getAddr32(0, y);
+ for (int x = 0; x < bm.width(); x++) {
+ SkPMColor c = *p;
+
+ unsigned a = SkGetPackedA32(c);
+ unsigned r = SkGetPackedR32(c);
+ unsigned g = SkGetPackedG32(c);
+ unsigned b = SkGetPackedB32(c);
+
+ unsigned d = DITHER_VALUE(x);
+
+ a = SkDITHER_A32To4444(a, d);
+ r = SkDITHER_R32To4444(r, d);
+ g = SkDITHER_G32To4444(g, d);
+ b = SkDITHER_B32To4444(b, d);
+
+ a = SkA4444ToA32(a);
+ r = SkR4444ToR32(r);
+ g = SkG4444ToG32(g);
+ b = SkB4444ToB32(b);
+
+ *p++ = SkPackARGB32(a, r, g, b);
+ }
+ }
+}
+
+class DitherView : public SampleView {
+public:
+ SkBitmap fBM, fBMPreDither, fBM16;
+ SkScalar fAngle;
+
+ DitherView() {
+ make_bm(&fBM);
+ make_bm(&fBMPreDither);
+ pre_dither(fBMPreDither);
+ fBM.copyTo(&fBM16, SkBitmap::kARGB_4444_Config);
+
+ fAngle = 0;
+
+ this->setBGColor(0xFF181818);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Dither");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+ SkScalar x = SkIntToScalar(10);
+ SkScalar y = SkIntToScalar(10);
+ const SkScalar DX = SkIntToScalar(fBM.width() + 10);
+
+ paint.setAntiAlias(true);
+
+ if (true) {
+ canvas->drawBitmap(fBM, x, y, &paint);
+ x += DX;
+ paint.setDither(true);
+ canvas->drawBitmap(fBM, x, y, &paint);
+
+ x += DX;
+ paint.setDither(false);
+ canvas->drawBitmap(fBMPreDither, x, y, &paint);
+
+ x += DX;
+ canvas->drawBitmap(fBM16, x, y, &paint);
+ }
+
+ canvas->translate(DX, DX*2);
+ draw_sweep(canvas, fBM.width(), fBM.height(), fAngle);
+ canvas->translate(DX, 0);
+ draw_sweep(canvas, fBM.width()>>1, fBM.height()>>1, fAngle);
+ canvas->translate(DX, 0);
+ draw_sweep(canvas, fBM.width()>>2, fBM.height()>>2, fAngle);
+
+ fAngle += SK_Scalar1/2;
+ this->inval(NULL);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new DitherView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleDitherBitmap.cpp b/samplecode/SampleDitherBitmap.cpp
new file mode 100644
index 0000000..0d62446
--- /dev/null
+++ b/samplecode/SampleDitherBitmap.cpp
@@ -0,0 +1,141 @@
+#include "SampleCode.h"
+#include "SkColorPriv.h"
+#include "SkGradientShader.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkUtils.h"
+
+static void draw_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
+ canvas->drawRect(r, p);
+
+ SkPaint frame(p);
+ frame.setShader(NULL);
+ frame.setStyle(SkPaint::kStroke_Style);
+ canvas->drawRect(r, frame);
+}
+
+static void draw_gradient(SkCanvas* canvas) {
+ SkRect r = { 0, 0, SkIntToScalar(256), SkIntToScalar(32) };
+ SkPoint pts[] = { { r.fLeft, r.fTop }, { r.fRight, r.fTop } };
+ SkColor colors[] = { 0xFF000000, 0xFFFF0000 };
+ SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2,
+ SkShader::kClamp_TileMode);
+
+ SkPaint p;
+ p.setShader(s)->unref();
+ draw_rect(canvas, r, p);
+
+ canvas->translate(0, SkIntToScalar(40));
+ p.setDither(true);
+ draw_rect(canvas, r, p);
+}
+
+static void test_pathregion() {
+ SkPath path;
+ SkRegion region;
+ path.moveTo(25071800.f, -141823808.f);
+ path.lineTo(25075500.f, -141824000.f);
+ path.lineTo(25075400.f, -141827712.f);
+ path.lineTo(25071810.f, -141827600.f);
+ path.close();
+
+ SkIRect bounds;
+ path.getBounds().round(&bounds);
+ SkRegion clip(bounds);
+ bool result = region.setPath(path, clip); // <-- !! DOWN !!
+ SkDebugf("----- result %d\n", result);
+}
+
+static SkBitmap make_bitmap() {
+ SkBitmap bm;
+ SkColorTable* ctable = new SkColorTable(256);
+
+ SkPMColor* c = ctable->lockColors();
+ for (int i = 0; i < 256; i++) {
+ c[i] = SkPackARGB32(0xFF, i, 0, 0);
+ }
+ ctable->unlockColors(true);
+ bm.setConfig(SkBitmap::kIndex8_Config, 256, 32);
+ bm.allocPixels(ctable);
+ ctable->unref();
+
+ bm.lockPixels();
+ for (int y = 0; y < bm.height(); y++) {
+ uint8_t* p = bm.getAddr8(0, y);
+ for (int x = 0; x < 256; x++) {
+ p[x] = x;
+ }
+ }
+ bm.unlockPixels();
+ return bm;
+}
+
+class DitherBitmapView : public SampleView {
+ SkBitmap fBM8;
+ SkBitmap fBM32;
+public:
+ DitherBitmapView() {
+ test_pathregion();
+ fBM8 = make_bitmap();
+ fBM8.copyTo(&fBM32, SkBitmap::kARGB_8888_Config);
+
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "DitherBitmap");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ static void setBitmapOpaque(SkBitmap* bm, bool isOpaque) {
+ SkAutoLockPixels alp(*bm); // needed for ctable
+ bm->setIsOpaque(isOpaque);
+ SkColorTable* ctable = bm->getColorTable();
+ if (ctable) {
+ ctable->setIsOpaque(isOpaque);
+ }
+ }
+
+ static void draw2(SkCanvas* canvas, const SkBitmap& bm) {
+ SkPaint paint;
+ SkBitmap bitmap(bm);
+
+ setBitmapOpaque(&bitmap, false);
+ paint.setDither(false);
+ canvas->drawBitmap(bitmap, 0, 0, &paint);
+ paint.setDither(true);
+ canvas->drawBitmap(bitmap, 0, SkIntToScalar(bm.height() + 10), &paint);
+
+ setBitmapOpaque(&bitmap, true);
+ SkScalar x = SkIntToScalar(bm.width() + 10);
+ paint.setDither(false);
+ canvas->drawBitmap(bitmap, x, 0, &paint);
+ paint.setDither(true);
+ canvas->drawBitmap(bitmap, x, SkIntToScalar(bm.height() + 10), &paint);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
+
+ draw2(canvas, fBM8);
+ canvas->translate(0, SkIntToScalar(fBM8.height() *3));
+ draw2(canvas, fBM32);
+
+ canvas->translate(0, SkIntToScalar(fBM8.height() *3));
+ draw_gradient(canvas);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new DitherBitmapView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleDraw.cpp b/samplecode/SampleDraw.cpp
new file mode 100644
index 0000000..deb1fb2
--- /dev/null
+++ b/samplecode/SampleDraw.cpp
@@ -0,0 +1,373 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGraphics.h"
+#include "SkRandom.h"
+
+static void test_clearonlayers(SkCanvas* canvas) {
+ SkCanvas& c = *canvas;
+
+ SkPaint paint;
+ paint.setColor(SK_ColorBLUE);
+ paint.setStyle(SkPaint::kStrokeAndFill_Style);
+ SkRect rect = SkRect::MakeXYWH(25, 25, 50, 50);
+ c.drawRect(rect, paint);
+
+ c.clipRect(rect);
+
+ c.saveLayer(NULL, NULL);
+ rect = SkRect::MakeXYWH(50, 10, 40, 80);
+ c.clipRect(rect, SkRegion::kUnion_Op);
+
+ rect = SkRect::MakeXYWH(50, 0, 50, 100);
+ // You might draw something here, but it's not necessary.
+ // paint.setColor(SK_ColorRED);
+ // c.drawRect(rect, paint);
+ paint.setXfermodeMode(SkXfermode::kClear_Mode);
+ c.drawRect(rect, paint);
+ c.restore();
+}
+
+static void test_strokerect(SkCanvas* canvas, const SkRect& r) {
+ SkPaint p;
+
+ p.setAntiAlias(true);
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(4);
+
+ canvas->drawRect(r, p);
+
+ SkPath path;
+ SkRect r2(r);
+ r2.offset(18, 0);
+ path.addRect(r2);
+
+ canvas->drawPath(path, p);
+}
+
+static void test_strokerect(SkCanvas* canvas) {
+ canvas->drawColor(SK_ColorWHITE);
+
+ SkRect r;
+
+ r.set(10, 10, 14, 14);
+ r.offset(0.25f, 0.3333f);
+ test_strokerect(canvas, r);
+ canvas->translate(0, 20);
+
+ r.set(10, 10, 14.5f, 14.5f);
+ r.offset(0.25f, 0.3333f);
+ test_strokerect(canvas, r);
+ canvas->translate(0, 20);
+
+ r.set(10, 10, 14.5f, 20);
+ r.offset(0.25f, 0.3333f);
+ test_strokerect(canvas, r);
+ canvas->translate(0, 20);
+
+ r.set(10, 10, 20, 14.5f);
+ r.offset(0.25f, 0.3333f);
+ test_strokerect(canvas, r);
+ canvas->translate(0, 20);
+
+ r.set(10, 10, 20, 20);
+ r.offset(0.25f, 0.3333f);
+ test_strokerect(canvas, r);
+ canvas->translate(0, 20);
+
+}
+
+class Draw : public SkRefCnt {
+public:
+ Draw() : fFlags(0) {}
+
+ enum Flags {
+ kSelected_Flag = 1 << 0
+ };
+ int getFlags() const { return fFlags; }
+ void setFlags(int flags);
+
+ bool isSelected() const { return SkToBool(fFlags & kSelected_Flag); }
+ void setSelected(bool pred) {
+ if (pred) {
+ fFlags |= kSelected_Flag;
+ } else {
+ fFlags &= ~kSelected_Flag;
+ }
+ }
+
+ void draw(SkCanvas* canvas) {
+ int sc = canvas->save();
+ this->onDraw(canvas);
+ canvas->restoreToCount(sc);
+
+ if (this->isSelected()) {
+ this->drawSelection(canvas);
+ }
+ }
+
+ void drawSelection(SkCanvas* canvas) {
+ int sc = canvas->save();
+ this->onDrawSelection(canvas);
+ canvas->restoreToCount(sc);
+ }
+
+ void getBounds(SkRect* bounds) {
+ this->onGetBounds(bounds);
+ }
+
+ bool hitTest(SkScalar x, SkScalar y) {
+ return this->onHitTest(x, y);
+ }
+
+ void offset(SkScalar dx, SkScalar dy) {
+ if (dx || dy) {
+ this->onOffset(dx, dy);
+ }
+ }
+
+protected:
+ virtual void onDraw(SkCanvas*) = 0;
+ virtual void onGetBounds(SkRect*) = 0;
+ virtual void onOffset(SkScalar dx, SkScalar dy) = 0;
+ virtual void onDrawSelection(SkCanvas* canvas) {
+ SkRect r;
+ this->getBounds(&r);
+ SkPaint paint;
+ SkPoint pts[4];
+ r.toQuad(pts);
+ paint.setStrokeWidth(SkIntToScalar(10));
+ paint.setColor(0x80FF8844);
+ paint.setStrokeCap(SkPaint::kRound_Cap);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, pts, paint);
+ }
+ virtual bool onHitTest(SkScalar x, SkScalar y) {
+ SkRect bounds;
+ this->getBounds(&bounds);
+ return bounds.contains(x, y);
+ }
+
+private:
+ int fFlags;
+};
+
+class RDraw : public Draw {
+public:
+ enum Style {
+ kRect_Style,
+ kOval_Style,
+ kRRect_Style,
+ kFrame_Style
+ };
+
+ RDraw(const SkRect& r, Style s) : fRect(r), fStyle(s) {}
+
+ void setRect(const SkRect& r) {
+ fRect = r;
+ }
+
+ void setPaint(const SkPaint& p) {
+ fPaint = p;
+ }
+
+protected:
+ virtual void onDraw(SkCanvas* canvas) {
+ switch (fStyle) {
+ case kRect_Style:
+ canvas->drawRect(fRect, fPaint);
+ break;
+ case kOval_Style:
+ canvas->drawOval(fRect, fPaint);
+ break;
+ case kRRect_Style: {
+ SkScalar rx = fRect.width() / 5;
+ SkScalar ry = fRect.height() / 5;
+ if (rx < ry) {
+ ry = rx;
+ } else {
+ rx = ry;
+ }
+ canvas->drawRoundRect(fRect, rx, ry, fPaint);
+ break;
+ }
+ case kFrame_Style: {
+ SkPath path;
+ path.addOval(fRect, SkPath::kCW_Direction);
+ SkRect r = fRect;
+ r.inset(fRect.width()/6, 0);
+ path.addOval(r, SkPath::kCCW_Direction);
+ canvas->drawPath(path, fPaint);
+ break;
+ }
+ }
+ }
+
+ virtual void onGetBounds(SkRect* bounds) {
+ *bounds = fRect;
+ }
+
+ virtual void onOffset(SkScalar dx, SkScalar dy) {
+ fRect.offset(dx, dy);
+ }
+
+private:
+ SkRect fRect;
+ SkPaint fPaint;
+ Style fStyle;
+};
+
+class DrawFactory {
+public:
+ DrawFactory() {
+ fPaint.setAntiAlias(true);
+ }
+
+ const SkPaint& getPaint() const { return fPaint; }
+
+ void setPaint(const SkPaint& p) {
+ fPaint = p;
+ }
+
+ virtual Draw* create(const SkPoint&, const SkPoint&) = 0;
+
+private:
+ SkPaint fPaint;
+};
+
+class RectFactory : public DrawFactory {
+public:
+ virtual Draw* create(const SkPoint& p0, const SkPoint& p1) {
+ SkRect r;
+ r.set(p0.x(), p0.y(), p1.x(), p1.y());
+ r.sort();
+
+// RDraw* d = new RDraw(r, RDraw::kRRect_Style);
+ RDraw* d = new RDraw(r, RDraw::kFrame_Style);
+ d->setPaint(this->getPaint());
+ return d;
+ }
+};
+
+class DrawView : public SkView {
+ Draw* fDraw;
+ DrawFactory* fFactory;
+ SkRandom fRand;
+ SkTDArray<Draw*> fList;
+
+public:
+ DrawView() : fDraw(NULL) {
+ fFactory = new RectFactory;
+ }
+
+ virtual ~DrawView() {
+ fList.unrefAll();
+ SkSafeUnref(fDraw);
+ delete fFactory;
+ }
+
+ Draw* setDraw(Draw* d) {
+ SkRefCnt_SafeAssign(fDraw, d);
+ return d;
+ }
+
+ SkColor randColor() {
+ return (SkColor)fRand.nextU() | 0xFF000000;
+ }
+
+ Draw* hitTestList(SkScalar x, SkScalar y) const {
+ Draw** first = fList.begin();
+ for (Draw** iter = fList.end(); iter > first;) {
+ --iter;
+ if ((*iter)->hitTest(x, y)) {
+ return *iter;
+ }
+ }
+ return NULL;
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Draw");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(0xFFDDDDDD);
+// canvas->drawColor(SK_ColorWHITE);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ this->drawBG(canvas);
+ test_clearonlayers(canvas); return;
+ // test_strokerect(canvas); return;
+
+ for (Draw** iter = fList.begin(); iter < fList.end(); iter++) {
+ (*iter)->draw(canvas);
+ }
+ if (fDraw) {
+ fDraw->draw(canvas);
+ }
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ for (Draw** iter = fList.begin(); iter < fList.end(); iter++) {
+ (*iter)->setSelected(false);
+ }
+
+ Click* c = new Click(this);
+ Draw* d = this->hitTestList(x, y);
+ if (d) {
+ d->setSelected(true);
+ c->setType("dragger");
+ } else {
+ c->setType("maker");
+ }
+ return c;
+ }
+
+ virtual bool onClick(Click* click) {
+ if (Click::kUp_State == click->fState) {
+ if (click->isType("maker")) {
+ if (SkPoint::Distance(click->fOrig, click->fCurr) > SkIntToScalar(3)) {
+ *fList.append() = fDraw;
+ } else {
+ fDraw->unref();
+ }
+ fDraw = NULL;
+ }
+ return true;
+ }
+
+ if (Click::kDown_State == click->fState) {
+ SkPaint p = fFactory->getPaint();
+ p.setColor(this->randColor());
+ fFactory->setPaint(p);
+ }
+
+ if (click->isType("maker")) {
+ this->setDraw(fFactory->create(click->fOrig, click->fCurr))->unref();
+ } else if (click->isType("dragger")) {
+ for (Draw** iter = fList.begin(); iter < fList.end(); iter++) {
+ if ((*iter)->isSelected()) {
+ (*iter)->offset(click->fCurr.x() - click->fPrev.x(),
+ click->fCurr.y() - click->fPrev.y());
+ }
+ }
+ }
+ this->inval(NULL);
+ return true;
+ }
+
+private:
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new DrawView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleDrawLooper.cpp b/samplecode/SampleDrawLooper.cpp
new file mode 100644
index 0000000..30879f7
--- /dev/null
+++ b/samplecode/SampleDrawLooper.cpp
@@ -0,0 +1,92 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGraphics.h"
+#include "SkRandom.h"
+#include "SkLayerDrawLooper.h"
+#include "SkBlurMaskFilter.h"
+
+#define WIDTH 200
+#define HEIGHT 200
+
+class LooperView : public SampleView {
+public:
+
+ SkLayerDrawLooper* fLooper;
+
+ LooperView() {
+ static const struct {
+ SkColor fColor;
+ SkPaint::Style fStyle;
+ SkScalar fWidth;
+ SkScalar fOffset;
+ int fBlur;
+ } gParams[] = {
+ { SK_ColorWHITE, SkPaint::kStroke_Style, SkIntToScalar(1)*3/4, 0, 0 },
+ { SK_ColorRED, SkPaint::kStroke_Style, SkIntToScalar(4), 0, 0 },
+ { SK_ColorBLUE, SkPaint::kFill_Style, 0, 0, 0 },
+ { 0x88000000, SkPaint::kFill_Style, 0, SkIntToScalar(10), 3 }
+ };
+
+ fLooper = new SkLayerDrawLooper;
+
+ SkLayerDrawLooper::LayerInfo info;
+ info.fFlagsMask = SkPaint::kAntiAlias_Flag;
+ info.fPaintBits = SkLayerDrawLooper::kStyle_Bit | SkLayerDrawLooper::kMaskFilter_Bit;
+ info.fColorMode = SkXfermode::kSrc_Mode;
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gParams); i++) {
+ info.fOffset.set(gParams[i].fOffset, gParams[i].fOffset);
+ SkPaint* paint = fLooper->addLayer(info);
+ paint->setAntiAlias(true);
+ paint->setColor(gParams[i].fColor);
+ paint->setStyle(gParams[i].fStyle);
+ paint->setStrokeWidth(gParams[i].fWidth);
+ if (gParams[i].fBlur > 0) {
+ SkMaskFilter* mf = SkBlurMaskFilter::Create(SkIntToScalar(gParams[i].fBlur),
+ SkBlurMaskFilter::kNormal_BlurStyle);
+ paint->setMaskFilter(mf)->unref();
+ }
+ }
+
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+ virtual ~LooperView() {
+ SkSafeUnref(fLooper);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "DrawLooper");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setTextSize(SkIntToScalar(72));
+ paint.setLooper(fLooper);
+
+ canvas->drawCircle(SkIntToScalar(50), SkIntToScalar(50),
+ SkIntToScalar(30), paint);
+
+ canvas->drawRectCoords(SkIntToScalar(150), SkIntToScalar(50),
+ SkIntToScalar(200), SkIntToScalar(100), paint);
+
+ canvas->drawText("Looper", 6, SkIntToScalar(230), SkIntToScalar(100),
+ paint);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new LooperView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleEffects.cpp b/samplecode/SampleEffects.cpp
new file mode 100644
index 0000000..a63c08d
--- /dev/null
+++ b/samplecode/SampleEffects.cpp
@@ -0,0 +1,130 @@
+#include "SampleCode.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkView.h"
+
+#include "SkBlurMaskFilter.h"
+#include "SkColorMatrixFilter.h"
+#include "SkDiscretePathEffect.h"
+#include "SkGradientShader.h"
+
+#include "SkEdgeClipper.h"
+
+static void test_edgeclipper() {
+ SkPoint pts[] = {
+ { -8.38822452e+21f, -7.69721471e+19f },
+ { 1.57645875e+23f, 1.44634003e+21f },
+ { 1.61519691e+23f, 1.48208059e+21f },
+ { 3.13963584e+23f, 2.88057438e+21f }
+ };
+ SkRect clip = { 0, 0, 300, 200 };
+
+ SkEdgeClipper clipper;
+ clipper.clipCubic(pts, clip);
+}
+
+///////////
+
+//#define COLOR 0xFFFF8844
+#define COLOR 0xFF888888
+
+static void paint_proc0(SkPaint* paint) {
+}
+
+static void paint_proc1(SkPaint* paint) {
+ paint->setMaskFilter(SkBlurMaskFilter::Create(2,
+ SkBlurMaskFilter::kNormal_BlurStyle))->unref();
+}
+
+static void paint_proc2(SkPaint* paint) {
+ SkScalar dir[3] = { 1, 1, 1};
+ paint->setMaskFilter(
+ SkBlurMaskFilter::CreateEmboss(dir, 0.1f, 0.05f, 1))->unref();
+}
+
+static void paint_proc3(SkPaint* paint) {
+ SkColor colors[] = { SK_ColorRED, COLOR, SK_ColorBLUE };
+ SkPoint pts[] = { { 3, 0 }, { 7, 5 } };
+ paint->setShader(SkGradientShader::CreateLinear(pts, colors, NULL, SK_ARRAY_COUNT(colors),
+ SkShader::kMirror_TileMode))->unref();
+}
+
+static void paint_proc5(SkPaint* paint) {
+ paint_proc3(paint);
+ paint_proc2(paint);
+}
+
+typedef void (*PaintProc)(SkPaint*);
+const PaintProc gPaintProcs[] = {
+ paint_proc0,
+ paint_proc1,
+ paint_proc2,
+ paint_proc3,
+ paint_proc5,
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class EffectsView : public SampleView {
+public:
+ SkPath fPath;
+ SkPaint fPaint[SK_ARRAY_COUNT(gPaintProcs)];
+
+ EffectsView() {
+ size_t i;
+ const float pts[] = {
+ 0, 0,
+ 10, 0,
+ 10, 5,
+ 20, -5,
+ 10, -15,
+ 10, -10,
+ 0, -10
+ };
+ fPath.moveTo(pts[0], pts[1]);
+ for (i = 2; i < SK_ARRAY_COUNT(pts); i += 2) {
+ fPath.lineTo(pts[i], pts[i+1]);
+ }
+
+ for (i = 0; i < SK_ARRAY_COUNT(gPaintProcs); i++) {
+ fPaint[i].setAntiAlias(true);
+ fPaint[i].setColor(COLOR);
+ gPaintProcs[i](&fPaint[i]);
+ }
+
+ test_edgeclipper();
+ SkColorMatrix cm;
+ cm.setRotate(SkColorMatrix::kG_Axis, 180);
+ cm.setIdentity();
+
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Effects");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ canvas->scale(3, 3);
+ canvas->translate(10, 30);
+ for (size_t i = 0; i < SK_ARRAY_COUNT(fPaint); i++) {
+ canvas->drawPath(fPath, fPaint[i]);
+ canvas->translate(32, 0);
+ }
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new EffectsView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleEmboss.cpp b/samplecode/SampleEmboss.cpp
new file mode 100644
index 0000000..8b3f194
--- /dev/null
+++ b/samplecode/SampleEmboss.cpp
@@ -0,0 +1,66 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "Sk64.h"
+#include "SkColorShader.h"
+#include "SkEmbossMaskFilter.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkKernel33MaskFilter.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"
+
+class EmbossView : public SampleView {
+ SkEmbossMaskFilter::Light fLight;
+public:
+ EmbossView() {
+ fLight.fDirection[0] = SK_Scalar1;
+ fLight.fDirection[1] = SK_Scalar1;
+ fLight.fDirection[2] = SK_Scalar1;
+ fLight.fAmbient = 128;
+ fLight.fSpecular = 16*2;
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Emboss");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkIntToScalar(10));
+ paint.setMaskFilter(new SkEmbossMaskFilter(fLight, SkIntToScalar(4)))->unref();
+ paint.setShader(new SkColorShader(SK_ColorBLUE))->unref();
+ paint.setDither(true);
+
+ canvas->drawCircle(SkIntToScalar(50), SkIntToScalar(50),
+ SkIntToScalar(30), paint);
+ }
+
+private:
+
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new EmbossView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleEncode.cpp b/samplecode/SampleEncode.cpp
new file mode 100644
index 0000000..f4ea195
--- /dev/null
+++ b/samplecode/SampleEncode.cpp
@@ -0,0 +1,224 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkImageEncoder.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+
+#include "SkStream.h"
+
+static void make_image(SkBitmap* bm, SkBitmap::Config config, int configIndex) {
+ const int width = 98;
+ const int height = 100;
+ SkBitmap device;
+
+ device.setConfig(SkBitmap::kARGB_8888_Config, width, height);
+ device.allocPixels();
+
+ SkCanvas canvas(device);
+ SkPaint paint;
+
+ paint.setAntiAlias(true);
+ canvas.drawColor(SK_ColorRED);
+ paint.setColor(SK_ColorBLUE);
+ canvas.drawCircle(SkIntToScalar(width)/2, SkIntToScalar(height)/2,
+ SkIntToScalar(width)/2, paint);
+
+ bm->setConfig(config, width, height);
+ switch (config) {
+ case SkBitmap::kARGB_8888_Config:
+ bm->swap(device);
+ break;
+ case SkBitmap::kRGB_565_Config: {
+ bm->allocPixels();
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ *bm->getAddr16(x, y) = SkPixel32ToPixel16(*device.getAddr32(x, y));
+ }
+ }
+ break;
+ }
+ case SkBitmap::kIndex8_Config: {
+ SkPMColor colors[256];
+ for (int i = 0; i < 256; i++) {
+ if (configIndex & 1) {
+ colors[i] = SkPackARGB32(255-i, 0, 0, 255-i);
+ } else {
+ colors[i] = SkPackARGB32(0xFF, i, 0, 255-i);
+ }
+ }
+ SkColorTable* ctable = new SkColorTable(colors, 256);
+ bm->allocPixels(ctable);
+ ctable->unref();
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ *bm->getAddr8(x, y) = SkGetPackedR32(*device.getAddr32(x, y));
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+// configs to build the original bitmap in. Can be at most these 3
+static const SkBitmap::Config gConfigs[] = {
+ SkBitmap::kARGB_8888_Config,
+ SkBitmap::kRGB_565_Config,
+ SkBitmap::kIndex8_Config, // opaque
+ SkBitmap::kIndex8_Config // alpha
+};
+
+static const char* const gConfigLabels[] = {
+ "8888", "565", "Index8", "Index8 alpha"
+};
+
+// types to encode into. Can be at most these 3. Must match up with gExt[]
+static const SkImageEncoder::Type gTypes[] = {
+ SkImageEncoder::kJPEG_Type,
+ SkImageEncoder::kPNG_Type
+};
+
+// must match up with gTypes[]
+static const char* const gExt[] = {
+ ".jpg", ".png"
+};
+
+static const char* gPath = "/encoded/";
+
+static void make_name(SkString* name, int config, int ext) {
+ name->set(gPath);
+ name->append(gConfigLabels[config]);
+ name->append(gExt[ext]);
+}
+
+#include <sys/stat.h>
+
+class EncodeView : public SampleView {
+public:
+ SkBitmap* fBitmaps;
+ size_t fBitmapCount;
+
+ EncodeView() {
+ #if 1
+ (void)mkdir(gPath, S_IRWXU | S_IRWXG | S_IRWXO);
+
+ fBitmapCount = SK_ARRAY_COUNT(gConfigs);
+ fBitmaps = new SkBitmap[fBitmapCount];
+ for (size_t i = 0; i < fBitmapCount; i++) {
+ make_image(&fBitmaps[i], gConfigs[i], i);
+
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gExt); j++) {
+ SkString path;
+ make_name(&path, i, j);
+
+ // remove any previous run of this file
+ remove(path.c_str());
+
+ SkImageEncoder* codec = SkImageEncoder::Create(gTypes[j]);
+ if (NULL == codec ||
+ !codec->encodeFile(path.c_str(), fBitmaps[i], 100)) {
+ SkDebugf("------ failed to encode %s\n", path.c_str());
+ remove(path.c_str()); // remove any partial file
+ }
+ delete codec;
+ }
+ }
+ #else
+ fBitmaps = NULL;
+ fBitmapCount = 0;
+ #endif
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+ virtual ~EncodeView() {
+ delete[] fBitmaps;
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "ImageEncoder");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ if (fBitmapCount == 0) {
+ return;
+ }
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setTextAlign(SkPaint::kCenter_Align);
+
+ canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
+
+ SkScalar x = 0, y = 0, maxX = 0;
+ const int SPACER = 10;
+
+ for (size_t i = 0; i < fBitmapCount; i++) {
+ canvas->drawText(gConfigLabels[i], strlen(gConfigLabels[i]),
+ x + SkIntToScalar(fBitmaps[i].width()) / 2, 0,
+ paint);
+ y = paint.getTextSize();
+
+ canvas->drawBitmap(fBitmaps[i], x, y);
+
+ SkScalar yy = y;
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gExt); j++) {
+ yy += SkIntToScalar(fBitmaps[i].height() + 10);
+
+ SkBitmap bm;
+ SkString name;
+
+ make_name(&name, i, j);
+
+ SkImageDecoder::DecodeFile(name.c_str(), &bm);
+ canvas->drawBitmap(bm, x, yy);
+ }
+
+ x += SkIntToScalar(fBitmaps[i].width() + SPACER);
+ if (x > maxX) {
+ maxX = x;
+ }
+ }
+
+ y = (paint.getTextSize() + SkIntToScalar(fBitmaps[0].height())) * 3 / 2;
+ x = maxX + SkIntToScalar(10);
+ paint.setTextAlign(SkPaint::kLeft_Align);
+
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gExt); j++) {
+ canvas->drawText(gExt[j], strlen(gExt[j]), x, y, paint);
+ y += SkIntToScalar(fBitmaps[0].height() + SPACER);
+ }
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ this->inval(NULL);
+ return this->INHERITED::onFindClickHandler(x, y);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new EncodeView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleExtractAlpha.cpp b/samplecode/SampleExtractAlpha.cpp
new file mode 100644
index 0000000..860272d
--- /dev/null
+++ b/samplecode/SampleExtractAlpha.cpp
@@ -0,0 +1,90 @@
+#include "SampleCode.h"
+#include "SkColorPriv.h"
+#include "SkGradientShader.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkUtils.h"
+
+static SkBitmap make_bitmap() {
+ SkBitmap bm;
+ SkColorTable* ctable = new SkColorTable(256);
+
+ SkPMColor* c = ctable->lockColors();
+ for (int i = 0; i < 256; i++) {
+ c[i] = SkPackARGB32(255 - i, 0, 0, 0);
+ }
+ ctable->unlockColors(true);
+ bm.setConfig(SkBitmap::kIndex8_Config, 256, 256);
+ bm.allocPixels(ctable);
+ ctable->unref();
+
+ bm.lockPixels();
+ const float cx = bm.width() * 0.5f;
+ const float cy = bm.height() * 0.5f;
+ for (int y = 0; y < bm.height(); y++) {
+ float dy = y - cy;
+ dy *= dy;
+ uint8_t* p = bm.getAddr8(0, y);
+ for (int x = 0; x < 256; x++) {
+ float dx = x - cx;
+ dx *= dx;
+ float d = (dx + dy) / (cx/2);
+ int id = (int)d;
+ if (id > 255) {
+ id = 255;
+ }
+ p[x] = id;
+ }
+ }
+ bm.unlockPixels();
+ return bm;
+}
+
+class ExtractAlphaView : public SampleView {
+ SkBitmap fBM8;
+ SkBitmap fBM32;
+ SkBitmap fBM4;
+public:
+ ExtractAlphaView() {
+ fBM8 = make_bitmap();
+ fBM8.copyTo(&fBM32, SkBitmap::kARGB_8888_Config);
+ fBM8.copyTo(&fBM4, SkBitmap::kARGB_4444_Config);
+
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "DitherBitmap");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+
+ SkMatrix matrix;
+ matrix.setScale(3.55f, 80.f);
+ canvas->setMatrix(matrix);
+
+ paint.setStrokeWidth(0.0588f);
+ canvas->drawLine(10, 5, 30, 4.8f, paint);
+
+ paint.setStrokeWidth(0.06f);
+ canvas->drawLine(20, 5, 40, 4.8f, paint);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new ExtractAlphaView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleFillType.cpp b/samplecode/SampleFillType.cpp
new file mode 100644
index 0000000..393c5f7
--- /dev/null
+++ b/samplecode/SampleFillType.cpp
@@ -0,0 +1,90 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkCornerPathEffect.h"
+#include "SkCullPoints.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+
+class FillTypeView : public SampleView {
+ SkPath fPath;
+public:
+ FillTypeView() {
+ const SkScalar radius = SkIntToScalar(45);
+ fPath.addCircle(SkIntToScalar(50), SkIntToScalar(50), radius);
+ fPath.addCircle(SkIntToScalar(100), SkIntToScalar(100), radius);
+
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "FillType");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void showPath(SkCanvas* canvas, int x, int y, SkPath::FillType ft,
+ SkScalar scale, const SkPaint& paint) {
+
+ const SkRect r = { 0, 0, SkIntToScalar(150), SkIntToScalar(150) };
+
+ canvas->save();
+ canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
+ canvas->clipRect(r);
+ canvas->drawColor(SK_ColorWHITE);
+ fPath.setFillType(ft);
+ canvas->translate(r.centerX(), r.centerY());
+ canvas->scale(scale, scale);
+ canvas->translate(-r.centerX(), -r.centerY());
+ canvas->drawPath(fPath, paint);
+ canvas->restore();
+ }
+
+ void showFour(SkCanvas* canvas, SkScalar scale, const SkPaint& paint) {
+ showPath(canvas, 0, 0, SkPath::kWinding_FillType,
+ scale, paint);
+ showPath(canvas, 200, 0, SkPath::kEvenOdd_FillType,
+ scale, paint);
+ showPath(canvas, 00, 200, SkPath::kInverseWinding_FillType,
+ scale, paint);
+ showPath(canvas, 200, 200, SkPath::kInverseEvenOdd_FillType,
+ scale, paint);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
+
+ SkPaint paint;
+ const SkScalar scale = SkIntToScalar(5)/4;
+
+ paint.setAntiAlias(false);
+ paint.setColor(0x8000FF00);
+
+ showFour(canvas, SK_Scalar1, paint);
+ canvas->translate(SkIntToScalar(450), 0);
+ showFour(canvas, scale, paint);
+
+ paint.setAntiAlias(true);
+
+ canvas->translate(SkIntToScalar(-450), SkIntToScalar(450));
+ showFour(canvas, SK_Scalar1, paint);
+ canvas->translate(SkIntToScalar(450), 0);
+ showFour(canvas, scale, paint);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new FillTypeView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleFilter.cpp b/samplecode/SampleFilter.cpp
new file mode 100644
index 0000000..a9089fa
--- /dev/null
+++ b/samplecode/SampleFilter.cpp
@@ -0,0 +1,138 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "Sk1DPathEffect.h"
+#include "SkCornerPathEffect.h"
+#include "SkPathMeasure.h"
+#include "SkRandom.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkDither.h"
+
+static void make_bm(SkBitmap* bm) {
+ const SkColor colors[] = {
+ SK_ColorRED, SK_ColorGREEN,
+ SK_ColorBLUE, SK_ColorWHITE
+ };
+ SkColorTable* ctable = new SkColorTable(colors, 4);
+ bm->setConfig(SkBitmap::kIndex8_Config, 2, 2);
+ bm->allocPixels(ctable);
+ ctable->unref();
+
+ *bm->getAddr8(0, 0) = 0;
+ *bm->getAddr8(1, 0) = 1;
+ *bm->getAddr8(0, 1) = 2;
+ *bm->getAddr8(1, 1) = 3;
+}
+
+static SkScalar draw_bm(SkCanvas* canvas, const SkBitmap& bm,
+ SkScalar x, SkScalar y, SkPaint* paint) {
+#if 1
+ canvas->drawBitmap(bm, x, y, paint);
+ return SkIntToScalar(bm.width()) * 5/4;
+#else
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->translate(x, y);
+
+ SkScalar w = SkIntToScalar(bm.width());
+ SkScalar h = SkIntToScalar(bm.height());
+ SkShader* s = SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+ paint->setShader(s)->unref();
+ canvas->drawRect(SkRect::MakeWH(w, h), *paint);
+ paint->setShader(NULL);
+ return w * 5/4;
+#endif
+}
+
+static SkScalar draw_set(SkCanvas* c, const SkBitmap& bm, SkScalar x, SkPaint* p) {
+ x += draw_bm(c, bm, x, 0, p);
+ p->setFilterBitmap(true);
+ x += draw_bm(c, bm, x, 0, p);
+ p->setDither(true);
+ return x + draw_bm(c, bm, x, 0, p);
+}
+
+static const char* gConfigNames[] = {
+ "unknown config",
+ "A1",
+ "A8",
+ "Index8",
+ "565",
+ "4444",
+ "8888"
+};
+
+static SkScalar draw_row(SkCanvas* canvas, const SkBitmap& bm) {
+ SkAutoCanvasRestore acr(canvas, true);
+
+ SkPaint paint;
+ SkScalar x = 0;
+ const int scale = 32;
+
+ paint.setAntiAlias(true);
+ const char* name = gConfigNames[bm.config()];
+ canvas->drawText(name, strlen(name), x, SkIntToScalar(bm.height())*scale*5/8,
+ paint);
+ canvas->translate(SkIntToScalar(48), 0);
+
+ canvas->scale(SkIntToScalar(scale), SkIntToScalar(scale));
+
+ x += draw_set(canvas, bm, 0, &paint);
+ paint.reset();
+ paint.setAlpha(0x80);
+ draw_set(canvas, bm, x, &paint);
+ return x * scale / 3;
+}
+
+class FilterView : public SampleView {
+public:
+ SkBitmap fBM8, fBM4444, fBM16, fBM32;
+
+ FilterView() {
+ make_bm(&fBM8);
+ fBM8.copyTo(&fBM4444, SkBitmap::kARGB_4444_Config);
+ fBM8.copyTo(&fBM16, SkBitmap::kRGB_565_Config);
+ fBM8.copyTo(&fBM32, SkBitmap::kARGB_8888_Config);
+
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Filter");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkScalar x = SkIntToScalar(10);
+ SkScalar y = SkIntToScalar(10);
+
+ canvas->translate(x, y);
+ y = draw_row(canvas, fBM8);
+ canvas->translate(0, y);
+ y = draw_row(canvas, fBM4444);
+ canvas->translate(0, y);
+ y = draw_row(canvas, fBM16);
+ canvas->translate(0, y);
+ draw_row(canvas, fBM32);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new FilterView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleFilter2.cpp b/samplecode/SampleFilter2.cpp
new file mode 100644
index 0000000..c1a16a8
--- /dev/null
+++ b/samplecode/SampleFilter2.cpp
@@ -0,0 +1,116 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+
+static const char* gNames[] = {
+ "/skimages/background_01.png"
+};
+
+class Filter2View : public SampleView {
+public:
+ SkBitmap* fBitmaps;
+ int fBitmapCount;
+ int fCurrIndex;
+
+ Filter2View() {
+ fBitmapCount = SK_ARRAY_COUNT(gNames)*2;
+ fBitmaps = new SkBitmap[fBitmapCount];
+
+ for (int i = 0; i < fBitmapCount/2; i++) {
+ SkImageDecoder::DecodeFile(gNames[i], &fBitmaps[i],
+ SkBitmap::kARGB_8888_Config,
+ SkImageDecoder::kDecodePixels_Mode, NULL);
+ }
+ for (int i = fBitmapCount/2; i < fBitmapCount; i++) {
+ SkImageDecoder::DecodeFile(gNames[i-fBitmapCount/2], &fBitmaps[i],
+ SkBitmap::kRGB_565_Config,
+ SkImageDecoder::kDecodePixels_Mode, NULL);
+ }
+ fCurrIndex = 0;
+
+ this->setBGColor(SK_ColorGRAY);
+ }
+
+ virtual ~Filter2View() {
+ delete[] fBitmaps;
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SkString str("Filter/Dither ");
+ str.append(gNames[fCurrIndex]);
+ SampleCode::TitleR(evt, str.c_str());
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ canvas->translate(SkIntToScalar(10), SkIntToScalar(50));
+
+ const SkScalar W = SkIntToScalar(fBitmaps[0].width() + 1);
+ const SkScalar H = SkIntToScalar(fBitmaps[0].height() + 1);
+ SkPaint paint;
+
+ const SkScalar scale = SkFloatToScalar(0.897917f);
+ canvas->scale(SK_Scalar1, scale);
+
+ for (int k = 0; k < 2; k++) {
+ paint.setFilterBitmap(k == 1);
+ for (int j = 0; j < 2; j++) {
+ paint.setDither(j == 1);
+ for (int i = 0; i < fBitmapCount; i++) {
+ SkScalar x = (k * fBitmapCount + j) * W;
+ SkScalar y = i * H;
+ x = SkIntToScalar(SkScalarRound(x));
+ y = SkIntToScalar(SkScalarRound(y));
+ canvas->drawBitmap(fBitmaps[i], x, y, &paint);
+ if (i == 0) {
+ SkPaint p;
+ p.setAntiAlias(true);
+ p.setTextAlign(SkPaint::kCenter_Align);
+ p.setTextSize(SkIntToScalar(18));
+ SkString s("dither=");
+ s.appendS32(paint.isDither());
+ s.append(" filter=");
+ s.appendS32(paint.isFilterBitmap());
+ canvas->drawText(s.c_str(), s.size(), x + W/2,
+ y - p.getTextSize(), p);
+ }
+ if (k+j == 2) {
+ SkPaint p;
+ p.setAntiAlias(true);
+ p.setTextSize(SkIntToScalar(18));
+ SkString s;
+ s.append(" depth=");
+ s.appendS32(fBitmaps[i].config() == SkBitmap::kRGB_565_Config ? 16 : 32);
+ canvas->drawText(s.c_str(), s.size(), x + W + SkIntToScalar(4),
+ y + H/2, p);
+ }
+ }
+ }
+ }
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new Filter2View; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleFontCache.cpp b/samplecode/SampleFontCache.cpp
new file mode 100644
index 0000000..0b8187a
--- /dev/null
+++ b/samplecode/SampleFontCache.cpp
@@ -0,0 +1,135 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGraphics.h"
+#include "SkRandom.h"
+
+#include <pthread.h>
+
+static void call_measure() {
+ SkPaint paint;
+ uint16_t text[32];
+ SkRandom rand;
+
+ paint.setAntiAlias(true);
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ for (int j = 0; j < SK_ARRAY_COUNT(text); j++)
+ text[j] = (uint16_t)((rand.nextU() & 0xFF) + 32);
+
+ for (int i = 9; i < 36; i++) {
+ SkPaint::FontMetrics m;
+
+ paint.setTextSize(SkIntToScalar(i));
+ paint.getFontMetrics(&m);
+ paint.measureText(text, sizeof(text));
+ }
+}
+
+static void call_draw(SkCanvas* canvas) {
+ SkPaint paint;
+ uint16_t text[32];
+ SkRandom rand;
+
+ paint.setAntiAlias(true);
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ for (int j = 0; j < SK_ARRAY_COUNT(text); j++)
+ text[j] = (uint16_t)((rand.nextU() & 0xFF) + 32);
+
+ SkScalar x = SkIntToScalar(10);
+ SkScalar y = SkIntToScalar(20);
+
+ canvas->drawColor(SK_ColorWHITE);
+ for (int i = 9; i < 36; i++)
+ {
+ SkPaint::FontMetrics m;
+
+ paint.setTextSize(SkIntToScalar(i));
+ paint.getFontMetrics(&m);
+ canvas->drawText(text, sizeof(text), x, y, paint);
+ y += m.fDescent - m.fAscent;
+ }
+}
+
+static bool gDone;
+
+static void* measure_proc(void* context) {
+ while (!gDone) {
+ call_measure();
+ }
+ return NULL;
+}
+
+static void* draw_proc(void* context) {
+ SkBitmap* bm = (SkBitmap*)context;
+ SkCanvas canvas(*bm);
+
+ while (!gDone) {
+ call_draw(&canvas);
+ }
+ return NULL;
+}
+
+class FontCacheView : public SampleView {
+public:
+ enum { N = 4 };
+
+ pthread_t fMThreads[N];
+ pthread_t fDThreads[N];
+ SkBitmap fBitmaps[N];
+
+ FontCacheView() {
+ gDone = false;
+ for (int i = 0; i < N; i++) {
+ int status;
+
+ status = pthread_create(&fMThreads[i], NULL, measure_proc, NULL);
+ SkASSERT(0 == status);
+
+ fBitmaps[i].setConfig(SkBitmap::kRGB_565_Config, 320, 240);
+ fBitmaps[i].allocPixels();
+ status = pthread_create(&fDThreads[i], NULL, draw_proc, &fBitmaps[i]);
+ SkASSERT(0 == status);
+ }
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+ virtual ~FontCacheView() {
+ gDone = true;
+ for (int i = 0; i < N; i++) {
+ void* ret;
+ int status = pthread_join(fMThreads[i], &ret);
+ SkASSERT(0 == status);
+ status = pthread_join(fDThreads[i], &ret);
+ SkASSERT(0 == status);
+ }
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "FontCache");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkScalar x = 0;
+ SkScalar y = 0;
+ for (int i = 0; i < N; i++) {
+ canvas->drawBitmap(fBitmaps[i], x, y);
+ x += SkIntToScalar(fBitmaps[i].width());
+ }
+ this->inval(NULL);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new FontCacheView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleFontScalerTest.cpp b/samplecode/SampleFontScalerTest.cpp
new file mode 100644
index 0000000..0b0d349
--- /dev/null
+++ b/samplecode/SampleFontScalerTest.cpp
@@ -0,0 +1,117 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkTypeface.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "Sk1DPathEffect.h"
+#include "SkCornerPathEffect.h"
+#include "SkPathMeasure.h"
+#include "SkRandom.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkDither.h"
+
+static const struct {
+ const char* fName;
+ SkTypeface::Style fStyle;
+} gFaces[] = {
+ { NULL, SkTypeface::kNormal },
+ { NULL, SkTypeface::kBold },
+ { "serif", SkTypeface::kNormal },
+ { "serif", SkTypeface::kBold },
+ { "serif", SkTypeface::kItalic },
+ { "serif", SkTypeface::kBoldItalic },
+ { "monospace", SkTypeface::kNormal }
+};
+
+static const int gFaceCount = SK_ARRAY_COUNT(gFaces);
+
+class FontScalerTestView : public SampleView {
+ SkTypeface* fFaces[gFaceCount];
+
+public:
+ FontScalerTestView() {
+ for (int i = 0; i < gFaceCount; i++) {
+ fFaces[i] = SkTypeface::CreateFromName(gFaces[i].fName,
+ gFaces[i].fStyle);
+ }
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+ virtual ~FontScalerTestView() {
+ for (int i = 0; i < gFaceCount; i++) {
+ SkSafeUnref(fFaces[i]);
+ }
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "FontScaler Test");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+
+ // test handling of obscene cubic values (currently broken)
+ if (false) {
+ SkPoint pts[4];
+ pts[0].set(1.61061274e+09f, 6291456);
+ pts[1].set(-7.18397061e+15f, -1.53091184e+13f);
+ pts[2].set(-1.30077315e+16f, -2.77196141e+13f);
+ pts[3].set(-1.30077315e+16f, -2.77196162e+13f);
+
+ SkPath path;
+ path.moveTo(pts[0]);
+ path.cubicTo(pts[1], pts[2], pts[3]);
+ canvas->drawPath(path, paint);
+ }
+
+ canvas->translate(200, 20);
+ canvas->rotate(30);
+
+ paint.setAntiAlias(true);
+ paint.setLCDRenderText(true);
+ SkSafeUnref(paint.setTypeface(SkTypeface::CreateFromName("Times Roman", SkTypeface::kNormal)));
+
+// const char* text = "abcdefghijklmnopqrstuvwxyz";
+ const char* text = "HnHnHnHnHnHnHnHnH";
+ size_t textLen = strlen(text);
+
+ SkScalar x = SkIntToScalar(10);
+ SkScalar y = SkIntToScalar(20);
+
+ {
+ SkPaint p;
+ p.setColor(SK_ColorRED);
+ SkRect r;
+ r.set(0, 0, x, y*20);
+ canvas->drawRect(r, p);
+ }
+
+ int index = 0;
+ for (int ps = 9; ps <= 24; ps++) {
+ textLen = strlen(text);
+ paint.setTextSize(SkIntToScalar(ps));
+ canvas->drawText(text, textLen, x, y, paint);
+ y += paint.getFontMetrics(NULL);
+ index += 1;
+ }
+ }
+
+private:
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new FontScalerTestView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleFuzz.cpp b/samplecode/SampleFuzz.cpp
new file mode 100644
index 0000000..5c41886
--- /dev/null
+++ b/samplecode/SampleFuzz.cpp
@@ -0,0 +1,363 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkBlurMaskFilter.h"
+#include "SkPaint.h"
+#include "SkPath.h"
+#include "SkXfermode.h"
+#include "SkMatrix.h"
+#include "SkColor.h"
+#include "SkRandom.h"
+
+static void set2x3(SkMatrix* m, float a, float b, float c, float d, float e, float f) {
+ m->reset();
+ m->set(0, a);
+ m->set(1, b);
+ m->set(2, c);
+ m->set(3, d);
+ m->set(4, e);
+ m->set(5, f);
+}
+
+static SkRandom gRand;
+static bool return_large;
+static bool return_undef;
+static bool quick;
+static bool scale_large;
+static int scval = 1;
+static float transval = 0;
+
+static int R(float x) {
+ return (int)floor(SkScalarToFloat(gRand.nextUScalar1()) * x);
+}
+
+static float huge() {
+ double d = 1e100;
+ float f = (float)d;
+ return f;
+}
+
+static float make_number() {
+ float v;
+ int sel;
+
+ if (return_large == true && R(3) == 1) sel = R(6); else sel = R(4);
+ if (return_undef == false && sel == 0) sel = 1;
+
+ if (R(2) == 1) v = (float)R(100); else
+
+ switch (sel) {
+ case 0: break;
+ case 1: v = 0; break;
+ case 2: v = 0.000001f; break;
+ case 3: v = 10000; break;
+ case 4: v = 2000000000; break;
+ case 5: v = huge(); break;
+ }
+
+ if (R(4) == 1) v = -v;
+ return v;
+}
+
+static SkColor make_color() {
+ if (R(2) == 1) return 0xFFC0F0A0; else return 0xFF000090;
+}
+
+
+static SkColor make_fill() {
+#if 0
+ int sel;
+
+ if (quick == true) sel = 0; else sel = R(6);
+
+ switch (sel) {
+
+ case 0:
+ case 1:
+ case 2:
+ return make_color();
+ break;
+
+ case 3:
+ var r = ctx.createLinearGradient(make_number(),make_number(),make_number(),make_number());
+ for (i=0;i<4;i++)
+ r.addColorStop(make_number(),make_color());
+ return r;
+ break;
+
+ case 4:
+ var r = ctx.createRadialGradient(make_number(),make_number(),make_number(),make_number(),make_number(),make_number());
+ for (i=0;i<4;i++)
+ r.addColorStop(make_number(),make_color());
+ return r;
+ break;
+
+ case 5:
+ var r = ctx.createPattern(imgObj,"repeat");
+ if (R(6) == 0)
+ r.addColorStop(make_number(),make_color());
+ return r;
+ break;
+ }
+#else
+ return make_color();
+#endif
+}
+
+
+static void do_fuzz(SkCanvas* canvas) {
+ SkPath path;
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ for (int i=0;i<100;i++) {
+ switch (R(33)) {
+
+ case 0:
+ paint.setColor(make_fill());
+ break;
+
+ case 1:
+ paint.setAlpha(gRand.nextU() & 0xFF);
+ break;
+
+ case 2: {
+ SkXfermode::Mode mode;
+ switch (R(3)) {
+ case 0: mode = SkXfermode::kSrc_Mode; break;
+ case 1: mode = SkXfermode::kXor_Mode; break;
+ case 2: mode = SkXfermode::kSrcOver_Mode; break;
+ }
+ paint.setXfermodeMode(mode);
+ }
+ break;
+
+ case 3:
+ switch (R(2)) {
+ case 0: paint.setStrokeCap(SkPaint::kRound_Cap); break;
+ case 1: paint.setStrokeCap(SkPaint::kButt_Cap); break;
+ }
+ break;
+
+ case 4:
+ switch (R(2)) {
+ case 0: paint.setStrokeJoin(SkPaint::kRound_Join); break;
+ case 1: paint.setStrokeJoin(SkPaint::kMiter_Join); break;
+ }
+ break;
+
+ case 5:
+ paint.setStrokeWidth(make_number());
+ break;
+
+ case 6:
+ paint.setStrokeMiter(make_number());
+ break;
+
+ case 7:
+ if (quick == true) break;
+ SkSafeUnref(paint.setMaskFilter(SkBlurMaskFilter::Create(make_number(), SkBlurMaskFilter::kNormal_BlurStyle)));
+ break;
+
+ case 8:
+ if (quick == true) break;
+ //ctx.shadowColor = make_fill();
+ break;
+
+ case 9:
+ if (quick == true) break;
+ //ctx.shadowOffsetX = make_number();
+ //ctx.shadowOffsetY = make_number();
+ break;
+
+ case 10:
+ canvas->restore();
+ break;
+
+ case 11:
+ canvas->rotate(make_number());
+ break;
+
+ case 12:
+ canvas->save();
+ break;
+
+ case 13:
+ canvas->scale(-1,-1);
+ break;
+
+ case 14:
+
+ if (quick == true) break;
+
+ if (transval == 0) {
+ transval = make_number();
+ canvas->translate(transval,0);
+ } else {
+ canvas->translate(-transval,0);
+ transval = 0;
+ }
+
+ break;
+
+ case 15: {
+ SkRect r;
+ r.set(make_number(),make_number(),make_number(),make_number());
+ SkPaint::Style s = paint.getStyle();
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas->drawRect(r, paint);
+ paint.setStyle(s);
+ // clearrect
+ } break;
+
+ case 16:
+ if (quick == true) break;
+// ctx.drawImage(imgObj,make_number(),make_number(),make_number(),make_number(),make_number(),make_number(),make_number(),make_number());
+ break;
+
+ case 17: {
+ SkRect r;
+ r.set(make_number(),make_number(),make_number(),make_number());
+ SkPaint::Style s = paint.getStyle();
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas->drawRect(r, paint);
+ paint.setStyle(s);
+ } break;
+
+ case 18:
+ path.reset();
+ break;
+
+ case 19:
+ // ctx.clip() is evil.
+ break;
+
+ case 20:
+ path.close();
+ break;
+
+ case 21: {
+ SkPaint::Style s = paint.getStyle();
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas->drawPath(path, paint);
+ paint.setStyle(s);
+ } break;
+
+ case 22: {
+ SkPaint::Style s = paint.getStyle();
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas->drawPath(path, paint);
+ paint.setStyle(s);
+ } break;
+
+ case 23: {
+ SkRect r;
+ r.set(make_number(),make_number(),make_number(),make_number());
+ SkPaint::Style s = paint.getStyle();
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawRect(r, paint);
+ paint.setStyle(s);
+ } break;
+
+ case 24:
+ if (quick == true) break;
+ //ctx.arc(make_number(),make_number(),make_number(),make_number(),make_number(),true);
+ break;
+
+ case 25:
+ if (quick == true) break;
+ //ctx.arcTo(make_number(),make_number(),make_number(),make_number(),make_number());
+ break;
+
+ case 26:
+ if (quick == true) break;
+ //ctx.bezierCurveTo(make_number(),make_number(),make_number(),make_number(),make_number(),make_number());
+ break;
+
+ case 27:
+ path.lineTo(make_number(),make_number());
+ break;
+
+ case 28:
+ path.moveTo(make_number(),make_number());
+ break;
+
+ case 29:
+ if (quick == true) break;
+ path.quadTo(make_number(),make_number(),make_number(),make_number());
+ break;
+
+ case 30: {
+ if (quick == true) break;
+ SkMatrix matrix;
+ set2x3(&matrix, make_number(),make_number(),make_number(),make_number(),make_number(),make_number());
+ canvas->concat(matrix);
+ } break;
+
+ case 31: {
+ if (quick == true) break;
+ SkMatrix matrix;
+ set2x3(&matrix, make_number(),make_number(),make_number(),make_number(),make_number(),make_number());
+ canvas->setMatrix(matrix);
+ } break;
+
+ case 32:
+
+ if (scale_large == true) {
+
+ switch (scval) {
+ case 0: canvas->scale(-1000000000,1);
+ canvas->scale(-1000000000,1);
+ scval = 1; break;
+ case 1: canvas->scale(-.000000001f,1); scval = 2; break;
+ case 2: canvas->scale(-.000000001f,1); scval = 0; break;
+ }
+
+ }
+
+ break;
+
+
+
+ }
+ }
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+class FuzzView : public SampleView {
+public:
+ FuzzView() {
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Fuzzer");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(0xFFDDDDDD);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkIRect r = canvas->getTotalClip().getBounds();
+ do_fuzz(canvas);
+ this->inval(NULL);
+ }
+
+private:
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new FuzzView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleGM.cpp b/samplecode/SampleGM.cpp
new file mode 100644
index 0000000..ec5b22a
--- /dev/null
+++ b/samplecode/SampleGM.cpp
@@ -0,0 +1,114 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+
+#include "gm.h"
+
+using namespace skiagm;
+
+// need to explicitly declare this, or we get some weird infinite loop llist
+template GMRegistry* GMRegistry::gHead;
+
+class Iter {
+public:
+ Iter() {
+ fReg = GMRegistry::Head();
+ }
+
+ void reset() {
+ fReg = GMRegistry::Head();
+ }
+
+ GM* next() {
+ if (fReg) {
+ GMRegistry::Factory fact = fReg->factory();
+ fReg = fReg->next();
+ return fact(0);
+ }
+ return NULL;
+ }
+
+ static int Count() {
+ const GMRegistry* reg = GMRegistry::Head();
+ int count = 0;
+ while (reg) {
+ count += 1;
+ reg = reg->next();
+ }
+ return count;
+ }
+
+private:
+ const GMRegistry* fReg;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GMView : public SampleView {
+ Iter fIter;
+ GM* fGM;
+public:
+ GMView() {
+ fGM = fIter.next();
+ this->postNextGM();
+
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+ virtual ~GMView() {
+ delete fGM;
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "GM");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual bool onEvent(const SkEvent& evt) {
+ if (evt.isType("next-gm")) {
+ delete fGM;
+ if (!(fGM = fIter.next())) {
+ fIter.reset();
+ fGM = fIter.next();
+ }
+ this->inval(NULL);
+ this->postNextGM();
+ return true;
+ }
+ return this->INHERITED::onEvent(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ fGM->draw(canvas);
+ }
+
+private:
+ void postNextGM() {
+ (new SkEvent("next-gm"))->post(this->getSinkID(), 1500);
+ }
+
+ typedef SampleView INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new GMView; }
+static SkViewRegister reg(MyFactory);
+
+///////////////////////////////////////////////////////////////////////////////
+
+using namespace skiagm;
+
+GM::GM() {}
+GM::~GM() {}
+
+void GM::draw(SkCanvas* canvas) {
+ this->onDraw(canvas);
+}
+
+
diff --git a/samplecode/SampleGradients.cpp b/samplecode/SampleGradients.cpp
new file mode 100644
index 0000000..902b0bd
--- /dev/null
+++ b/samplecode/SampleGradients.cpp
@@ -0,0 +1,176 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+
+static SkShader* setgrad(const SkRect& r, SkColor c0, SkColor c1) {
+ SkColor colors[] = { c0, c1 };
+ SkPoint pts[] = { { r.fLeft, r.fTop }, { r.fRight, r.fTop } };
+ return SkGradientShader::CreateLinear(pts, colors, NULL, 2,
+ SkShader::kClamp_TileMode, NULL);
+}
+
+static void test_alphagradients(SkCanvas* canvas) {
+ SkRect r;
+ r.set(SkIntToScalar(10), SkIntToScalar(10),
+ SkIntToScalar(410), SkIntToScalar(30));
+ SkPaint p, p2;
+ p2.setStyle(SkPaint::kStroke_Style);
+
+ p.setShader(setgrad(r, 0xFF00FF00, 0x0000FF00))->unref();
+ canvas->drawRect(r, p);
+ canvas->drawRect(r, p2);
+
+ r.offset(0, r.height() + SkIntToScalar(4));
+ p.setShader(setgrad(r, 0xFF00FF00, 0x00000000))->unref();
+ canvas->drawRect(r, p);
+ canvas->drawRect(r, p2);
+
+ r.offset(0, r.height() + SkIntToScalar(4));
+ p.setShader(setgrad(r, 0xFF00FF00, 0x00FF0000))->unref();
+ canvas->drawRect(r, p);
+ canvas->drawRect(r, p2);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+struct GradData {
+ int fCount;
+ const SkColor* fColors;
+ const SkScalar* fPos;
+};
+
+static const SkColor gColors[] = {
+ SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
+};
+static const SkScalar gPos0[] = { 0, SK_Scalar1 };
+static const SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
+static const SkScalar gPos2[] = {
+ 0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1
+};
+
+static const GradData gGradData[] = {
+ { 2, gColors, NULL },
+ { 2, gColors, gPos0 },
+ { 2, gColors, gPos1 },
+ { 5, gColors, NULL },
+ { 5, gColors, gPos2 }
+};
+
+static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, SkUnitMapper* mapper) {
+ return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
+ data.fCount, tm, mapper);
+}
+
+static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, SkUnitMapper* mapper) {
+ SkPoint center;
+ center.set(SkScalarAve(pts[0].fX, pts[1].fX),
+ SkScalarAve(pts[0].fY, pts[1].fY));
+ return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
+ data.fPos, data.fCount, tm, mapper);
+}
+
+static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, SkUnitMapper* mapper) {
+ SkPoint center;
+ center.set(SkScalarAve(pts[0].fX, pts[1].fX),
+ SkScalarAve(pts[0].fY, pts[1].fY));
+ return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
+ data.fPos, data.fCount, mapper);
+}
+
+static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, SkUnitMapper* mapper) {
+ SkPoint center0, center1;
+ center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
+ SkScalarAve(pts[0].fY, pts[1].fY));
+ center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
+ SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
+ return SkGradientShader::CreateTwoPointRadial(
+ center1, (pts[1].fX - pts[0].fX) / 7,
+ center0, (pts[1].fX - pts[0].fX) / 2,
+ data.fColors, data.fPos, data.fCount, tm, mapper);
+}
+
+static SkShader* Make2RadialConcentric(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, SkUnitMapper* mapper) {
+ SkPoint center;
+ center.set(SkScalarAve(pts[0].fX, pts[1].fX),
+ SkScalarAve(pts[0].fY, pts[1].fY));
+ return SkGradientShader::CreateTwoPointRadial(
+ center, (pts[1].fX - pts[0].fX) / 7,
+ center, (pts[1].fX - pts[0].fX) / 2,
+ data.fColors, data.fPos, data.fCount, tm, mapper);
+}
+
+typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, SkUnitMapper* mapper);
+static const GradMaker gGradMakers[] = {
+ MakeLinear, MakeRadial, MakeSweep, Make2Radial, Make2RadialConcentric
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GradientsView : public SampleView {
+public:
+ GradientsView() {
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Gradients");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPoint pts[2] = {
+ { 0, 0 },
+ { SkIntToScalar(100), SkIntToScalar(100) }
+ };
+ SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
+ SkPaint paint;
+ paint.setDither(true);
+
+ canvas->save();
+ canvas->translate(SkIntToScalar(20), SkIntToScalar(10));
+
+ for (int tm = 0; tm < SkShader::kTileModeCount; ++tm) {
+ canvas->save();
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
+ canvas->save();
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); j++) {
+ SkShader* shader;
+ shader = gGradMakers[j](pts, gGradData[i], (SkShader::TileMode)tm, NULL);
+ paint.setShader(shader)->unref();
+ canvas->drawRect(r, paint);
+ canvas->translate(0, SkIntToScalar(120));
+ }
+ canvas->restore();
+ canvas->translate(SkIntToScalar(120), 0);
+ }
+ canvas->restore();
+ canvas->translate(SK_ARRAY_COUNT(gGradData)*SkIntToScalar(120), 0);
+ }
+ canvas->restore();
+
+ canvas->translate(0, SkIntToScalar(370));
+ // test_alphagradients(canvas);
+ this->inval(NULL);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new GradientsView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleHairline.cpp b/samplecode/SampleHairline.cpp
new file mode 100644
index 0000000..8368f5b
--- /dev/null
+++ b/samplecode/SampleHairline.cpp
@@ -0,0 +1,272 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "Sk64.h"
+#include "SkCornerPathEffect.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkKernel33MaskFilter.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 test_chromium_9005() {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, 800, 600);
+ bm.allocPixels();
+
+ SkCanvas canvas(bm);
+
+ SkPoint pt0 = { SkFloatToScalar(799.33374f), SkFloatToScalar(1.2360189f) };
+ SkPoint pt1 = { SkFloatToScalar(808.49969f), SkFloatToScalar(-7.4338055f) };
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ canvas.drawLine(pt0.fX, pt0.fY, pt1.fX, pt1.fY, paint);
+}
+
+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(), rb >> 2)) {
+ return false;
+ }
+ int right = bm.width() - margin + i;
+ if (!check_zeros(bm.getAddr32(right, 0), bm.height(), 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() {
+ fCounter = 0;
+ fProcIndex = 0;
+ fDoAA = true;
+ fNow = 0;
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ 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);
+ }
+
+ int fCounter;
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ gRand.setSeed(fNow);
+
+ if (false) {
+ test_chromium_9005();
+ }
+
+ SkBitmap bm, bm2;
+ bm.setConfig(SkBitmap::kARGB_8888_Config,
+ WIDTH + MARGIN*2,
+ HEIGHT + MARGIN*2);
+ bm.allocPixels();
+ // this will erase our margin, which we want to always stay 0
+ bm.eraseColor(0);
+
+ bm2.setConfig(SkBitmap::kARGB_8888_Config, WIDTH, HEIGHT,
+ bm.rowBytes());
+ bm2.setPixels(bm.getAddr32(MARGIN, MARGIN));
+
+ SkCanvas c2(bm2);
+ SkPaint paint;
+ paint.setAntiAlias(fDoAA);
+ paint.setStyle(SkPaint::kStroke_Style);
+
+ bm2.eraseColor(0);
+ gProcs[fProcIndex].fProc(&c2, paint, bm);
+ canvas->drawBitmap(bm2, SkIntToScalar(10), SkIntToScalar(10), NULL);
+
+ SkMSec now = SampleCode::GetAnimTime();
+ if (fNow != now) {
+ fNow = now;
+ fCounter += 1;
+ fDoAA = !fDoAA;
+ if (fCounter > 50) {
+ fProcIndex = cycle_hairproc_index(fProcIndex);
+ // todo: signal that we want to rebuild our TITLE
+ fCounter = 0;
+ }
+ this->inval(NULL);
+ }
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ fDoAA = !fDoAA;
+ this->inval(NULL);
+ return this->INHERITED::onFindClickHandler(x, y);
+ }
+
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new HairlineView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleImage.cpp b/samplecode/SampleImage.cpp
new file mode 100644
index 0000000..2944299
--- /dev/null
+++ b/samplecode/SampleImage.cpp
@@ -0,0 +1,156 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+
+#include "SkImageRef_GlobalPool.h"
+#include "SkStream.h"
+
+static const char* gNames[] = {
+ "1.bmp", "1.gif", "1.jpg", "1.png",
+ "2.bmp", "2.gif", "2.jpg", "2.png"
+};
+
+static bool SetImageRef(SkBitmap* bitmap, SkStream* stream,
+ SkBitmap::Config pref, const char name[] = NULL)
+{
+ if (SkImageDecoder::DecodeStream(stream, bitmap, pref,
+ SkImageDecoder::kDecodeBounds_Mode, NULL)) {
+ SkASSERT(bitmap->config() != SkBitmap::kNo_Config);
+
+ SkImageRef* ref = new SkImageRef_GlobalPool(stream, bitmap->config());
+ ref->setURI(name);
+ bitmap->setPixelRef(ref)->unref();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+class ImageView : public SkView {
+public:
+ SkBitmap* fBitmaps;
+ SkShader* fShader;
+
+ ImageView() {
+ SkImageRef_GlobalPool::SetRAMBudget(32 * 1024);
+
+ int i, N = SK_ARRAY_COUNT(gNames);
+ fBitmaps = new SkBitmap[N];
+
+ for (i = 0; i < N; i++) {
+ SkString str("/skimages/");
+ str.append(gNames[i]);
+ SkFILEStream* stream = new SkFILEStream(str.c_str());
+
+ SetImageRef(&fBitmaps[i], stream, SkBitmap::kNo_Config, gNames[i]);
+ if (i & 1)
+ fBitmaps[i].buildMipMap();
+ stream->unref();
+ }
+
+ fShader = SkShader::CreateBitmapShader(fBitmaps[5],
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+
+ if (true) {
+ SkMatrix m;
+
+ m.setRotate(SkIntToScalar(30));
+ fShader->setLocalMatrix(m);
+ }
+
+#if 0
+ SkImageRef::DumpPool();
+ for (i = 0; i < N; i++) {
+ SkBitmap& bm = fBitmaps[i];
+
+ SkDebugf("<%s> addr=%p", gNames[i], bm.getPixels());
+ bool success = bm.lockPixels();
+ SkDebugf(" addr=%d", bm.getPixels());
+ if (success)
+ bm.unlockPixels();
+ SkDebugf(" addr=%p", bm.getPixels());
+ success = bm.lockPixels();
+ SkDebugf(" addr=%d", bm.getPixels());
+ if (success)
+ bm.unlockPixels();
+ SkDebugf("\n");
+ }
+ SkImageRef::DumpPool();
+#endif
+ }
+
+ virtual ~ImageView() {
+ delete[] fBitmaps;
+ delete fShader;
+
+ SkImageRef_GlobalPool::DumpPool();
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Image");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(0xFFDDDDDD);
+// canvas->drawColor(SK_ColorWHITE);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ this->drawBG(canvas);
+
+ canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
+
+ SkScalar x = 0, y = 0;
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); i++) {
+ canvas->drawBitmap(fBitmaps[i], x, y);
+ x += SkIntToScalar(fBitmaps[i].width() + 10);
+ }
+
+ canvas->translate(0, SkIntToScalar(120));
+
+ SkPaint paint;
+ paint.setShader(fShader);
+ paint.setFilterBitmap(true);
+ SkRect r = { 0, 0, SkIntToScalar(300), SkIntToScalar(100) };
+
+ canvas->drawRect(r, paint);
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ this->inval(NULL);
+ return this->INHERITED::onFindClickHandler(x, y);
+ }
+
+ virtual bool onClick(Click* click) {
+ return this->INHERITED::onClick(click);
+ }
+
+private:
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new ImageView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleImageDir.cpp b/samplecode/SampleImageDir.cpp
new file mode 100644
index 0000000..8ef59ad
--- /dev/null
+++ b/samplecode/SampleImageDir.cpp
@@ -0,0 +1,310 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkComposeShader.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+
+#include "SkImageRef_GlobalPool.h"
+#include "SkOSFile.h"
+#include "SkStream.h"
+
+#include "SkBlurDrawLooper.h"
+#include "SkColorMatrixFilter.h"
+
+static void drawmarshmallow(SkCanvas* canvas) {
+ SkBitmap bitmap;
+ SkPaint paint;
+ SkRect r;
+ SkMatrix m;
+
+ SkImageDecoder::DecodeFile("/Users/reed/Downloads/3elfs.jpg", &bitmap);
+ SkShader* s = SkShader::CreateBitmapShader(bitmap,
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+ paint.setShader(s)->unref();
+ m.setTranslate(SkIntToScalar(250), SkIntToScalar(134));
+ s->setLocalMatrix(m);
+
+ r.set(SkIntToScalar(250),
+ SkIntToScalar(134),
+ SkIntToScalar(250 + 449),
+ SkIntToScalar(134 + 701));
+ paint.setFlags(2);
+
+ canvas->drawRect(r, paint);
+}
+
+static void DrawRoundRect(SkCanvas& canvas) {
+ bool ret = false;
+ SkPaint paint;
+ SkBitmap bitmap;
+ SkMatrix matrix;
+ matrix.reset();
+
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1370, 812);
+ bitmap.allocPixels();
+#if 0
+ SkCanvas canvas;
+ canvas.setBitmapDevice(bitmap);
+#endif
+
+ // set up clipper
+ SkRect skclip;
+ skclip.set(SkIntToFixed(284), SkIntToFixed(40), SkIntToFixed(1370), SkIntToFixed(708));
+
+// ret = canvas.clipRect(skclip);
+// SkASSERT(ret);
+
+ matrix.set(SkMatrix::kMTransX, SkFloatToFixed(-1153.28));
+ matrix.set(SkMatrix::kMTransY, SkFloatToFixed(1180.50));
+
+ matrix.set(SkMatrix::kMScaleX, SkFloatToFixed(0.177171));
+ matrix.set(SkMatrix::kMScaleY, SkFloatToFixed(0.177043));
+
+ matrix.set(SkMatrix::kMSkewX, SkFloatToFixed(0.126968));
+ matrix.set(SkMatrix::kMSkewY, SkFloatToFixed(-0.126876));
+
+ matrix.set(SkMatrix::kMPersp0, SkFloatToFixed(0.0));
+ matrix.set(SkMatrix::kMPersp1, SkFloatToFixed(0.0));
+
+ ret = canvas.concat(matrix);
+
+ paint.setAntiAlias(true);
+ paint.setColor(0xb2202020);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkFloatToFixed(68.13));
+
+ SkRect r;
+ r.set(SkFloatToFixed(-313.714417), SkFloatToFixed(-4.826389), SkFloatToFixed(18014.447266), SkFloatToFixed(1858.154541));
+ canvas.drawRoundRect(r, SkFloatToFixed(91.756363), SkFloatToFixed(91.756363), paint);
+}
+
+static bool SetImageRef(SkBitmap* bitmap, SkStream* stream,
+ SkBitmap::Config pref, const char name[] = NULL) {
+#if 0
+ // test buffer streams
+ SkStream* str = new SkBufferStream(stream, 717);
+ stream->unref();
+ stream = str;
+#endif
+
+ SkImageRef* ref = new SkImageRef_GlobalPool(stream, pref, 1);
+ ref->setURI(name);
+ if (!ref->getInfo(bitmap)) {
+ delete ref;
+ return false;
+ }
+ bitmap->setPixelRef(ref)->unref();
+ return true;
+}
+
+//#define SPECIFIC_IMAGE "/skimages/72.jpg"
+#define SPECIFIC_IMAGE "/Users/reed/Downloads/3elfs.jpg"
+
+#define IMAGE_DIR "/skimages/"
+#define IMAGE_SUFFIX ".gif"
+
+class ImageDirView : public SkView {
+public:
+ SkBitmap* fBitmaps;
+ SkString* fStrings;
+ int fBitmapCount;
+ int fCurrIndex;
+ SkScalar fSaturation;
+ SkScalar fAngle;
+
+ ImageDirView() {
+ SkImageRef_GlobalPool::SetRAMBudget(320 * 1024);
+
+#ifdef SPECIFIC_IMAGE
+ fBitmaps = new SkBitmap[3];
+ fStrings = new SkString[3];
+ fBitmapCount = 3;
+ const SkBitmap::Config configs[] = {
+ SkBitmap::kARGB_8888_Config,
+ SkBitmap::kRGB_565_Config,
+ SkBitmap::kARGB_4444_Config
+ };
+ for (int i = 0; i < fBitmapCount; i++) {
+#if 1
+ SkStream* stream = new SkFILEStream(SPECIFIC_IMAGE);
+ SetImageRef(&fBitmaps[i], stream, configs[i], SPECIFIC_IMAGE);
+ stream->unref();
+#else
+ SkImageDecoder::DecodeFile(SPECIFIC_IMAGE, &fBitmaps[i]);
+#endif
+ }
+#else
+ int i, N = 0;
+ SkOSFile::Iter iter(IMAGE_DIR, IMAGE_SUFFIX);
+ SkString name;
+ while (iter.next(&name)) {
+ N += 1;
+ }
+ fBitmaps = new SkBitmap[N];
+ fStrings = new SkString[N];
+ iter.reset(IMAGE_DIR, IMAGE_SUFFIX);
+ for (i = 0; i < N; i++) {
+ iter.next(&name);
+ SkString path(IMAGE_DIR);
+ path.append(name);
+ SkStream* stream = new SkFILEStream(path.c_str());
+
+ SetImageRef(&fBitmaps[i], stream, SkBitmap::kNo_Config,
+ name.c_str());
+ stream->unref();
+ fStrings[i] = name;
+ }
+ fBitmapCount = N;
+#endif
+ fCurrIndex = 0;
+ fDX = fDY = 0;
+
+ fSaturation = SK_Scalar1;
+ fAngle = 0;
+
+ fScale = SK_Scalar1;
+ }
+
+ virtual ~ImageDirView() {
+ delete[] fBitmaps;
+ delete[] fStrings;
+
+ SkImageRef_GlobalPool::DumpPool();
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SkString str("ImageDir: ");
+#ifdef SPECIFIC_IMAGE
+ str.append(SPECIFIC_IMAGE);
+#else
+ str.append(IMAGE_DIR);
+#endif
+ SampleCode::TitleR(evt, str.c_str());
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawBG(SkCanvas* canvas) {
+// canvas->drawColor(0xFFDDDDDD);
+ canvas->drawColor(SK_ColorGRAY);
+ canvas->drawColor(SK_ColorWHITE);
+ }
+
+ SkScalar fScale;
+ virtual void onDraw(SkCanvas* canvas) {
+ this->drawBG(canvas);
+
+ if (true) {
+ canvas->scale(SkIntToScalar(2), SkIntToScalar(2));
+ drawmarshmallow(canvas);
+ return;
+ }
+
+ if (false) {
+ SkPaint p;
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(SkIntToScalar(4));
+ canvas->drawCircle(SkIntToScalar(100), SkIntToScalar(100), SkIntToScalar(50), p);
+ p.setAntiAlias(true);
+ canvas->drawCircle(SkIntToScalar(300), SkIntToScalar(100), SkIntToScalar(50), p);
+ }
+ if (false) {
+ SkScalar cx = this->width()/2;
+ SkScalar cy = this->height()/2;
+ canvas->translate(cx, cy);
+ canvas->scale(fScale, fScale);
+ canvas->translate(-cx, -cy);
+ DrawRoundRect(*canvas);
+ return;
+ }
+
+ canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
+
+ SkScalar x = SkIntToScalar(32), y = SkIntToScalar(32);
+ SkPaint paint;
+
+#if 0
+ for (int i = 0; i < fBitmapCount; i++) {
+ SkPaint p;
+
+#if 1
+ const SkScalar cm[] = {
+ SkIntToScalar(2), 0, 0, 0, SkIntToScalar(-255),
+ 0, SkIntToScalar(2), 0, 0, SkIntToScalar(-255),
+ 0, 0, SkIntToScalar(2), 0, SkIntToScalar(-255),
+ 0, 0, 0, SkIntToScalar(1), 0
+ };
+ SkColorFilter* cf = new SkColorMatrixFilter(cm);
+ p.setColorFilter(cf)->unref();
+#endif
+
+ canvas->drawBitmap(fBitmaps[i], x, y, &p);
+ x += SkIntToScalar(fBitmaps[i].width() + 10);
+ }
+ return;
+#endif
+
+ canvas->drawBitmap(fBitmaps[fCurrIndex], x, y, &paint);
+#ifndef SPECIFIC_IMAGE
+ if (true) {
+ fCurrIndex += 1;
+ if (fCurrIndex >= fBitmapCount) {
+ fCurrIndex = 0;
+ }
+ this->inval(NULL);
+ }
+#endif
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ if (true) {
+ fCurrIndex += 1;
+ if (fCurrIndex >= fBitmapCount)
+ fCurrIndex = 0;
+ this->inval(NULL);
+ }
+ return new Click(this);
+ }
+
+ virtual bool onClick(Click* click) {
+ SkScalar center = this->width()/2;
+ fSaturation = SkScalarDiv(click->fCurr.fX - center, center/2);
+ center = this->height()/2;
+ fAngle = SkScalarDiv(click->fCurr.fY - center, center) * 180;
+
+ fDX += click->fCurr.fX - click->fPrev.fX;
+ fDY += click->fCurr.fY - click->fPrev.fY;
+
+ fScale = SkScalarDiv(click->fCurr.fX, this->width());
+
+ this->inval(NULL);
+ return true;
+ return this->INHERITED::onClick(click);
+ }
+
+private:
+ SkScalar fDX, fDY;
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new ImageDirView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleLCD.cpp b/samplecode/SampleLCD.cpp
new file mode 100644
index 0000000..098958f
--- /dev/null
+++ b/samplecode/SampleLCD.cpp
@@ -0,0 +1,61 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkPaint.h"
+#include "SkShader.h"
+
+class LCDView : public SkView {
+public:
+ LCDView() {}
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "LCD Text");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(SK_ColorWHITE);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ this->drawBG(canvas);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ SkScalar textSize = SkIntToScalar(6);
+ SkScalar delta = SK_Scalar1;
+ const char* text = "HHHamburgefonts iii";
+ size_t len = strlen(text);
+ SkScalar x0 = SkIntToScalar(10);
+ SkScalar x1 = SkIntToScalar(310);
+ SkScalar y = SkIntToScalar(20);
+
+ for (int i = 0; i < 20; i++) {
+ paint.setTextSize(textSize);
+ textSize += delta;
+
+ paint.setLCDRenderText(false);
+ canvas->drawText(text, len, x0, y, paint);
+ paint.setLCDRenderText(true);
+ canvas->drawText(text, len, x1, y, paint);
+
+ y += paint.getFontSpacing();
+ }
+ }
+
+private:
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new LCDView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleLayerMask.cpp b/samplecode/SampleLayerMask.cpp
new file mode 100644
index 0000000..9bd00ae
--- /dev/null
+++ b/samplecode/SampleLayerMask.cpp
@@ -0,0 +1,68 @@
+#include "SampleCode.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkView.h"
+
+///////////////////////////////////////////////////////////////////////////////
+
+class LayerMaskView : public SampleView {
+public:
+ LayerMaskView() {
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "LayerMask");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawMask(SkCanvas* canvas, const SkRect& r) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ if (true) {
+ SkBitmap mask;
+ int w = SkScalarRound(r.width());
+ int h = SkScalarRound(r.height());
+ mask.setConfig(SkBitmap::kARGB_8888_Config, w, h);
+ mask.allocPixels();
+ mask.eraseColor(0);
+ SkCanvas c(mask);
+ SkRect bounds = r;
+ bounds.offset(-bounds.fLeft, -bounds.fTop);
+ c.drawOval(bounds, paint);
+
+ paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
+ canvas->drawBitmap(mask, r.fLeft, r.fTop, &paint);
+ } else {
+ SkPath p;
+ p.addOval(r);
+ p.setFillType(SkPath::kInverseWinding_FillType);
+ paint.setXfermodeMode(SkXfermode::kDstOut_Mode);
+ canvas->drawPath(p, paint);
+ }
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkRect r;
+ r.set(SkIntToScalar(20), SkIntToScalar(20), SkIntToScalar(120), SkIntToScalar(120));
+ canvas->saveLayer(&r, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
+ canvas->drawColor(SK_ColorRED);
+ drawMask(canvas, r);
+ canvas->restore();
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new LayerMaskView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleLayers.cpp b/samplecode/SampleLayers.cpp
new file mode 100644
index 0000000..6fc9c83
--- /dev/null
+++ b/samplecode/SampleLayers.cpp
@@ -0,0 +1,271 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkBlurMaskFilter.h"
+#include "SkCamera.h"
+#include "SkColorFilter.h"
+#include "SkColorPriv.h"
+#include "SkDevice.h"
+#include "SkGradientShader.h"
+#include "SkImageDecoder.h"
+#include "SkInterpolator.h"
+#include "SkMaskFilter.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+#include "SkUtils.h"
+#include "SkKey.h"
+#include "SkXfermode.h"
+#include "SkDrawFilter.h"
+
+static void make_paint(SkPaint* paint) {
+ SkColor colors[] = { 0, SK_ColorWHITE };
+ SkPoint pts[] = { { 0, 0 }, { 0, SK_Scalar1*20 } };
+ SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode);
+
+ paint->setShader(s)->unref();
+ paint->setXfermodeMode(SkXfermode::kDstIn_Mode);
+}
+
+static void dump_layers(const char label[], SkCanvas* canvas) {
+ SkDebugf("Dump Layers(%s)\n", label);
+
+ SkCanvas::LayerIter iter(canvas, true);
+ int index = 0;
+ while (!iter.done()) {
+ const SkBitmap& bm = iter.device()->accessBitmap(false);
+ const SkIRect& clip = iter.clip().getBounds();
+ SkDebugf("Layer[%d] bitmap [%d %d] X=%d Y=%d clip=[%d %d %d %d] alpha=%d\n", index++,
+ bm.width(), bm.height(), iter.x(), iter.y(),
+ clip.fLeft, clip.fTop, clip.fRight, clip.fBottom,
+ iter.paint().getAlpha());
+ iter.next();
+ }
+}
+
+// test drawing with strips of fading gradient above and below
+static void test_fade(SkCanvas* canvas) {
+ SkAutoCanvasRestore ar(canvas, true);
+
+ SkRect r;
+
+ SkPaint p;
+ p.setAlpha(0x88);
+
+ SkAutoCanvasRestore(canvas, false);
+
+ // create the layers
+
+ r.set(0, 0, SkIntToScalar(100), SkIntToScalar(100));
+ canvas->clipRect(r);
+
+ r.fBottom = SkIntToScalar(20);
+ canvas->saveLayer(&r, NULL, (SkCanvas::SaveFlags)(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag));
+
+ r.fTop = SkIntToScalar(80);
+ r.fBottom = SkIntToScalar(100);
+ canvas->saveLayer(&r, NULL, (SkCanvas::SaveFlags)(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag));
+
+ // now draw the "content"
+
+ if (true) {
+ r.set(0, 0, SkIntToScalar(100), SkIntToScalar(100));
+
+ canvas->saveLayerAlpha(&r, 0x80);
+
+ SkPaint p;
+ p.setColor(SK_ColorRED);
+ p.setAntiAlias(true);
+ canvas->drawOval(r, p);
+
+ dump_layers("inside layer alpha", canvas);
+
+ canvas->restore();
+ } else {
+ r.set(0, 0, SkIntToScalar(100), SkIntToScalar(100));
+
+ SkPaint p;
+ p.setColor(SK_ColorRED);
+ p.setAntiAlias(true);
+ canvas->drawOval(r, p);
+ }
+
+// return;
+
+ dump_layers("outside layer alpha", canvas);
+
+ // now apply an effect
+
+ SkPaint paint;
+ make_paint(&paint);
+ r.set(0, 0, SkIntToScalar(100), SkIntToScalar(20));
+// SkDebugf("--------- draw top grad\n");
+ canvas->drawRect(r, paint);
+
+ SkMatrix m;
+ SkShader* s = paint.getShader();
+ m.setScale(SK_Scalar1, -SK_Scalar1);
+ m.postTranslate(0, SkIntToScalar(100));
+ s->setLocalMatrix(m);
+
+ r.fTop = SkIntToScalar(80);
+ r.fBottom = SkIntToScalar(100);
+// SkDebugf("--------- draw bot grad\n");
+ canvas->drawRect(r, paint);
+}
+
+class RedFilter : public SkDrawFilter {
+public:
+ virtual bool filter(SkCanvas*, SkPaint* p, SkDrawFilter::Type) {
+ fColor = p->getColor();
+ if (fColor == SK_ColorRED) {
+ p->setColor(SK_ColorGREEN);
+ }
+ return true;
+ }
+ virtual void restore(SkCanvas*, SkPaint* p, SkDrawFilter::Type) {
+ p->setColor(fColor);
+ }
+
+private:
+ SkColor fColor;
+};
+
+class LayersView : public SkView {
+public:
+ LayersView() {}
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Layers");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(SK_ColorGRAY);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ this->drawBG(canvas);
+
+ if (true) {
+ SkRect r;
+ r.set(SkIntToScalar(0), SkIntToScalar(0),
+ SkIntToScalar(220), SkIntToScalar(120));
+ SkPaint p;
+ canvas->saveLayer(&r, &p);
+ canvas->drawColor(0xFFFF0000);
+ p.setAlpha(0); // or 0
+ p.setXfermodeMode(SkXfermode::kSrc_Mode);
+ canvas->drawOval(r, p);
+ canvas->restore();
+ return;
+ }
+
+ if (false) {
+ SkRect r;
+ r.set(SkIntToScalar(0), SkIntToScalar(0),
+ SkIntToScalar(220), SkIntToScalar(120));
+ SkPaint p;
+ p.setAlpha(0x88);
+ p.setAntiAlias(true);
+
+ if (true) {
+ canvas->saveLayer(&r, &p);
+ p.setColor(0xFFFF0000);
+ canvas->drawOval(r, p);
+ canvas->restore();
+ }
+
+ p.setColor(0xFF0000FF);
+ r.offset(SkIntToScalar(20), SkIntToScalar(50));
+ canvas->drawOval(r, p);
+ }
+
+ if (false) {
+ SkPaint p;
+ p.setAlpha(0x88);
+ p.setAntiAlias(true);
+
+ canvas->translate(SkIntToScalar(300), 0);
+
+ SkRect r;
+ r.set(SkIntToScalar(0), SkIntToScalar(0),
+ SkIntToScalar(220), SkIntToScalar(60));
+
+ canvas->saveLayer(&r, &p, (SkCanvas::SaveFlags)(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag));
+// canvas->clipRect(r, SkRegion::kDifference_Op);
+// canvas->clipRect(r, SkRegion::kIntersect_Op);
+
+ r.set(SkIntToScalar(0), SkIntToScalar(0),
+ SkIntToScalar(220), SkIntToScalar(120));
+ p.setColor(SK_ColorBLUE);
+ canvas->drawOval(r, p);
+ canvas->restore();
+ return;
+ }
+
+ //canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
+ test_fade(canvas);
+ return;
+
+ // canvas->setDrawFilter(new RedFilter)->unref();
+
+ SkRect r;
+ SkPaint p;
+
+ canvas->translate(SkIntToScalar(220), SkIntToScalar(20));
+
+ p.setAntiAlias(true);
+ r.set(SkIntToScalar(20), SkIntToScalar(20),
+ SkIntToScalar(220), SkIntToScalar(120));
+
+ p.setColor(SK_ColorBLUE);
+ // p.setMaskFilter(SkBlurMaskFilter::Create(SkIntToScalar(8), SkBlurMaskFilter::kNormal_BlurStyle))->unref();
+ canvas->drawRect(r, p);
+ p.setMaskFilter(NULL);
+
+ SkRect bounds = r;
+ bounds.fBottom = bounds.centerY();
+ canvas->saveLayer(&bounds, NULL, SkCanvas::kARGB_NoClipLayer_SaveFlag);
+
+ p.setColor(SK_ColorRED);
+ canvas->drawOval(r, p);
+
+ p.setAlpha(0x80);
+ p.setXfermodeMode(SkXfermode::kDstIn_Mode);
+ canvas->drawRect(bounds, p);
+
+ canvas->restore();
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ this->inval(NULL);
+
+ return this->INHERITED::onFindClickHandler(x, y);
+ }
+
+ virtual bool onClick(Click* click) {
+ return this->INHERITED::onClick(click);
+ }
+
+ virtual bool handleKey(SkKey key) {
+ this->inval(NULL);
+ return true;
+ }
+
+private:
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new LayersView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleLineClipper.cpp b/samplecode/SampleLineClipper.cpp
new file mode 100644
index 0000000..ac6b013
--- /dev/null
+++ b/samplecode/SampleLineClipper.cpp
@@ -0,0 +1,255 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkRandom.h"
+
+#include "SkLineClipper.h"
+#include "SkEdgeClipper.h"
+
+#define AUTO_ANIMATE true
+
+static int test0(SkPoint pts[], SkRect* clip) {
+ pts[0].set(200000, 140);
+ pts[1].set(-740000, 483);
+ pts[2].set(1.00000102e-06f, 9.10000017e-05f);
+ clip->set(0, 0, 640, 480);
+ return 2;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void drawQuad(SkCanvas* canvas, const SkPoint pts[3], const SkPaint& p) {
+ SkPath path;
+ path.moveTo(pts[0]);
+ path.quadTo(pts[1], pts[2]);
+ canvas->drawPath(path, p);
+}
+
+static void drawCubic(SkCanvas* canvas, const SkPoint pts[4], const SkPaint& p) {
+ SkPath path;
+ path.moveTo(pts[0]);
+ path.cubicTo(pts[1], pts[2], pts[3]);
+ canvas->drawPath(path, p);
+}
+
+typedef void (*clipper_proc)(const SkPoint src[], const SkRect& clip,
+ SkCanvas*, const SkPaint&, const SkPaint&);
+
+static void check_clipper(int count, const SkPoint pts[], const SkRect& clip) {
+ for (int i = 0; i < count; i++) {
+ SkASSERT(pts[i].fX >= clip.fLeft);
+ SkASSERT(pts[i].fX <= clip.fRight);
+ SkASSERT(pts[i].fY >= clip.fTop);
+ SkASSERT(pts[i].fY <= clip.fBottom);
+ }
+
+ if (count > 1) {
+ sk_assert_monotonic_y(pts, count);
+ }
+}
+
+static void line_intersector(const SkPoint src[], const SkRect& clip,
+ SkCanvas* canvas, const SkPaint& p0, const SkPaint& p1) {
+ canvas->drawPoints(SkCanvas::kLines_PointMode, 2, src, p1);
+
+ SkPoint dst[2];
+ if (SkLineClipper::IntersectLine(src, clip, dst)) {
+ check_clipper(2, dst, clip);
+ canvas->drawPoints(SkCanvas::kLines_PointMode, 2, dst, p0);
+ }
+}
+
+static void line_clipper(const SkPoint src[], const SkRect& clip,
+ SkCanvas* canvas, const SkPaint& p0, const SkPaint& p1) {
+ canvas->drawPoints(SkCanvas::kLines_PointMode, 2, src, p1);
+
+ SkPoint dst[SkLineClipper::kMaxPoints];
+ int count = SkLineClipper::ClipLine(src, clip, dst);
+ for (int i = 0; i < count; i++) {
+ check_clipper(2, &dst[i], clip);
+ canvas->drawPoints(SkCanvas::kLines_PointMode, 2, &dst[i], p0);
+ }
+}
+
+static void quad_clipper(const SkPoint src[], const SkRect& clip,
+ SkCanvas* canvas, const SkPaint& p0, const SkPaint& p1) {
+ drawQuad(canvas, src, p1);
+
+ SkEdgeClipper clipper;
+ if (clipper.clipQuad(src, clip)) {
+ SkPoint pts[4];
+ SkPath::Verb verb;
+ while ((verb = clipper.next(pts)) != SkPath::kDone_Verb) {
+ switch (verb) {
+ case SkPath::kLine_Verb:
+ check_clipper(2, pts, clip);
+ canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p0);
+ break;
+ case SkPath::kQuad_Verb:
+ check_clipper(3, pts, clip);
+ drawQuad(canvas, pts, p0);
+ break;
+ default:
+ SkASSERT(!"unexpected verb");
+ }
+ }
+ }
+}
+
+static void cubic_clipper(const SkPoint src[], const SkRect& clip,
+ SkCanvas* canvas, const SkPaint& p0, const SkPaint& p1) {
+ drawCubic(canvas, src, p1);
+
+ SkEdgeClipper clipper;
+ if (clipper.clipCubic(src, clip)) {
+ SkPoint pts[4];
+ SkPath::Verb verb;
+ while ((verb = clipper.next(pts)) != SkPath::kDone_Verb) {
+ switch (verb) {
+ case SkPath::kLine_Verb:
+ check_clipper(2, pts, clip);
+ canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p0);
+ break;
+ case SkPath::kCubic_Verb:
+ // check_clipper(4, pts, clip);
+ drawCubic(canvas, pts, p0);
+ break;
+ default:
+ SkASSERT(!"unexpected verb");
+ }
+ }
+ }
+}
+
+static const clipper_proc gProcs[] = {
+ line_intersector,
+ line_clipper,
+ quad_clipper,
+ cubic_clipper
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+enum {
+ W = 640/3,
+ H = 480/3
+};
+
+class LineClipperView : public SkView {
+ SkMSec fNow;
+ int fCounter;
+ int fProcIndex;
+ SkRect fClip;
+ SkRandom fRand;
+ SkPoint fPts[4];
+
+ void randPts() {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(fPts); i++) {
+ fPts[i].set(fRand.nextUScalar1() * 640,
+ fRand.nextUScalar1() * 480);
+ }
+ fCounter += 1;
+ }
+
+public:
+ LineClipperView() {
+ fProcIndex = 0;
+ fCounter = 0;
+ fNow = 0;
+
+ int x = (640 - W)/2;
+ int y = (480 - H)/2;
+ fClip.set(SkIntToScalar(x), SkIntToScalar(y),
+ SkIntToScalar(x + W), SkIntToScalar(y + H));
+ this->randPts();
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "LineClipper");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(SK_ColorWHITE);
+ }
+
+ static void drawVLine(SkCanvas* canvas, SkScalar x, const SkPaint& paint) {
+ canvas->drawLine(x, -999, x, 999, paint);
+ }
+
+ static void drawHLine(SkCanvas* canvas, SkScalar y, const SkPaint& paint) {
+ canvas->drawLine(-999, y, 999, y, paint);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ this->drawBG(canvas);
+
+ SkMSec now = SampleCode::GetAnimTime();
+ if (fNow != now) {
+ fNow = now;
+ this->randPts();
+ this->inval(NULL);
+ }
+
+ // fProcIndex = test0(fPts, &fClip);
+
+ SkPaint paint, paint1;
+
+ drawVLine(canvas, fClip.fLeft + SK_ScalarHalf, paint);
+ drawVLine(canvas, fClip.fRight - SK_ScalarHalf, paint);
+ drawHLine(canvas, fClip.fTop + SK_ScalarHalf, paint);
+ drawHLine(canvas, fClip.fBottom - SK_ScalarHalf, paint);
+
+ paint.setColor(SK_ColorLTGRAY);
+ canvas->drawRect(fClip, paint);
+
+ paint.setAntiAlias(true);
+ paint.setColor(SK_ColorBLUE);
+ paint.setStyle(SkPaint::kStroke_Style);
+ // paint.setStrokeWidth(SkIntToScalar(3));
+ paint.setStrokeCap(SkPaint::kRound_Cap);
+
+ paint1.setAntiAlias(true);
+ paint1.setColor(SK_ColorRED);
+ paint1.setStyle(SkPaint::kStroke_Style);
+ gProcs[fProcIndex](fPts, fClip, canvas, paint, paint1);
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ // fProcIndex = (fProcIndex + 1) % SK_ARRAY_COUNT(gProcs);
+ if (x < 50 && y < 50) {
+ this->randPts();
+ }
+ this->inval(NULL);
+ return NULL;
+ }
+
+ virtual bool onClick(Click* click) {
+ return false;
+ }
+
+private:
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new LineClipperView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleLines.cpp b/samplecode/SampleLines.cpp
new file mode 100644
index 0000000..03dd30f
--- /dev/null
+++ b/samplecode/SampleLines.cpp
@@ -0,0 +1,109 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "Sk64.h"
+#include "SkCornerPathEffect.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkKernel33MaskFilter.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"
+
+class LinesView : public SampleView {
+public:
+ LinesView() {}
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Lines");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ /*
+ 0x1F * x + 0x1F * (32 - x)
+ */
+ void drawRings(SkCanvas* canvas) {
+ canvas->scale(SkIntToScalar(1)/2, SkIntToScalar(1)/2);
+
+ SkRect r;
+ SkScalar x = SkIntToScalar(10);
+ SkScalar y = SkIntToScalar(10);
+ r.set(x, y, x + SkIntToScalar(100), y + SkIntToScalar(100));
+
+ SkPaint paint;
+ // paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkScalarHalf(SkIntToScalar(3)));
+ paint.setColor(0xFFFF8800);
+ // paint.setColor(0xFFFFFFFF);
+ canvas->drawRect(r, paint);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkBitmap bm;
+ SkImageDecoder::DecodeFile("/kill.gif", &bm);
+ canvas->drawBitmap(bm, 0, 0, NULL);
+
+ this->drawRings(canvas);
+ return;
+
+ SkPaint paint;
+
+ // fAlpha = 0x80;
+ paint.setColor(SK_ColorWHITE);
+ paint.setAlpha(fAlpha & 0xFF);
+ SkRect r;
+
+ SkScalar x = SkIntToScalar(10);
+ SkScalar y = SkIntToScalar(10);
+ r.set(x, y, x + SkIntToScalar(100), y + SkIntToScalar(100));
+ canvas->drawRect(r, paint);
+ return;
+
+ paint.setColor(0xffffff00); // yellow
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkIntToScalar(2));
+
+// y += SK_Scalar1/2;
+
+ canvas->drawLine(x, y, x + SkIntToScalar(90), y + SkIntToScalar(90), paint);
+
+ paint.setAntiAlias(true); // with anti-aliasing
+ y += SkIntToScalar(10);
+ canvas->drawLine(x, y, x + SkIntToScalar(90), y + SkIntToScalar(90), paint);
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ fAlpha = SkScalarRound(y);
+ this->inval(NULL);
+ return NULL;
+ }
+private:
+
+ int fAlpha;
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new LinesView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleMeasure.cpp b/samplecode/SampleMeasure.cpp
new file mode 100644
index 0000000..8078e03
--- /dev/null
+++ b/samplecode/SampleMeasure.cpp
@@ -0,0 +1,115 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "Sk1DPathEffect.h"
+#include "SkCornerPathEffect.h"
+#include "SkPathMeasure.h"
+#include "SkRandom.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkDither.h"
+
+// exercise scale/linear/devkern
+struct Setting {
+ SkScalar fScale;
+ bool fLinearText;
+ bool fDevKernText;
+};
+
+static const SkScalar ONE = SkIntToScalar(9999)/10000;
+
+static const Setting gSettings[] = {
+ { 0, false, false },
+ { 0, false, true },
+ { 0, true, false },
+ { 0, true, true },
+ { ONE, false, false },
+ { ONE, false, true },
+ { ONE, true, false },
+ { ONE, true, true }
+};
+
+static void doMeasure(SkCanvas* canvas, const SkPaint& paint, const char text[]) {
+ SkScalar dy = paint.getFontMetrics(NULL);
+
+ size_t len = strlen(text);
+ SkAutoTMalloc<SkScalar> autoWidths(len);
+ SkScalar* widths = autoWidths.get();
+ SkAutoTMalloc<SkRect> autoRects(len);
+ SkRect* rects = autoRects.get();
+ SkRect bounds;
+
+ SkPaint p(paint);
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gSettings); i++) {
+ p.setLinearText(gSettings[i].fLinearText);
+ p.setDevKernText(gSettings[i].fDevKernText);
+ SkScalar scale = gSettings[i].fScale;
+
+ int n = p.getTextWidths(text, len, widths, rects);
+ SkScalar w = p.measureText(text, len, &bounds, scale);
+
+ p.setStyle(SkPaint::kFill_Style);
+ p.setColor(0x8888FF88);
+ canvas->drawRect(bounds, p);
+ p.setColor(0xFF000000);
+ canvas->drawText(text, len, 0, 0, p);
+
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(0);
+ p.setColor(0xFFFF0000);
+ SkScalar x = 0;
+ for (int j = 0; j < n; j++) {
+ SkRect r = rects[j];
+ r.offset(x, 0);
+ canvas->drawRect(r, p);
+ x += widths[j];
+ }
+
+ p.setColor(0xFF0000FF);
+ canvas->drawLine(0, 0, w, 0, p);
+ p.setStrokeWidth(SkIntToScalar(4));
+ canvas->drawPoint(x, 0, p);
+
+ canvas->translate(0, dy);
+ }
+}
+
+class MeasureView : public SampleView {
+public:
+ SkPaint fPaint;
+
+ MeasureView() {
+ fPaint.setAntiAlias(true);
+ fPaint.setTextSize(SkIntToScalar(64));
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Measure");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ canvas->translate(fPaint.getTextSize(), fPaint.getTextSize());
+ doMeasure(canvas, fPaint, "Hamburgefons");
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new MeasureView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleMipMap.cpp b/samplecode/SampleMipMap.cpp
new file mode 100644
index 0000000..3d95156
--- /dev/null
+++ b/samplecode/SampleMipMap.cpp
@@ -0,0 +1,143 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkPaint.h"
+#include "SkShader.h"
+
+static SkBitmap createBitmap(int n) {
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, n, n);
+ bitmap.allocPixels();
+ bitmap.eraseColor(0);
+
+ SkCanvas canvas(bitmap);
+ SkRect r;
+ r.set(0, 0, SkIntToScalar(n), SkIntToScalar(n));
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ paint.setColor(SK_ColorRED);
+ canvas.drawOval(r, paint);
+ paint.setColor(SK_ColorBLUE);
+ paint.setStrokeWidth(SkIntToScalar(n)/15);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas.drawLine(0, 0, r.fRight, r.fBottom, paint);
+ canvas.drawLine(0, r.fBottom, r.fRight, 0, paint);
+
+ return bitmap;
+}
+
+class MipMapView : public SampleView {
+ SkBitmap fBitmap;
+ enum {
+ N = 64
+ };
+public:
+ MipMapView() {
+ fBitmap = createBitmap(N);
+
+ fWidth = N;
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "MipMaps");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawN(SkCanvas* canvas, const SkBitmap& bitmap) {
+ SkAutoCanvasRestore acr(canvas, true);
+ for (int i = N; i > 1; i >>= 1) {
+ canvas->drawBitmap(bitmap, 0, 0, NULL);
+ canvas->translate(SkIntToScalar(N + 8), 0);
+ canvas->scale(SK_ScalarHalf, SK_ScalarHalf);
+ }
+ }
+
+ void drawN2(SkCanvas* canvas, const SkBitmap& bitmap) {
+ SkBitmap bg;
+ bg.setConfig(SkBitmap::kARGB_8888_Config, N, N);
+ bg.allocPixels();
+
+ SkAutoCanvasRestore acr(canvas, true);
+ for (int i = 0; i < 6; i++) {
+ bg.eraseColor(0);
+ SkCanvas c(bg);
+ c.scale(SK_Scalar1 / (1 << i), SK_Scalar1 / (1 << i));
+ c.drawBitmap(bitmap, 0, 0, NULL);
+
+ canvas->save();
+ canvas->scale(SkIntToScalar(1 << i), SkIntToScalar(1 << i));
+ canvas->drawBitmap(bg, 0, 0, NULL);
+ canvas->restore();
+ canvas->translate(SkIntToScalar(N + 8), 0);
+ }
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
+
+ canvas->scale(1.00000001f, 0.9999999f);
+
+ drawN2(canvas, fBitmap);
+
+ canvas->translate(0, SkIntToScalar(N + 8));
+ SkBitmap bitmap(fBitmap);
+ bitmap.buildMipMap();
+ drawN2(canvas, bitmap);
+
+ SkScalar time = SampleCode::GetAnimScalar(SkIntToScalar(1)/4,
+ SkIntToScalar(2));
+ if (time >= SK_Scalar1) {
+ time = SkIntToScalar(2) - time;
+ }
+ fWidth = 8 + SkScalarRound(N * time);
+
+ SkRect dst;
+ dst.set(0, 0, SkIntToScalar(fWidth), SkIntToScalar(fWidth));
+
+ SkPaint paint;
+ paint.setFilterBitmap(true);
+ paint.setAntiAlias(true);
+
+ canvas->translate(0, SkIntToScalar(N + 8));
+ canvas->drawBitmapRect(fBitmap, NULL, dst, NULL);
+ canvas->translate(SkIntToScalar(N + 8), 0);
+ canvas->drawBitmapRect(fBitmap, NULL, dst, &paint);
+ canvas->translate(-SkIntToScalar(N + 8), SkIntToScalar(N + 8));
+ canvas->drawBitmapRect(bitmap, NULL, dst, NULL);
+ canvas->translate(SkIntToScalar(N + 8), 0);
+ canvas->drawBitmapRect(bitmap, NULL, dst, &paint);
+
+ SkShader* s = SkShader::CreateBitmapShader(bitmap,
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+ paint.setShader(s)->unref();
+ SkMatrix m;
+ m.setScale(SkIntToScalar(fWidth) / N,
+ SkIntToScalar(fWidth) / N);
+ s->setLocalMatrix(m);
+ SkRect r;
+ r.set(0, 0, SkIntToScalar(4*N), SkIntToScalar(5*N/2));
+ r.offset(SkIntToScalar(N + 12), -SkIntToScalar(N + 4));
+ canvas->drawRect(r, paint);
+
+ this->inval(NULL);
+ }
+
+private:
+ int fWidth;
+
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new MipMapView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleMovie.cpp b/samplecode/SampleMovie.cpp
new file mode 100644
index 0000000..af34198
--- /dev/null
+++ b/samplecode/SampleMovie.cpp
@@ -0,0 +1,61 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkMovie.h"
+#include "SkTime.h"
+#include <new>
+
+class AnimGifView : public SkView {
+ SkMovie* fMovie;
+public:
+ AnimGifView() {
+ fMovie = SkMovie::DecodeFile("/skimages/dollarblk.gif");
+ }
+
+ virtual ~AnimGifView() {
+ SkSafeUnref(fMovie);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Animated Gif");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(0xFFDDDDDD);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ this->drawBG(canvas);
+
+ if (fMovie) {
+ if (fMovie->duration()) {
+ fMovie->setTime(SkTime::GetMSecs() % fMovie->duration());
+ } else {
+ fMovie->setTime(0);
+ }
+ canvas->drawBitmap(fMovie->bitmap(), SkIntToScalar(20),
+ SkIntToScalar(20));
+ this->inval(NULL);
+ }
+ }
+
+private:
+ SkRect fClip;
+ SkIPoint* fPoints;
+ SkPath fPath;
+ int fPtCount;
+
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new AnimGifView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleNinePatch.cpp b/samplecode/SampleNinePatch.cpp
new file mode 100644
index 0000000..e158287
--- /dev/null
+++ b/samplecode/SampleNinePatch.cpp
@@ -0,0 +1,114 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkImageDecoder.h"
+#include "SkNinePatch.h"
+#include "SkPaint.h"
+#include "SkUnPreMultiply.h"
+
+class NinePatchView : public SampleView {
+public:
+ SkBitmap fBM;
+
+ NinePatchView() {
+ SkImageDecoder::DecodeFile("/skimages/btn_default_normal_disable.9.png", &fBM);
+
+ // trim off the edge guide-lines
+ SkBitmap tmp;
+ SkIRect r;
+ r.set(1, 1, fBM.width() - 1, fBM.height() - 1);
+ fBM.extractSubset(&tmp, r);
+ fBM.swap(tmp);
+
+ fX = SkIntToScalar(fBM.width());
+ fY = 0;
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "NinePatch");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawBackground(SkCanvas* canvas) {
+ SkPaint p;
+ p.setDither(true);
+ p.setColor(0xFF909090);
+ canvas->drawPaint(p);
+ }
+
+ static void test_rects(SkCanvas* canvas, const SkBitmap& bm, const SkPaint* paint) {
+ static const SkIRect src[] = {
+ { 0, 0, 18, 34 },
+ { 18, 0, 19, 34 },
+ { 19, 0, 36, 34 },
+ { 0, 34, 18, 35 },
+ { 18, 34, 19, 35 },
+ { 19, 34, 36, 35 },
+ { 0, 35, 18, 72 },
+ { 18, 35, 19, 72 },
+ { 19, 35, 36, 72 },
+ };
+ static const SkRect dst[] = {
+ { 0, 0, 18, 34 },
+ { 18, 0, 283, 34 },
+ { 283, 0, 300, 34 },
+ { 0, 34, 18, 163 },
+ { 18, 34, 283, 163 },
+ { 283, 34, 300, 163 },
+ { 0, 163, 18, 200 },
+ { 18, 163, 283, 200 },
+ { 283, 163, 300, 200 },
+ };
+ for (size_t i = 0; i < SK_ARRAY_COUNT(src); i++) {
+ canvas->drawBitmapRect(bm, &src[i], dst[i], paint);
+ }
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ canvas->drawBitmap(fBM, 0, 0);
+
+ SkIRect margins;
+ SkRect dst;
+ int d = 25;
+
+ margins.set(d, d, d, d);
+ margins.fLeft = fBM.width()/2 - 1;
+ margins.fTop = fBM.height()/2 - 1;
+ margins.fRight = fBM.width() - margins.fLeft - 1;
+ margins.fBottom = fBM.height() - margins.fTop - 1;
+
+ // canvas->translate(fX/5, fY/5);
+ canvas->translate(0, 76);
+
+ dst.set(0, 0, SkIntToScalar(200), SkIntToScalar(200));
+
+ SkPaint paint;
+ paint.setAntiAlias(false);
+ paint.setDither(true);
+ paint.setFilterBitmap(false);
+ // SkNinePatch::DrawNine(canvas, dst, fBM, margins, &paint);
+ test_rects(canvas, fBM, &paint);
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ fX = x / 1.5f;
+ fY = y / 1.5f;
+ fX = x; fY = y;
+ this->inval(NULL);
+ return this->INHERITED::onFindClickHandler(x, y);
+ }
+private:
+ SkScalar fX, fY;
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new NinePatchView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleOvalTest.cpp b/samplecode/SampleOvalTest.cpp
new file mode 100644
index 0000000..f625529
--- /dev/null
+++ b/samplecode/SampleOvalTest.cpp
@@ -0,0 +1,110 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+
+static const int kILimit = 101;
+static const SkScalar kLimit = SK_Scalar1 * kILimit;
+
+class OvalTestView : public SampleView {
+public:
+ SkSize fSize;
+ SkPMColor fInsideColor; // signals an interior pixel that was not set
+ SkPMColor fOutsideColor; // signals an exterior pixels that was set
+ SkBitmap fBitmap;
+
+ OvalTestView() {
+ fSize.set(SK_Scalar1, SK_Scalar1);
+
+ fBitmap.setConfig(SkBitmap::kARGB_8888_Config, kILimit, kILimit);
+ fBitmap.allocPixels();
+
+ fInsideColor = SkPreMultiplyColor(SK_ColorRED);
+ fOutsideColor = SkPreMultiplyColor(SK_ColorGREEN);
+
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "OvalTest");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawOval() {
+ SkCanvas canvas(fBitmap);
+ SkPaint p;
+
+ fBitmap.eraseColor(0);
+ canvas.drawOval(SkRect::MakeSize(fSize), p);
+ }
+
+ int checkOval(int* flatCount, int* buldgeCount) {
+ int flatc = 0;
+ int buldgec = 0;
+ const SkScalar rad = SkScalarHalf(fSize.width());
+ SkScalar cx = SkScalarHalf(fSize.width());
+ SkScalar cy = SkScalarHalf(fSize.height());
+ for (int y = 0; y < kILimit; y++) {
+ for (int x = 0; x < kILimit; x++) {
+ // measure from pixel centers
+ SkScalar px = SkIntToScalar(x) + SK_ScalarHalf;
+ SkScalar py = SkIntToScalar(y) + SK_ScalarHalf;
+
+ SkPMColor* ptr = fBitmap.getAddr32(x, y);
+ SkScalar dist = SkPoint::Length(px - cx, py - cy);
+ if (dist <= rad && !*ptr) {
+ flatc++;
+ *ptr = fInsideColor;
+ } else if (dist > rad && *ptr) {
+ buldgec++;
+ *ptr = fOutsideColor;
+ }
+ }
+ }
+ if (flatCount) *flatCount = flatc;
+ if (buldgeCount) *buldgeCount = buldgec;
+ return flatc + buldgec;
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ this->drawOval();
+ int flatCount, buldgeCount;
+ this->checkOval(&flatCount, &buldgeCount);
+ this->inval(NULL);
+
+ canvas->drawBitmap(fBitmap, SkIntToScalar(20), SkIntToScalar(20), NULL);
+
+
+ static int gFlatCount;
+ static int gBuldgeCount;
+ gFlatCount += flatCount;
+ gBuldgeCount += buldgeCount;
+
+ if (fSize.fWidth < kLimit) {
+ SkDebugf("--- width=%g, flat=%d buldge=%d total: flat=%d buldge=%d\n", fSize.fWidth,
+ flatCount, buldgeCount, gFlatCount, gBuldgeCount);
+ fSize.fWidth += SK_Scalar1;
+ fSize.fHeight += SK_Scalar1;
+ } else {
+ // fSize.set(SK_Scalar1, SK_Scalar1);
+ }
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ this->inval(NULL);
+ return NULL;
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new OvalTestView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleOverflow.cpp b/samplecode/SampleOverflow.cpp
new file mode 100644
index 0000000..d3ecff7
--- /dev/null
+++ b/samplecode/SampleOverflow.cpp
@@ -0,0 +1,100 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkPaint.h"
+
+static void DrawRoundRect() {
+#ifdef SK_SCALAR_IS_FIXED
+ bool ret = false;
+ SkPaint paint;
+ SkBitmap bitmap;
+ SkCanvas canvas;
+ SkMatrix matrix;
+ matrix.reset();
+
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1370, 812);
+ bitmap.allocPixels();
+ canvas.setBitmapDevice(bitmap);
+
+ // set up clipper
+ SkRect skclip;
+ skclip.set(SkIntToFixed(284), SkIntToFixed(40), SkIntToFixed(1370), SkIntToFixed(708));
+
+ ret = canvas.clipRect(skclip);
+ SkASSERT(ret);
+
+ matrix.set(SkMatrix::kMTransX, SkFloatToFixed(-1153.28));
+ matrix.set(SkMatrix::kMTransY, SkFloatToFixed(1180.50));
+
+ matrix.set(SkMatrix::kMScaleX, SkFloatToFixed(0.177171));
+ matrix.set(SkMatrix::kMScaleY, SkFloatToFixed(0.177043));
+
+ matrix.set(SkMatrix::kMSkewX, SkFloatToFixed(0.126968));
+ matrix.set(SkMatrix::kMSkewY, SkFloatToFixed(-0.126876));
+
+ matrix.set(SkMatrix::kMPersp0, SkFloatToFixed(0.0));
+ matrix.set(SkMatrix::kMPersp1, SkFloatToFixed(0.0));
+
+ ret = canvas.concat(matrix);
+
+ paint.setAntiAlias(true);
+ paint.setColor(0xb2202020);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkFloatToFixed(68.13));
+
+ SkRect r;
+ r.set(SkFloatToFixed(-313.714417), SkFloatToFixed(-4.826389), SkFloatToFixed(18014.447266), SkFloatToFixed(1858.154541));
+ canvas.drawRoundRect(r, SkFloatToFixed(91.756363), SkFloatToFixed(91.756363), paint);
+#endif
+}
+
+static bool HitTestPath(const SkPath& path, SkScalar x, SkScalar y) {
+ SkRegion rgn, clip;
+
+ int ix = SkScalarFloor(x);
+ int iy = SkScalarFloor(y);
+
+ clip.setRect(ix, iy, ix + 1, iy + 1);
+
+ bool contains = rgn.setPath(path, clip);
+ return contains;
+}
+
+static void TestOverflowHitTest() {
+ SkPath path;
+
+#ifdef SK_SCALAR_IS_FLOATx
+ path.addCircle(0, 0, 70000, SkPath::kCCW_Direction);
+ SkASSERT(HitTestPath(path, 40000, 40000));
+#endif
+}
+
+class OverflowView : public SampleView {
+public:
+ OverflowView() {}
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Circles");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ DrawRoundRect();
+ TestOverflowHitTest();
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new OverflowView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SamplePageFlip.cpp b/samplecode/SamplePageFlip.cpp
new file mode 100644
index 0000000..7c5bf48
--- /dev/null
+++ b/samplecode/SamplePageFlip.cpp
@@ -0,0 +1,167 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGraphics.h"
+#include "SkRandom.h"
+#include "SkFlipPixelRef.h"
+#include "SkPageFlipper.h"
+
+#include <pthread.h>
+
+#define WIDTH 200
+#define HEIGHT 200
+
+static bool gDone;
+
+static void bounce(SkScalar* x, SkScalar* dx, const int max) {
+ *x += *dx;
+ if (*x < 0) {
+ *x = 0;
+ if (*dx < 0) {
+ *dx = -*dx;
+ }
+ } else if (*x > SkIntToScalar(max)) {
+ *x = SkIntToScalar(max);
+ if (*dx > 0) {
+ *dx = -*dx;
+ }
+ }
+}
+
+static void* draw_proc(void* context) {
+ const int OVALW = 32;
+ const int OVALH = 32;
+
+ const SkBitmap* bm = static_cast<const SkBitmap*>(context);
+ SkFlipPixelRef* ref = static_cast<SkFlipPixelRef*>(bm->pixelRef());
+
+ const int DSCALE = 1;
+ SkScalar dx = SkIntToScalar(7) / DSCALE;
+ SkScalar dy = SkIntToScalar(5) / DSCALE;
+ SkScalar x = 0;
+ SkScalar y = 0;
+
+ SkPaint paint;
+
+ paint.setAntiAlias(true);
+ paint.setColor(SK_ColorRED);
+
+ SkRect oval;
+ oval.setEmpty();
+
+ while (!gDone) {
+ ref->inval(oval, true);
+ oval.set(x, y, x + SkIntToScalar(OVALW), y + SkIntToScalar(OVALH));
+ ref->inval(oval, true);
+
+ SkAutoFlipUpdate update(ref);
+
+ if (!update.dirty().isEmpty()) {
+ // this must be local to the loop, since it needs to forget the pixels
+ // its writing to after each iteration, since we do the swap
+ SkCanvas canvas(update.bitmap());
+
+// SkDebugf("----- dirty [%d %d %d %d]\n", dirty.getBounds().fLeft, dirty.getBounds().fTop, dirty.getBounds().width(), dirty.getBounds().height());
+ canvas.clipRegion(update.dirty());
+
+ canvas.drawColor(0, SkXfermode::kClear_Mode);
+ canvas.drawOval(oval, paint);
+ }
+ bounce(&x, &dx, WIDTH-OVALW);
+ bounce(&y, &dy, HEIGHT-OVALH);
+
+#if 1
+ for (int i = 0; i < 1000; i++) {
+ for (int j = 0; j < 10000; j++) {
+ SkFixedMul(j, 10);
+ }
+ }
+#endif
+ }
+ return NULL;
+}
+
+static const SkBitmap::Config gConfigs[] = {
+ SkBitmap::kARGB_8888_Config,
+#if 1
+ SkBitmap::kRGB_565_Config,
+ SkBitmap::kARGB_4444_Config,
+ SkBitmap::kA8_Config
+#endif
+};
+
+class PageFlipView : public SampleView {
+public:
+
+ enum { N = SK_ARRAY_COUNT(gConfigs) };
+
+ pthread_t fThreads[N];
+ SkBitmap fBitmaps[N];
+
+ PageFlipView() {
+ gDone = false;
+ for (int i = 0; i < N; i++) {
+ int status;
+ pthread_attr_t attr;
+
+ status = pthread_attr_init(&attr);
+ SkASSERT(0 == status);
+
+ fBitmaps[i].setConfig(gConfigs[i], WIDTH, HEIGHT);
+ SkFlipPixelRef* pr = new SkFlipPixelRef(gConfigs[i], WIDTH, HEIGHT);
+ fBitmaps[i].setPixelRef(pr)->unref();
+ fBitmaps[i].eraseColor(0);
+
+ status = pthread_create(&fThreads[i], &attr, draw_proc, &fBitmaps[i]);
+ SkASSERT(0 == status);
+ }
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+ virtual ~PageFlipView() {
+ gDone = true;
+ for (int i = 0; i < N; i++) {
+ void* ret;
+ int status = pthread_join(fThreads[i], &ret);
+ SkASSERT(0 == status);
+ }
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "PageFlip");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkScalar x = SkIntToScalar(10);
+ SkScalar y = SkIntToScalar(10);
+ for (int i = 0; i < N; i++) {
+ canvas->drawBitmap(fBitmaps[i], x, y);
+ x += SkIntToScalar(fBitmaps[i].width() + 20);
+ }
+ this->inval(NULL);
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ this->inval(NULL);
+ return this->INHERITED::onFindClickHandler(x, y);
+ }
+
+ virtual bool onClick(Click* click) {
+ return this->INHERITED::onClick(click);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new PageFlipView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SamplePatch.cpp b/samplecode/SamplePatch.cpp
new file mode 100644
index 0000000..ea365c7
--- /dev/null
+++ b/samplecode/SamplePatch.cpp
@@ -0,0 +1,342 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.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 "SkXfermode.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+
+#include "SkOSFile.h"
+#include "SkStream.h"
+
+#include "SkGeometry.h" // private include :(
+
+static void drawtriangle(SkCanvas* canvas, const SkPaint& paint,
+ const SkPoint pts[3]) {
+ SkPath path;
+
+ path.moveTo(pts[0]);
+ path.lineTo(pts[1]);
+ path.lineTo(pts[2]);
+
+ canvas->drawPath(path, paint);
+}
+
+static SkShader* make_shader0(SkIPoint* size) {
+ SkBitmap bm;
+
+// SkImageDecoder::DecodeFile("/skimages/progressivejpg.jpg", &bm);
+ SkImageDecoder::DecodeFile("/skimages/logo.png", &bm);
+ size->set(bm.width(), bm.height());
+ return SkShader::CreateBitmapShader(bm, SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode);
+}
+
+static SkShader* make_shader1(const SkIPoint& size) {
+ SkPoint pts[] = { { 0, 0, },
+ { SkIntToScalar(size.fX), SkIntToScalar(size.fY) } };
+ SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorRED };
+ return SkGradientShader::CreateLinear(pts, colors, NULL,
+ SK_ARRAY_COUNT(colors), SkShader::kMirror_TileMode, NULL);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class Patch {
+public:
+ Patch() { sk_bzero(fPts, sizeof(fPts)); }
+ ~Patch() {}
+
+ void setPatch(const SkPoint pts[12]) {
+ memcpy(fPts, pts, 12 * sizeof(SkPoint));
+ fPts[12] = pts[0]; // the last shall be first
+ }
+ void setBounds(int w, int h) { fW = w; fH = h; }
+
+ void draw(SkCanvas*, const SkPaint&, int segsU, int segsV,
+ bool doTextures, bool doColors);
+
+private:
+ SkPoint fPts[13];
+ int fW, fH;
+};
+
+static void eval_patch_edge(const SkPoint cubic[], SkPoint samples[], int segs) {
+ SkScalar t = 0;
+ SkScalar dt = SK_Scalar1 / segs;
+
+ samples[0] = cubic[0];
+ for (int i = 1; i < segs; i++) {
+ t += dt;
+ SkEvalCubicAt(cubic, t, &samples[i], NULL, NULL);
+ }
+}
+
+static void eval_sheet(const SkPoint edge[], int nu, int nv, int iu, int iv,
+ SkPoint* pt) {
+ const int TL = 0;
+ const int TR = nu;
+ const int BR = TR + nv;
+ const int BL = BR + nu;
+
+ SkScalar u = SkIntToScalar(iu) / nu;
+ SkScalar v = SkIntToScalar(iv) / nv;
+
+ SkScalar uv = SkScalarMul(u, v);
+ SkScalar Uv = SkScalarMul(SK_Scalar1 - u, v);
+ SkScalar uV = SkScalarMul(u, SK_Scalar1 - v);
+ SkScalar UV = SkScalarMul(SK_Scalar1 - u, SK_Scalar1 - v);
+
+ SkScalar x0 = SkScalarMul(UV, edge[TL].fX) + SkScalarMul(uV, edge[TR].fX) +
+ SkScalarMul(Uv, edge[BL].fX) + SkScalarMul(uv, edge[BR].fX);
+ SkScalar y0 = SkScalarMul(UV, edge[TL].fY) + SkScalarMul(uV, edge[TR].fY) +
+ SkScalarMul(Uv, edge[BL].fY) + SkScalarMul(uv, edge[BR].fY);
+
+ SkScalar x = SkScalarMul(SK_Scalar1 - v, edge[TL+iu].fX) +
+ SkScalarMul(u, edge[TR+iv].fX) +
+ SkScalarMul(v, edge[BR+nu-iu].fX) +
+ SkScalarMul(SK_Scalar1 - u, edge[BL+nv-iv].fX) - x0;
+ SkScalar y = SkScalarMul(SK_Scalar1 - v, edge[TL+iu].fY) +
+ SkScalarMul(u, edge[TR+iv].fY) +
+ SkScalarMul(v, edge[BR+nu-iu].fY) +
+ SkScalarMul(SK_Scalar1 - u, edge[BL+nv-iv].fY) - y0;
+ pt->set(x, y);
+}
+
+static int ScalarTo255(SkScalar v) {
+ int scale = SkScalarToFixed(v) >> 8;
+ if (scale < 0) {
+ scale = 0;
+ } else if (scale > 255) {
+ scale = 255;
+ }
+ return scale;
+}
+
+static SkColor make_color(SkScalar s, SkScalar t) {
+ int cs = ScalarTo255(s);
+ int ct = ScalarTo255(t);
+ return SkColorSetARGB(0xFF, cs, 0, 0) + SkColorSetARGB(0, 0, ct, 0);
+}
+
+void Patch::draw(SkCanvas* canvas, const SkPaint& paint, int nu, int nv,
+ bool doTextures, bool doColors) {
+ if (nu < 1 || nv < 1) {
+ return;
+ }
+
+ int i, npts = (nu + nv) * 2;
+ SkAutoSTMalloc<16, SkPoint> storage(npts + 1);
+ SkPoint* edge0 = storage.get();
+ SkPoint* edge1 = edge0 + nu;
+ SkPoint* edge2 = edge1 + nv;
+ SkPoint* edge3 = edge2 + nu;
+
+ // evaluate the edge points
+ eval_patch_edge(fPts + 0, edge0, nu);
+ eval_patch_edge(fPts + 3, edge1, nv);
+ eval_patch_edge(fPts + 6, edge2, nu);
+ eval_patch_edge(fPts + 9, edge3, nv);
+ edge3[nv] = edge0[0]; // the last shall be first
+
+ for (i = 0; i < npts; i++) {
+// canvas->drawLine(edge0[i].fX, edge0[i].fY, edge0[i+1].fX, edge0[i+1].fY, paint);
+ }
+
+ int row, vertCount = (nu + 1) * (nv + 1);
+ SkAutoTMalloc<SkPoint> vertStorage(vertCount);
+ SkPoint* verts = vertStorage.get();
+
+ // first row
+ memcpy(verts, edge0, (nu + 1) * sizeof(SkPoint));
+ // rows
+ SkPoint* r = verts;
+ for (row = 1; row < nv; row++) {
+ r += nu + 1;
+ r[0] = edge3[nv - row];
+ for (int col = 1; col < nu; col++) {
+ eval_sheet(edge0, nu, nv, col, row, &r[col]);
+ }
+ r[nu] = edge1[row];
+ }
+ // last row
+ SkPoint* last = verts + nv * (nu + 1);
+ for (i = 0; i <= nu; i++) {
+ last[i] = edge2[nu - i];
+ }
+
+// canvas->drawPoints(verts, vertCount, paint);
+
+ int stripCount = (nu + 1) * 2;
+ SkAutoTMalloc<SkPoint> stripStorage(stripCount * 2);
+ SkAutoTMalloc<SkColor> colorStorage(stripCount);
+ SkPoint* strip = stripStorage.get();
+ SkPoint* tex = strip + stripCount;
+ SkColor* colors = colorStorage.get();
+ SkScalar t = 0;
+ const SkScalar ds = SK_Scalar1 * fW / nu;
+ const SkScalar dt = SK_Scalar1 * fH / nv;
+ r = verts;
+ for (row = 0; row < nv; row++) {
+ SkPoint* upper = r;
+ SkPoint* lower = r + nu + 1;
+ r = lower;
+ SkScalar s = 0;
+ for (i = 0; i <= nu; i++) {
+ strip[i*2 + 0] = *upper++;
+ strip[i*2 + 1] = *lower++;
+ tex[i*2 + 0].set(s, t);
+ tex[i*2 + 1].set(s, t + dt);
+ colors[i*2 + 0] = make_color(s/fW, t/fH);
+ colors[i*2 + 1] = make_color(s/fW, (t + dt)/fH);
+ s += ds;
+ }
+ t += dt;
+ canvas->drawVertices(SkCanvas::kTriangleStrip_VertexMode, stripCount,
+ strip, doTextures ? tex : NULL,
+ doColors ? colors : NULL, NULL,
+ NULL, 0, paint);
+ }
+}
+
+static void drawpatches(SkCanvas* canvas, const SkPaint& paint, int nu, int nv,
+ Patch* patch) {
+
+ SkAutoCanvasRestore ar(canvas, true);
+
+ patch->draw(canvas, paint, 10, 10, false, false);
+ canvas->translate(SkIntToScalar(180), 0);
+ patch->draw(canvas, paint, 10, 10, true, false);
+ canvas->translate(SkIntToScalar(180), 0);
+ patch->draw(canvas, paint, 10, 10, false, true);
+ canvas->translate(SkIntToScalar(180), 0);
+ patch->draw(canvas, paint, 10, 10, true, true);
+}
+
+class PatchView : public SampleView {
+ SkShader* fShader0;
+ SkShader* fShader1;
+ SkIPoint fSize0, fSize1;
+ SkPoint fPts[12];
+
+public:
+ PatchView() {
+ fShader0 = make_shader0(&fSize0);
+ fSize1 = fSize0;
+ if (fSize0.fX == 0 || fSize0.fY == 0) {
+ fSize1.set(2, 2);
+ }
+ fShader1 = make_shader1(fSize1);
+
+ const SkScalar S = SkIntToScalar(50);
+ const SkScalar T = SkIntToScalar(40);
+ fPts[0].set(S*0, T);
+ fPts[1].set(S*1, T);
+ fPts[2].set(S*2, T);
+ fPts[3].set(S*3, T);
+ fPts[4].set(S*3, T*2);
+ fPts[5].set(S*3, T*3);
+ fPts[6].set(S*3, T*4);
+ fPts[7].set(S*2, T*4);
+ fPts[8].set(S*1, T*4);
+ fPts[9].set(S*0, T*4);
+ fPts[10].set(S*0, T*3);
+ fPts[11].set(S*0, T*2);
+
+ this->setBGColor(SK_ColorGRAY);
+ }
+
+ virtual ~PatchView() {
+ SkSafeUnref(fShader0);
+ SkSafeUnref(fShader1);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt))
+ {
+ SkString str("Patch");
+ SampleCode::TitleR(evt, str.c_str());
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setDither(true);
+ paint.setFilterBitmap(true);
+
+ canvas->translate(SkIntToScalar(20), 0);
+
+ Patch patch;
+
+ paint.setShader(fShader0);
+ if (fSize0.fX == 0) {
+ fSize0.fX = 1;
+ }
+ if (fSize0.fY == 0) {
+ fSize0.fY = 1;
+ }
+ patch.setBounds(fSize0.fX, fSize0.fY);
+
+ patch.setPatch(fPts);
+ drawpatches(canvas, paint, 10, 10, &patch);
+
+ paint.setShader(NULL);
+ paint.setAntiAlias(true);
+ paint.setStrokeWidth(SkIntToScalar(5));
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, SK_ARRAY_COUNT(fPts), fPts, paint);
+
+ canvas->translate(0, SkIntToScalar(300));
+
+ paint.setAntiAlias(false);
+ paint.setShader(fShader1);
+ patch.setBounds(fSize1.fX, fSize1.fY);
+ drawpatches(canvas, paint, 10, 10, &patch);
+ }
+
+ class PtClick : public Click {
+ public:
+ int fIndex;
+ PtClick(SkView* view, int index) : Click(view), fIndex(index) {}
+ };
+
+ static bool hittest(const SkPoint& pt, SkScalar x, SkScalar y) {
+ return SkPoint::Length(pt.fX - x, pt.fY - y) < SkIntToScalar(5);
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(fPts); i++) {
+ if (hittest(fPts[i], x, y)) {
+ return new PtClick(this, i);
+ }
+ }
+ return this->INHERITED::onFindClickHandler(x, y);
+ }
+
+ virtual bool onClick(Click* click) {
+ fPts[((PtClick*)click)->fIndex].set(click->fCurr.fX, click->fCurr.fY);
+ this->inval(NULL);
+ return true;
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new PatchView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SamplePath.cpp b/samplecode/SamplePath.cpp
new file mode 100644
index 0000000..cd45ed9
--- /dev/null
+++ b/samplecode/SamplePath.cpp
@@ -0,0 +1,200 @@
+
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkParsePath.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+
+#include "SkGeometry.h"
+
+// http://code.google.com/p/skia/issues/detail?id=32
+static void test_cubic() {
+ SkPoint src[4] = {
+ { 556.25000f, 523.03003f },
+ { 556.23999f, 522.96002f },
+ { 556.21997f, 522.89001f },
+ { 556.21997f, 522.82001f }
+ };
+ SkPoint dst[11];
+ dst[10].set(42, -42); // one past the end, that we don't clobber these
+ SkScalar tval[] = { 0.33333334f, 0.99999994f };
+
+ SkChopCubicAt(src, dst, tval, 2);
+
+#if 0
+ for (int i = 0; i < 11; i++) {
+ SkDebugf("--- %d [%g %g]\n", i, dst[i].fX, dst[i].fY);
+ }
+#endif
+}
+
+static void test_cubic2() {
+ const char* str = "M2242 -590088L-377758 9.94099e+07L-377758 9.94099e+07L2242 -590088Z";
+ SkPath path;
+ SkParsePath::FromSVGString(str, &path);
+
+ {
+#ifdef SK_BUILD_FOR_WIN
+ // windows doesn't have strtof
+ float x = (float)strtod("9.94099e+07", NULL);
+#else
+ float x = strtof("9.94099e+07", NULL);
+#endif
+ int ix = (int)x;
+ int fx = (int)(x * 65536);
+ int ffx = SkScalarToFixed(x);
+ printf("%g %x %x %x\n", x, ix, fx, ffx);
+
+ SkRect r = path.getBounds();
+ SkIRect ir;
+ r.round(&ir);
+ printf("[%g %g %g %g] [%x %x %x %x]\n",
+ r.fLeft, r.fTop, r.fRight, r.fBottom,
+ ir.fLeft, ir.fTop, ir.fRight, ir.fBottom);
+ }
+
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, 300, 200);
+ bitmap.allocPixels();
+
+ SkCanvas canvas(bitmap);
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ canvas.drawPath(path, paint);
+}
+
+class PathView : public SampleView {
+public:
+ int fDStroke, fStroke, fMinStroke, fMaxStroke;
+ SkPath fPath[6];
+ bool fShowHairline;
+
+ PathView() {
+ test_cubic();
+ test_cubic2();
+
+ fShowHairline = false;
+
+ fDStroke = 1;
+ fStroke = 10;
+ fMinStroke = 10;
+ fMaxStroke = 180;
+
+ const int V = 85;
+
+ fPath[0].moveTo(SkIntToScalar(40), SkIntToScalar(70));
+ fPath[0].lineTo(SkIntToScalar(70), SkIntToScalar(70) + SK_Scalar1/1);
+ fPath[0].lineTo(SkIntToScalar(110), SkIntToScalar(70));
+
+ fPath[1].moveTo(SkIntToScalar(40), SkIntToScalar(70));
+ fPath[1].lineTo(SkIntToScalar(70), SkIntToScalar(70) - SK_Scalar1/1);
+ fPath[1].lineTo(SkIntToScalar(110), SkIntToScalar(70));
+
+ fPath[2].moveTo(SkIntToScalar(V), SkIntToScalar(V));
+ fPath[2].lineTo(SkIntToScalar(50), SkIntToScalar(V));
+ fPath[2].lineTo(SkIntToScalar(50), SkIntToScalar(50));
+
+ fPath[3].moveTo(SkIntToScalar(50), SkIntToScalar(50));
+ fPath[3].lineTo(SkIntToScalar(50), SkIntToScalar(V));
+ fPath[3].lineTo(SkIntToScalar(V), SkIntToScalar(V));
+
+ fPath[4].moveTo(SkIntToScalar(50), SkIntToScalar(50));
+ fPath[4].lineTo(SkIntToScalar(50), SkIntToScalar(V));
+ fPath[4].lineTo(SkIntToScalar(52), SkIntToScalar(50));
+
+ fPath[5].moveTo(SkIntToScalar(52), SkIntToScalar(50));
+ fPath[5].lineTo(SkIntToScalar(50), SkIntToScalar(V));
+ fPath[5].lineTo(SkIntToScalar(50), SkIntToScalar(50));
+
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+ void nextStroke() {
+ fStroke += fDStroke;
+ if (fStroke > fMaxStroke || fStroke < fMinStroke)
+ fDStroke = -fDStroke;
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Paths");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawPath(SkCanvas* canvas, const SkPath& path, SkPaint::Join j) {
+ SkPaint paint;
+
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeJoin(j);
+ paint.setStrokeWidth(SkIntToScalar(fStroke));
+
+ if (fShowHairline) {
+ SkPath fill;
+
+ paint.getFillPath(path, &fill);
+ paint.setStrokeWidth(0);
+ canvas->drawPath(fill, paint);
+ } else {
+ canvas->drawPath(path, paint);
+ }
+
+ paint.setColor(SK_ColorRED);
+ paint.setStrokeWidth(0);
+ canvas->drawPath(path, paint);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ canvas->translate(SkIntToScalar(50), SkIntToScalar(50));
+
+ static const SkPaint::Join gJoins[] = {
+ SkPaint::kBevel_Join,
+ SkPaint::kMiter_Join,
+ SkPaint::kRound_Join
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gJoins); i++) {
+ canvas->save();
+ for (size_t j = 0; j < SK_ARRAY_COUNT(fPath); j++) {
+ this->drawPath(canvas, fPath[j], gJoins[i]);
+ canvas->translate(SkIntToScalar(200), 0);
+ }
+ canvas->restore();
+
+ canvas->translate(0, SkIntToScalar(200));
+ }
+
+ this->nextStroke();
+ this->inval(NULL);
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ fShowHairline = !fShowHairline;
+ this->inval(NULL);
+ return this->INHERITED::onFindClickHandler(x, y);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new PathView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SamplePathClip.cpp b/samplecode/SamplePathClip.cpp
new file mode 100644
index 0000000..8139171
--- /dev/null
+++ b/samplecode/SamplePathClip.cpp
@@ -0,0 +1,84 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+
+class PathClipView : public SampleView {
+public:
+ SkRect fOval;
+ SkPoint fCenter;
+
+ PathClipView() {
+ fOval.set(0, 0, SkIntToScalar(200), SkIntToScalar(50));
+ fCenter.set(SkIntToScalar(250), SkIntToScalar(250));
+
+// test_ats();
+ }
+
+ virtual ~PathClipView() {}
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "PathClip");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkRect oval = fOval;
+ oval.offset(fCenter.fX - oval.centerX(), fCenter.fY - oval.centerY());
+
+ SkPaint p;
+ p.setAntiAlias(true);
+
+ p.setStyle(SkPaint::kStroke_Style);
+ canvas->drawOval(oval, p);
+
+ SkRect r;
+ r.set(SkIntToScalar(200), SkIntToScalar(200),
+ SkIntToScalar(300), SkIntToScalar(300));
+ canvas->clipRect(r);
+
+ p.setStyle(SkPaint::kFill_Style);
+ p.setColor(SK_ColorRED);
+ canvas->drawRect(r, p);
+
+ p.setColor(0x800000FF);
+ r.set(SkIntToScalar(150), SkIntToScalar(10),
+ SkIntToScalar(250), SkIntToScalar(400));
+ canvas->drawOval(oval, p);
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ return new Click(this);
+ }
+
+ virtual bool onClick(Click* click) {
+ fCenter.set(click->fCurr.fX, click->fCurr.fY);
+ this->inval(NULL);
+ return NULL;
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new PathClipView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SamplePathEffects.cpp b/samplecode/SamplePathEffects.cpp
new file mode 100644
index 0000000..75566b0
--- /dev/null
+++ b/samplecode/SamplePathEffects.cpp
@@ -0,0 +1,184 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "Sk1DPathEffect.h"
+#include "SkCornerPathEffect.h"
+#include "SkPathMeasure.h"
+#include "SkRandom.h"
+#include "SkColorPriv.h"
+#include "SkPixelXorXfermode.h"
+
+#define CORNER_RADIUS 12
+static SkScalar gPhase;
+
+static const int gXY[] = {
+ 4, 0, 0, -4, 8, -4, 12, 0, 8, 4, 0, 4
+};
+
+static SkPathEffect* make_pe(int flags) {
+ if (flags == 1)
+ return new SkCornerPathEffect(SkIntToScalar(CORNER_RADIUS));
+
+ SkPath path;
+ path.moveTo(SkIntToScalar(gXY[0]), SkIntToScalar(gXY[1]));
+ for (unsigned i = 2; i < SK_ARRAY_COUNT(gXY); i += 2)
+ path.lineTo(SkIntToScalar(gXY[i]), SkIntToScalar(gXY[i+1]));
+ path.close();
+ path.offset(SkIntToScalar(-6), 0);
+
+ SkPathEffect* outer = new SkPath1DPathEffect(path, SkIntToScalar(12), gPhase, SkPath1DPathEffect::kRotate_Style);
+
+ if (flags == 2)
+ return outer;
+
+ SkPathEffect* inner = new SkCornerPathEffect(SkIntToScalar(CORNER_RADIUS));
+
+ SkPathEffect* pe = new SkComposePathEffect(outer, inner);
+ outer->unref();
+ inner->unref();
+ return pe;
+}
+
+static SkPathEffect* make_warp_pe() {
+ SkPath path;
+ path.moveTo(SkIntToScalar(gXY[0]), SkIntToScalar(gXY[1]));
+ for (unsigned i = 2; i < SK_ARRAY_COUNT(gXY); i += 2)
+ path.lineTo(SkIntToScalar(gXY[i]), SkIntToScalar(gXY[i+1]));
+ path.close();
+ path.offset(SkIntToScalar(-6), 0);
+
+ SkPathEffect* outer = new SkPath1DPathEffect(path, SkIntToScalar(12), gPhase, SkPath1DPathEffect::kMorph_Style);
+ SkPathEffect* inner = new SkCornerPathEffect(SkIntToScalar(CORNER_RADIUS));
+
+ SkPathEffect* pe = new SkComposePathEffect(outer, inner);
+ outer->unref();
+ inner->unref();
+ return pe;
+}
+
+///////////////////////////////////////////////////////////
+
+#include "SkColorFilter.h"
+#include "SkLayerRasterizer.h"
+
+class testrast : public SkLayerRasterizer {
+public:
+ testrast() {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+#if 0
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SK_Scalar1*4);
+ this->addLayer(paint);
+
+ paint.setStrokeWidth(SK_Scalar1*1);
+ paint.setXfermode(SkXfermode::kClear_Mode);
+ this->addLayer(paint);
+#else
+ paint.setAlpha(0x66);
+ this->addLayer(paint, SkIntToScalar(4), SkIntToScalar(4));
+
+ paint.setAlpha(0xFF);
+ this->addLayer(paint);
+#endif
+ }
+};
+
+class PathEffectView : public SampleView {
+ SkPath fPath;
+ SkPoint fClickPt;
+public:
+ PathEffectView() {
+ SkRandom rand;
+ int steps = 20;
+ SkScalar dist = SkIntToScalar(400);
+ SkScalar x = SkIntToScalar(20);
+ SkScalar y = SkIntToScalar(50);
+
+ fPath.moveTo(x, y);
+ for (int i = 0; i < steps; i++) {
+ x += dist/steps;
+ SkScalar tmpY = y + SkIntToScalar(rand.nextS() % 25);
+ if (i == steps/2) {
+ fPath.moveTo(x, tmpY);
+ } else {
+ fPath.lineTo(x, tmpY);
+ }
+ }
+
+ {
+ SkRect oval;
+ oval.set(SkIntToScalar(20), SkIntToScalar(30),
+ SkIntToScalar(100), SkIntToScalar(60));
+ oval.offset(x, 0);
+ fPath.addRoundRect(oval, SkIntToScalar(8), SkIntToScalar(8));
+ }
+
+ fClickPt.set(SkIntToScalar(200), SkIntToScalar(200));
+
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "PathEffects");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ gPhase -= SampleCode::GetAnimSecondsDelta() * 40;
+ this->inval(NULL);
+
+ SkPaint paint;
+
+#if 0
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkIntToScalar(5));
+ canvas->drawPath(fPath, paint);
+ paint.setStrokeWidth(0);
+
+ paint.setColor(SK_ColorWHITE);
+ paint.setPathEffect(make_pe(1))->unref();
+ canvas->drawPath(fPath, paint);
+#endif
+
+ canvas->translate(0, SkIntToScalar(50));
+
+ paint.setColor(SK_ColorBLUE);
+ paint.setPathEffect(make_pe(2))->unref();
+ canvas->drawPath(fPath, paint);
+
+ canvas->translate(0, SkIntToScalar(50));
+
+ paint.setARGB(0xFF, 0, 0xBB, 0);
+ paint.setPathEffect(make_pe(3))->unref();
+ canvas->drawPath(fPath, paint);
+
+ canvas->translate(0, SkIntToScalar(50));
+
+ paint.setARGB(0xFF, 0, 0, 0);
+ paint.setPathEffect(make_warp_pe())->unref();
+ paint.setRasterizer(new testrast)->unref();
+ canvas->drawPath(fPath, paint);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new PathEffectView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SamplePathFill.cpp b/samplecode/SamplePathFill.cpp
new file mode 100644
index 0000000..845b7a8
--- /dev/null
+++ b/samplecode/SamplePathFill.cpp
@@ -0,0 +1,140 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGraphics.h"
+#include "SkRandom.h"
+#include "SkBlurDrawLooper.h"
+#include "SkGradientShader.h"
+
+typedef SkScalar (*MakePathProc)(SkPath*);
+
+static SkScalar make_frame(SkPath* path) {
+ SkRect r = { 10, 10, 630, 470 };
+ path->addRoundRect(r, 15, 15);
+
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(5);
+ paint.getFillPath(*path, path);
+ return 15;
+}
+
+static SkScalar make_triangle(SkPath* path) {
+ static const int gCoord[] = {
+ 10, 20, 15, 5, 30, 30
+ };
+ path->moveTo(SkIntToScalar(gCoord[0]), SkIntToScalar(gCoord[1]));
+ path->lineTo(SkIntToScalar(gCoord[2]), SkIntToScalar(gCoord[3]));
+ path->lineTo(SkIntToScalar(gCoord[4]), SkIntToScalar(gCoord[5]));
+ path->close();
+ path->offset(10, 0);
+ return SkIntToScalar(30);
+}
+
+static SkScalar make_rect(SkPath* path) {
+ SkRect r = { 10, 10, 30, 30 };
+ path->addRect(r);
+ path->offset(10, 0);
+ return SkIntToScalar(30);
+}
+
+static SkScalar make_oval(SkPath* path) {
+ SkRect r = { 10, 10, 30, 30 };
+ path->addOval(r);
+ path->offset(10, 0);
+ return SkIntToScalar(30);
+}
+
+static SkScalar make_sawtooth(SkPath* path) {
+ SkScalar x = SkIntToScalar(20);
+ SkScalar y = SkIntToScalar(20);
+ const SkScalar x0 = x;
+ const SkScalar dx = SK_Scalar1 * 5;
+ const SkScalar dy = SK_Scalar1 * 10;
+
+ path->moveTo(x, y);
+ for (int i = 0; i < 32; i++) {
+ x += dx;
+ path->lineTo(x, y - dy);
+ x += dx;
+ path->lineTo(x, y + dy);
+ }
+ path->lineTo(x, y + 2 * dy);
+ path->lineTo(x0, y + 2 * dy);
+ path->close();
+ return SkIntToScalar(30);
+}
+
+static SkScalar make_star(SkPath* path, int n) {
+ const SkScalar c = SkIntToScalar(45);
+ const SkScalar r = SkIntToScalar(20);
+
+ SkScalar rad = -SK_ScalarPI / 2;
+ const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n;
+
+ path->moveTo(c, c - r);
+ for (int i = 1; i < n; i++) {
+ rad += drad;
+ SkScalar cosV, sinV = SkScalarSinCos(rad, &cosV);
+ path->lineTo(c + SkScalarMul(cosV, r), c + SkScalarMul(sinV, r));
+ }
+ path->close();
+ return r * 2 * 6 / 5;
+}
+
+static SkScalar make_star_5(SkPath* path) { return make_star(path, 5); }
+static SkScalar make_star_13(SkPath* path) { return make_star(path, 13); }
+
+static const MakePathProc gProcs[] = {
+ make_frame,
+ make_triangle,
+ make_rect,
+ make_oval,
+ make_sawtooth,
+ make_star_5,
+ make_star_13
+};
+
+#define N SK_ARRAY_COUNT(gProcs)
+
+class PathFillView : public SampleView {
+ SkPath fPath[N];
+ SkScalar fDY[N];
+
+public:
+ PathFillView() {
+ for (size_t i = 0; i < N; i++) {
+ fDY[i] = gProcs[i](&fPath[i]);
+ }
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "PathFill");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ for (size_t i = 0; i < N; i++) {
+ canvas->drawPath(fPath[i], paint);
+ canvas->translate(0, fDY[i]);
+ }
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new PathFillView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SamplePicture.cpp b/samplecode/SamplePicture.cpp
new file mode 100644
index 0000000..d7b6b22
--- /dev/null
+++ b/samplecode/SamplePicture.cpp
@@ -0,0 +1,254 @@
+#include "SampleCode.h"
+#include "SkDumpCanvas.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "Sk64.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPath.h"
+#include "SkPicture.h"
+#include "SkRandom.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkShape.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+#include "SkXfermode.h"
+
+#include "SkStream.h"
+#include "SkXMLParser.h"
+
+class SignalShape : public SkShape {
+public:
+ SignalShape() : fSignal(0) {}
+
+ SkShape* setSignal(int n) {
+ fSignal = n;
+ return this;
+ }
+
+protected:
+ virtual void onDraw(SkCanvas* canvas) {
+ // SkDebugf("---- sc %d\n", canvas->getSaveCount() - 1);
+ }
+
+private:
+ int fSignal;
+};
+
+static SkPMColor SignalProc(SkPMColor src, SkPMColor dst) {
+ return dst;
+}
+
+/* Picture playback will skip blocks of draw calls that follow a clip() call
+ that returns empty, and jump down to the corresponding restore() call.
+
+ This is a great preformance win for drawing very large/tall pictures with
+ a small visible window (think scrolling a long document). These tests make
+ sure that (a) we are performing the culling, and (b) we don't get confused
+ by nested save() calls, nor by calls to restoreToCount().
+ */
+static void test_saveRestoreCulling() {
+ SkPaint signalPaint;
+ SignalShape signalShape;
+
+ SkPicture pic;
+ SkRect r = SkRect::MakeWH(0, 0);
+ int n;
+ SkCanvas* canvas = pic.beginRecording(100, 100);
+ int startN = canvas->getSaveCount();
+ SkDebugf("---- start sc %d\n", startN);
+ canvas->drawShape(signalShape.setSignal(1));
+ canvas->save();
+ canvas->drawShape(signalShape.setSignal(2));
+ n = canvas->save();
+ canvas->drawShape(signalShape.setSignal(3));
+ canvas->save();
+ canvas->clipRect(r);
+ canvas->drawShape(signalShape.setSignal(4));
+ canvas->restoreToCount(n);
+ canvas->drawShape(signalShape.setSignal(5));
+ canvas->restore();
+ canvas->drawShape(signalShape.setSignal(6));
+ SkASSERT(canvas->getSaveCount() == startN);
+
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
+ bm.allocPixels();
+ SkCanvas c(bm);
+ c.drawPicture(pic);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkImageRef_GlobalPool.h"
+
+static SkBitmap load_bitmap() {
+ SkStream* stream = new SkFILEStream("/skimages/sesame_street_ensemble-hp.jpg");
+ SkAutoUnref aur(stream);
+
+ SkBitmap bm;
+ if (SkImageDecoder::DecodeStream(stream, &bm, SkBitmap::kNo_Config,
+ SkImageDecoder::kDecodeBounds_Mode)) {
+ SkPixelRef* pr = new SkImageRef_GlobalPool(stream, bm.config(), 1);
+ bm.setPixelRef(pr)->unref();
+ }
+ return bm;
+}
+
+static void drawCircle(SkCanvas* canvas, int r, SkColor color) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(color);
+
+ canvas->drawCircle(SkIntToScalar(r), SkIntToScalar(r), SkIntToScalar(r),
+ paint);
+}
+
+class PictureView : public SampleView {
+ SkBitmap fBitmap;
+public:
+ PictureView() {
+ SkImageRef_GlobalPool::SetRAMBudget(16 * 1024);
+
+ fBitmap = load_bitmap();
+
+ fPicture = new SkPicture;
+ SkCanvas* canvas = fPicture->beginRecording(100, 100);
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ canvas->drawBitmap(fBitmap, 0, 0, NULL);
+
+ drawCircle(canvas, 50, SK_ColorBLACK);
+ fSubPicture = new SkPicture;
+ canvas->drawPicture(*fSubPicture);
+ canvas->translate(SkIntToScalar(50), 0);
+ canvas->drawPicture(*fSubPicture);
+ canvas->translate(0, SkIntToScalar(50));
+ canvas->drawPicture(*fSubPicture);
+ canvas->translate(SkIntToScalar(-50), 0);
+ canvas->drawPicture(*fSubPicture);
+ // fPicture now has (4) references to us. We can release ours, and just
+ // unref fPicture in our destructor, and it will in turn take care of
+ // the other references to fSubPicture
+ fSubPicture->unref();
+
+ test_saveRestoreCulling();
+ }
+
+ virtual ~PictureView() {
+ fPicture->unref();
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Picture");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawSomething(SkCanvas* canvas) {
+ SkPaint paint;
+
+ canvas->save();
+ canvas->scale(0.5f, 0.5f);
+ canvas->drawBitmap(fBitmap, 0, 0, NULL);
+ canvas->restore();
+
+ const char beforeStr[] = "before circle";
+ const char afterStr[] = "after circle";
+
+ paint.setAntiAlias(true);
+
+ paint.setColor(SK_ColorRED);
+ canvas->drawData(beforeStr, sizeof(beforeStr));
+ canvas->drawCircle(SkIntToScalar(50), SkIntToScalar(50),
+ SkIntToScalar(40), paint);
+ canvas->drawData(afterStr, sizeof(afterStr));
+ paint.setColor(SK_ColorBLACK);
+ paint.setTextSize(SkIntToScalar(40));
+ canvas->drawText("Picture", 7, SkIntToScalar(50), SkIntToScalar(62),
+ paint);
+
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ drawSomething(canvas);
+
+ SkPicture* pict = new SkPicture;
+ SkAutoUnref aur(pict);
+
+ drawSomething(pict->beginRecording(100, 100));
+ pict->endRecording();
+
+ canvas->save();
+ canvas->translate(SkIntToScalar(300), SkIntToScalar(50));
+ canvas->scale(-SK_Scalar1, -SK_Scalar1);
+ canvas->translate(-SkIntToScalar(100), -SkIntToScalar(50));
+ canvas->drawPicture(*pict);
+ canvas->restore();
+
+ canvas->save();
+ canvas->translate(SkIntToScalar(200), SkIntToScalar(150));
+ canvas->scale(SK_Scalar1, -SK_Scalar1);
+ canvas->translate(0, -SkIntToScalar(50));
+ canvas->drawPicture(*pict);
+ canvas->restore();
+
+ canvas->save();
+ canvas->translate(SkIntToScalar(100), SkIntToScalar(100));
+ canvas->scale(-SK_Scalar1, SK_Scalar1);
+ canvas->translate(-SkIntToScalar(100), 0);
+ canvas->drawPicture(*pict);
+ canvas->restore();
+
+ if (false) {
+ SkDebugfDumper dumper;
+ SkDumpCanvas dumpCanvas(&dumper);
+ dumpCanvas.drawPicture(*pict);
+ }
+
+ // test that we can re-record a subpicture, and see the results
+
+ SkRandom rand(SampleCode::GetAnimTime());
+ canvas->translate(SkIntToScalar(10), SkIntToScalar(250));
+ drawCircle(fSubPicture->beginRecording(50, 50), 25,
+ rand.nextU() | 0xFF000000);
+ canvas->drawPicture(*fPicture);
+ delayInval(500);
+ }
+
+private:
+ #define INVAL_ALL_TYPE "inval-all"
+
+ void delayInval(SkMSec delay) {
+ (new SkEvent(INVAL_ALL_TYPE))->post(this->getSinkID(), delay);
+ }
+
+ virtual bool onEvent(const SkEvent& evt) {
+ if (evt.isType(INVAL_ALL_TYPE)) {
+ this->inval(NULL);
+ return true;
+ }
+ return this->INHERITED::onEvent(evt);
+ }
+
+ SkPicture* fPicture;
+ SkPicture* fSubPicture;
+
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new PictureView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SamplePoints.cpp b/samplecode/SamplePoints.cpp
new file mode 100644
index 0000000..a2804b4
--- /dev/null
+++ b/samplecode/SamplePoints.cpp
@@ -0,0 +1,78 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "Sk64.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkKernel33MaskFilter.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"
+
+class PointsView : public SampleView {
+public:
+ PointsView() {}
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Points");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ static void fill_pts(SkPoint pts[], size_t n, SkRandom* rand) {
+ for (size_t i = 0; i < n; i++)
+ pts[i].set(rand->nextUScalar1() * 640, rand->nextUScalar1() * 480);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ canvas->translate(SK_Scalar1, SK_Scalar1);
+
+ SkRandom rand;
+ SkPaint p0, p1, p2, p3;
+ const size_t n = 99;
+
+ p0.setColor(SK_ColorRED);
+ p1.setColor(SK_ColorGREEN);
+ p2.setColor(SK_ColorBLUE);
+ p3.setColor(SK_ColorWHITE);
+
+ p0.setStrokeWidth(SkIntToScalar(4));
+ p2.setStrokeCap(SkPaint::kRound_Cap);
+ p2.setStrokeWidth(SkIntToScalar(6));
+
+ SkPoint* pts = new SkPoint[n];
+ fill_pts(pts, n, &rand);
+
+ canvas->drawPoints(SkCanvas::kPolygon_PointMode, n, pts, p0);
+ canvas->drawPoints(SkCanvas::kLines_PointMode, n, pts, p1);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, n, pts, p2);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, n, pts, p3);
+
+ delete[] pts;
+ }
+
+private:
+
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new PointsView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SamplePolyToPoly.cpp b/samplecode/SamplePolyToPoly.cpp
new file mode 100644
index 0000000..aea0cb4
--- /dev/null
+++ b/samplecode/SamplePolyToPoly.cpp
@@ -0,0 +1,161 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGraphics.h"
+#include "SkPath.h"
+#include "SkRandom.h"
+#include "SkTime.h"
+
+extern bool SkSetPoly3To3(SkMatrix* matrix, const SkPoint src[3], const SkPoint dst[3]);
+
+class PolyToPolyView : public SampleView {
+public:
+ PolyToPolyView() {
+ // tests
+ {
+ SkPoint src[] = { { 0, 0 },
+ { SK_Scalar1, 0 },
+ { 0, SK_Scalar1 } };
+ SkPoint dst[] = { { 0, 0 },
+ { 2*SK_Scalar1, 0 },
+ { 0, 2*SK_Scalar1 } };
+ SkMatrix m1, m2;
+ bool success;
+
+ success = m1.setPolyToPoly(src, dst, 3);
+
+ m2.reset();
+ m2.set(SkMatrix::kMScaleX, dst[1].fX - dst[0].fX);
+ m2.set(SkMatrix::kMSkewX, dst[2].fX - dst[0].fX);
+ m2.set(SkMatrix::kMTransX, dst[0].fX);
+ m2.set(SkMatrix::kMSkewY, dst[1].fY - dst[0].fY);
+ m2.set(SkMatrix::kMScaleY, dst[2].fY - dst[0].fY);
+ m2.set(SkMatrix::kMTransY, dst[0].fY);
+
+ m1.reset();
+
+ const SkScalar src1[] = {
+ 0, 0, 0, SkFloatToScalar(427), SkFloatToScalar(316), SkFloatToScalar(427), SkFloatToScalar(316), 0
+ };
+ const SkScalar dst1[] = {
+ SkFloatToScalar(158), SkFloatToScalar(177.5f), SkFloatToScalar(158), SkFloatToScalar(249.5f),
+ SkFloatToScalar(158), SkFloatToScalar(604.5f), SkFloatToScalar(158), SkFloatToScalar(-177.5f)
+ };
+
+ success = m2.setPolyToPoly((const SkPoint*)src1, (SkPoint*)dst1, 4);
+
+ {
+ const SkPoint src[] = {
+ { SkIntToScalar(1), SkIntToScalar(0) },
+ { SkIntToScalar(4), SkIntToScalar(7) },
+ { SkIntToScalar(10), SkIntToScalar(2) }
+ };
+ const SkPoint dst[] = {
+ { SkIntToScalar(4), SkIntToScalar(2) },
+ { SkIntToScalar(45), SkIntToScalar(26) },
+ { SkIntToScalar(32), SkIntToScalar(17) }
+ };
+
+ SkMatrix m0, m1;
+ m0.setPolyToPoly(src, dst, 3);
+ // SkSetPoly3To3(&m1, src, dst);
+ // m0.dump();
+ // m1.dump();
+ }
+ }
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SkString str("PolyToPolyView");
+ SampleCode::TitleR(evt, str.c_str());
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ static void doDraw(SkCanvas* canvas, SkPaint* paint, const int isrc[],
+ const int idst[], int count) {
+ SkMatrix matrix;
+ SkPoint src[4], dst[4];
+
+ for (int i = 0; i < count; i++) {
+ src[i].set(SkIntToScalar(isrc[2*i+0]), SkIntToScalar(isrc[2*i+1]));
+ dst[i].set(SkIntToScalar(idst[2*i+0]), SkIntToScalar(idst[2*i+1]));
+ }
+
+ canvas->save();
+ matrix.setPolyToPoly(src, dst, count);
+ canvas->concat(matrix);
+
+ paint->setColor(SK_ColorGRAY);
+ paint->setStyle(SkPaint::kStroke_Style);
+ const SkScalar D = SkIntToScalar(64);
+ canvas->drawRectCoords(0, 0, D, D, *paint);
+ canvas->drawLine(0, 0, D, D, *paint);
+ canvas->drawLine(0, D, D, 0, *paint);
+
+ SkPaint::FontMetrics fm;
+ paint->getFontMetrics(&fm);
+ paint->setColor(SK_ColorRED);
+ paint->setStyle(SkPaint::kFill_Style);
+ SkScalar x = D/2;
+ float y = D/2 - (fm.fAscent + fm.fDescent)/2;
+ SkString str;
+ str.appendS32(count);
+ canvas->drawText(str.c_str(), str.size(), x, y, *paint);
+
+ canvas->restore();
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStrokeWidth(SkIntToScalar(4));
+ paint.setTextSize(SkIntToScalar(40));
+ paint.setTextAlign(SkPaint::kCenter_Align);
+
+ canvas->save();
+ canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
+ // translate (1 point)
+ const int src1[] = { 0, 0 };
+ const int dst1[] = { 5, 5 };
+ doDraw(canvas, &paint, src1, dst1, 1);
+ canvas->restore();
+
+ canvas->save();
+ canvas->translate(SkIntToScalar(160), SkIntToScalar(10));
+ // rotate/uniform-scale (2 points)
+ const int src2[] = { 32, 32, 64, 32 };
+ const int dst2[] = { 32, 32, 64, 48 };
+ doDraw(canvas, &paint, src2, dst2, 2);
+ canvas->restore();
+
+ canvas->save();
+ canvas->translate(SkIntToScalar(10), SkIntToScalar(110));
+ // rotate/skew (3 points)
+ const int src3[] = { 0, 0, 64, 0, 0, 64 };
+ const int dst3[] = { 0, 0, 96, 0, 24, 64 };
+ doDraw(canvas, &paint, src3, dst3, 3);
+ canvas->restore();
+
+ canvas->save();
+ canvas->translate(SkIntToScalar(160), SkIntToScalar(110));
+ // perspective (4 points)
+ const int src4[] = { 0, 0, 64, 0, 64, 64, 0, 64 };
+ const int dst4[] = { 0, 0, 96, 0, 64, 96, 0, 64 };
+ doDraw(canvas, &paint, src4, dst4, 4);
+ canvas->restore();
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new PolyToPolyView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleRegion.cpp b/samplecode/SampleRegion.cpp
new file mode 100644
index 0000000..822bd6f
--- /dev/null
+++ b/samplecode/SampleRegion.cpp
@@ -0,0 +1,273 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkImageDecoder.h"
+
+#ifdef SK_BUILD_FOR_WIN
+// windows doesn't have roundf
+inline float roundf(float x) { return (x-floor(x))>0.5 ? ceil(x) : floor(x); }
+#endif
+
+#ifdef SK_DEBUG
+static void make_rgn(SkRegion* rgn, int left, int top, int right, int bottom,
+ size_t count, int32_t runs[]) {
+ SkIRect r;
+ r.set(left, top, right, bottom);
+
+ rgn->debugSetRuns(runs, count);
+ SkASSERT(rgn->getBounds() == r);
+}
+
+static void test_union_bug_1505668(SkRegion* ra, SkRegion* rb, SkRegion* rc) {
+ static int32_t dataA[] = {
+ 0x00000001, 0x000001dd,
+ 0x00000001, 0x0000000c, 0x0000000d, 0x00000025,
+ 0x7fffffff, 0x000001de, 0x00000001, 0x00000025,
+ 0x7fffffff, 0x000004b3, 0x00000001, 0x00000026,
+ 0x7fffffff, 0x000004b4, 0x0000000c, 0x00000026,
+ 0x7fffffff, 0x00000579, 0x00000000, 0x0000013a,
+ 0x7fffffff, 0x000005d8, 0x00000000, 0x0000013b,
+ 0x7fffffff, 0x7fffffff
+ };
+ make_rgn(ra, 0, 1, 315, 1496, SK_ARRAY_COUNT(dataA), dataA);
+
+ static int32_t dataB[] = {
+ 0x000000b6, 0x000000c4,
+ 0x000000a1, 0x000000f0, 0x7fffffff, 0x000000d6,
+ 0x7fffffff, 0x000000e4, 0x00000070, 0x00000079,
+ 0x000000a1, 0x000000b0, 0x7fffffff, 0x000000e6,
+ 0x7fffffff, 0x000000f4, 0x00000070, 0x00000079,
+ 0x000000a1, 0x000000b0, 0x7fffffff, 0x000000f6,
+ 0x7fffffff, 0x00000104, 0x000000a1, 0x000000b0,
+ 0x7fffffff, 0x7fffffff
+ };
+ make_rgn(rb, 112, 182, 240, 260, SK_ARRAY_COUNT(dataB), dataB);
+
+ rc->op(*ra, *rb, SkRegion::kUnion_Op);
+}
+#endif
+
+static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
+ dst->fLeft = (int)::roundf(src.fLeft * scale);
+ dst->fTop = (int)::roundf(src.fTop * scale);
+ dst->fRight = (int)::roundf(src.fRight * scale);
+ dst->fBottom = (int)::roundf(src.fBottom * scale);
+}
+
+static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
+ SkRegion tmp;
+ SkRegion::Iterator iter(src);
+
+ for (; !iter.done(); iter.next()) {
+ SkIRect r;
+ scale_rect(&r, iter.rect(), scale);
+ tmp.op(r, SkRegion::kUnion_Op);
+ }
+ dst->swap(tmp);
+}
+
+static void paint_rgn(SkCanvas* canvas, const SkRegion& rgn,
+ const SkPaint& paint) {
+ SkRegion scaled;
+ scale_rgn(&scaled, rgn, 0.5f);
+
+ SkRegion::Iterator iter(rgn);
+
+ for (; !iter.done(); iter.next())
+ {
+ SkRect r;
+ r.set(iter.rect());
+ canvas->drawRect(r, paint);
+ }
+}
+
+class RegionView : public SampleView {
+public:
+ RegionView() {
+ fBase.set(100, 100, 150, 150);
+ fRect = fBase;
+ fRect.inset(5, 5);
+ fRect.offset(25, 25);
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+ void build_rgn(SkRegion* rgn, SkRegion::Op op) {
+ rgn->setRect(fBase);
+ SkIRect r = fBase;
+ r.offset(75, 20);
+ rgn->op(r, SkRegion::kUnion_Op);
+ rgn->op(fRect, op);
+ }
+
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Regions");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawOrig(SkCanvas* canvas, bool bg) {
+ SkRect r;
+ SkPaint paint;
+
+ paint.setStyle(SkPaint::kStroke_Style);
+ if (bg)
+ paint.setColor(0xFFBBBBBB);
+
+ r.set(fBase);
+ canvas->drawRect(r, paint);
+ r.set(fRect);
+ canvas->drawRect(r, paint);
+ }
+
+ void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
+ SkRegion rgn;
+
+ this->build_rgn(&rgn, op);
+
+ {
+ SkRegion tmp, tmp2(rgn);
+
+ tmp = tmp2;
+ tmp.translate(5, -3);
+
+ {
+ char buffer[1000];
+ size_t size = tmp.flatten(NULL);
+ SkASSERT(size <= sizeof(buffer));
+ size_t size2 = tmp.flatten(buffer);
+ SkASSERT(size == size2);
+
+ SkRegion tmp3;
+ size2 = tmp3.unflatten(buffer);
+ SkASSERT(size == size2);
+
+ SkASSERT(tmp3 == tmp);
+ }
+
+ rgn.translate(20, 30, &tmp);
+ SkASSERT(rgn.isEmpty() || tmp != rgn);
+ tmp.translate(-20, -30);
+ SkASSERT(tmp == rgn);
+ }
+
+ this->drawOrig(canvas, true);
+
+ SkPaint paint;
+ paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
+ paint_rgn(canvas, rgn, paint);
+
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setColor(color);
+ paint_rgn(canvas, rgn, paint);
+ }
+
+ void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
+ SkRegion rgn;
+ SkPath path;
+
+ this->build_rgn(&rgn, op);
+ rgn.getBoundaryPath(&path);
+
+ this->drawOrig(canvas, true);
+
+ SkPaint paint;
+
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
+ canvas->drawPath(path, paint);
+ paint.setColor(color);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawPath(path, paint);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+#ifdef SK_DEBUG
+ if (true) {
+ SkRegion a, b, c;
+ test_union_bug_1505668(&a, &b, &c);
+
+ if (false) { // draw the result of the test
+ SkPaint paint;
+
+ canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
+ paint.setColor(SK_ColorRED);
+ paint_rgn(canvas, a, paint);
+ paint.setColor(0x800000FF);
+ paint_rgn(canvas, b, paint);
+ paint.setColor(SK_ColorBLACK);
+ paint.setStyle(SkPaint::kStroke_Style);
+ // paint_rgn(canvas, c, paint);
+ return;
+ }
+ }
+#endif
+
+ static const struct {
+ SkColor fColor;
+ const char* fName;
+ SkRegion::Op fOp;
+ } gOps[] = {
+ { SK_ColorBLACK, "Difference", SkRegion::kDifference_Op },
+ { SK_ColorRED, "Intersect", SkRegion::kIntersect_Op },
+ { 0xFF008800, "Union", SkRegion::kUnion_Op },
+ { SK_ColorBLUE, "XOR", SkRegion::kXOR_Op }
+ };
+
+ SkPaint textPaint;
+ textPaint.setAntiAlias(true);
+ textPaint.setTextSize(SK_Scalar1*24);
+
+ this->drawOrig(canvas, false);
+ canvas->save();
+ canvas->translate(SkIntToScalar(200), 0);
+ this->drawRgnOped(canvas, SkRegion::kUnion_Op, SK_ColorBLACK);
+ canvas->restore();
+
+ canvas->translate(0, SkIntToScalar(200));
+
+ for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); op++) {
+ canvas->drawText(gOps[op].fName, strlen(gOps[op].fName), SkIntToScalar(75), SkIntToScalar(50), textPaint);
+
+ this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
+
+ canvas->save();
+ canvas->translate(0, SkIntToScalar(200));
+ this->drawPathOped(canvas, gOps[op].fOp, gOps[op].fColor);
+ canvas->restore();
+
+ canvas->translate(SkIntToScalar(200), 0);
+ }
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ return fRect.contains(SkScalarRound(x), SkScalarRound(y)) ? new Click(this) : NULL;
+ }
+
+ virtual bool onClick(Click* click) {
+ fRect.offset(click->fICurr.fX - click->fIPrev.fX,
+ click->fICurr.fY - click->fIPrev.fY);
+ this->inval(NULL);
+ return true;
+ }
+
+private:
+ SkIRect fBase, fRect;
+
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new RegionView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleRepeatTile.cpp b/samplecode/SampleRepeatTile.cpp
new file mode 100644
index 0000000..9867074
--- /dev/null
+++ b/samplecode/SampleRepeatTile.cpp
@@ -0,0 +1,86 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkShader.h"
+#include "SkKey.h"
+
+static void make_bitmap(SkBitmap* bm) {
+ const int W = 100;
+ const int H = 100;
+ bm->setConfig(SkBitmap::kARGB_8888_Config, W, H);
+ bm->allocPixels();
+
+ SkPaint paint;
+ SkCanvas canvas(*bm);
+ canvas.drawColor(SK_ColorWHITE);
+
+ const SkColor colors[] = {
+ SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE
+ };
+
+ for (int ix = 0; ix < W; ix += 1) {
+ SkScalar x = SkIntToScalar(ix) + SK_ScalarHalf;
+ paint.setColor(colors[ix & 3]);
+ canvas.drawLine(x, 0, x, SkIntToScalar(H - 1), paint);
+ }
+ paint.setColor(SK_ColorGRAY);
+ canvas.drawLine(0, 0, SkIntToScalar(W), 0, paint);
+}
+
+static void make_paint(SkPaint* paint, SkShader::TileMode tm) {
+ SkBitmap bm;
+ make_bitmap(&bm);
+
+ SkShader* shader = SkShader::CreateBitmapShader(bm, tm, tm);
+ paint->setShader(shader)->unref();
+}
+
+class RepeatTileView : public SampleView {
+public:
+ RepeatTileView() {
+ this->setBGColor(SK_ColorGRAY);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "RepeatTile");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+ make_paint(&paint, SkShader::kRepeat_TileMode);
+
+// canvas->scale(SK_Scalar1*2, SK_Scalar1);
+ canvas->translate(SkIntToScalar(100), SkIntToScalar(100));
+ canvas->drawPaint(paint);
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ this->inval(NULL);
+
+ return this->INHERITED::onFindClickHandler(x, y);
+ }
+
+ virtual bool onClick(Click* click) {
+ return this->INHERITED::onClick(click);
+ }
+
+ virtual bool handleKey(SkKey key) {
+ this->inval(NULL);
+ return true;
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new RepeatTileView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleShaderText.cpp b/samplecode/SampleShaderText.cpp
new file mode 100644
index 0000000..2748b55
--- /dev/null
+++ b/samplecode/SampleShaderText.cpp
@@ -0,0 +1,195 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkUnitMappers.h"
+
+static void makebm(SkBitmap* bm, SkBitmap::Config config, int w, int h) {
+ bm->setConfig(config, w, h);
+ bm->allocPixels();
+ bm->eraseColor(0);
+
+ SkCanvas canvas(*bm);
+ SkScalar s = SkIntToScalar(w < h ? w : h);
+ SkPoint pts[] = { { 0, 0 }, { s, s } };
+ SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
+ SkScalar pos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
+ SkPaint paint;
+
+ SkUnitMapper* um = NULL;
+
+ um = new SkCosineMapper;
+
+ SkAutoUnref au(um);
+
+ paint.setDither(true);
+ paint.setShader(SkGradientShader::CreateLinear(pts, colors, pos,
+ SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode, um))->unref();
+ canvas.drawPaint(paint);
+}
+
+SkShader* MakeBitmapShader(SkShader::TileMode tx, SkShader::TileMode ty,
+ int w, int h) {
+ static SkBitmap bmp;
+ if (bmp.isNull()) {
+ makebm(&bmp, SkBitmap::kARGB_8888_Config, w/2, h/4);
+ }
+ return SkShader::CreateBitmapShader(bmp, tx, ty);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+struct GradData {
+ int fCount;
+ const SkColor* fColors;
+ const SkScalar* fPos;
+};
+
+static const SkColor gColors[] = {
+ SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
+};
+
+static const GradData gGradData[] = {
+ { 2, gColors, NULL },
+ { 5, gColors, NULL },
+};
+
+static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, SkUnitMapper* mapper) {
+ return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
+ data.fCount, tm, mapper);
+}
+
+static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, SkUnitMapper* mapper) {
+ SkPoint center;
+ center.set(SkScalarAve(pts[0].fX, pts[1].fX),
+ SkScalarAve(pts[0].fY, pts[1].fY));
+ return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
+ data.fPos, data.fCount, tm, mapper);
+}
+
+static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, SkUnitMapper* mapper) {
+ SkPoint center;
+ center.set(SkScalarAve(pts[0].fX, pts[1].fX),
+ SkScalarAve(pts[0].fY, pts[1].fY));
+ return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
+ data.fPos, data.fCount, mapper);
+}
+
+static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, SkUnitMapper* mapper) {
+ SkPoint center0, center1;
+ center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
+ SkScalarAve(pts[0].fY, pts[1].fY));
+ center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
+ SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
+ return SkGradientShader::CreateTwoPointRadial(
+ center1, (pts[1].fX - pts[0].fX) / 7,
+ center0, (pts[1].fX - pts[0].fX) / 2,
+ data.fColors, data.fPos, data.fCount, tm, mapper);
+}
+
+typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, SkUnitMapper* mapper);
+static const GradMaker gGradMakers[] = {
+ MakeLinear, MakeRadial, MakeSweep, Make2Radial
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class ShaderTextView : public SampleView {
+public:
+ ShaderTextView() {
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Shader Text");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ const char text[] = "Shaded Text";
+ const int textLen = SK_ARRAY_COUNT(text) - 1;
+ static int pointSize = 48;
+
+ int w = pointSize * textLen;
+ int h = pointSize;
+
+ SkPoint pts[2] = {
+ { 0, 0 },
+ { SkIntToScalar(w), SkIntToScalar(h) }
+ };
+ SkScalar textBase = SkIntToScalar(h/2);
+
+ SkShader::TileMode tileModes[] = {
+ SkShader::kClamp_TileMode,
+ SkShader::kRepeat_TileMode,
+ SkShader::kMirror_TileMode
+ };
+
+ static const int gradCount = SK_ARRAY_COUNT(gGradData) *
+ SK_ARRAY_COUNT(gGradMakers);
+ static const int bmpCount = SK_ARRAY_COUNT(tileModes) *
+ SK_ARRAY_COUNT(tileModes);
+ SkShader* shaders[gradCount + bmpCount];
+
+ int shdIdx = 0;
+ for (size_t d = 0; d < SK_ARRAY_COUNT(gGradData); ++d) {
+ for (size_t m = 0; m < SK_ARRAY_COUNT(gGradMakers); ++m) {
+ shaders[shdIdx++] = gGradMakers[m](pts,
+ gGradData[d],
+ SkShader::kClamp_TileMode,
+ NULL);
+ }
+ }
+ for (size_t tx = 0; tx < SK_ARRAY_COUNT(tileModes); ++tx) {
+ for (size_t ty = 0; ty < SK_ARRAY_COUNT(tileModes); ++ty) {
+ shaders[shdIdx++] = MakeBitmapShader(tileModes[tx],
+ tileModes[ty],
+ w/8, h);
+ }
+ }
+
+ SkPaint paint;
+ paint.setDither(true);
+ paint.setAntiAlias(true);
+ paint.setTextSize(SkIntToScalar(pointSize));
+
+ canvas->save();
+ canvas->translate(SkIntToScalar(20), SkIntToScalar(10));
+
+ static const int testsPerCol = 8;
+ static const int rowHeight = 60;
+ static const int colWidth = 300;
+ canvas->save();
+ for (size_t s = 0; s < SK_ARRAY_COUNT(shaders); s++) {
+ canvas->save();
+ canvas->translate(SkIntToScalar((s / testsPerCol) * colWidth),
+ SkIntToScalar((s % testsPerCol) * rowHeight));
+ paint.setShader(shaders[s])->unref();
+ canvas->drawText(text, textLen, 0, textBase, paint);
+ canvas->restore();
+ }
+ canvas->restore();
+
+ canvas->translate(0, SkIntToScalar(370));
+ this->inval(NULL);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new ShaderTextView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleShaders.cpp b/samplecode/SampleShaders.cpp
new file mode 100644
index 0000000..c1bb0fd
--- /dev/null
+++ b/samplecode/SampleShaders.cpp
@@ -0,0 +1,134 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkComposeShader.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTransparentShader.h"
+#include "SkTypeface.h"
+
+static SkShader* make_bitmapfade(const SkBitmap& bm)
+{
+ SkPoint pts[2];
+ SkColor colors[2];
+
+ pts[0].set(0, 0);
+ pts[1].set(0, SkIntToScalar(bm.height()));
+ colors[0] = SK_ColorBLACK;
+ colors[1] = SkColorSetARGB(0, 0, 0, 0);
+ SkShader* shaderA = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode);
+
+ SkShader* shaderB = SkShader::CreateBitmapShader(bm,
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+
+ SkXfermode* mode = SkXfermode::Create(SkXfermode::kDstIn_Mode);
+
+ SkShader* shader = new SkComposeShader(shaderB, shaderA, mode);
+ shaderA->unref();
+ shaderB->unref();
+ mode->unref();
+
+ return shader;
+}
+
+class ShaderView : public SampleView {
+public:
+ SkShader* fShader;
+ SkBitmap fBitmap;
+
+ ShaderView() {
+ SkImageDecoder::DecodeFile("/skimages/logo.gif", &fBitmap);
+
+ SkPoint pts[2];
+ SkColor colors[2];
+
+ pts[0].set(0, 0);
+ pts[1].set(SkIntToScalar(100), 0);
+ colors[0] = SK_ColorRED;
+ colors[1] = SK_ColorBLUE;
+ SkShader* shaderA = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode);
+
+ pts[0].set(0, 0);
+ pts[1].set(0, SkIntToScalar(100));
+ colors[0] = SK_ColorBLACK;
+ colors[1] = SkColorSetARGB(0x80, 0, 0, 0);
+ SkShader* shaderB = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode);
+
+ SkXfermode* mode = SkXfermode::Create(SkXfermode::kDstIn_Mode);
+
+ fShader = new SkComposeShader(shaderA, shaderB, mode);
+ shaderA->unref();
+ shaderB->unref();
+ mode->unref();
+ }
+ virtual ~ShaderView() {
+ SkSafeUnref(fShader);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Shaders");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ canvas->drawBitmap(fBitmap, 0, 0);
+
+ canvas->translate(SkIntToScalar(20), SkIntToScalar(120));
+
+ SkPaint paint;
+ SkRect r;
+
+ paint.setColor(SK_ColorGREEN);
+ canvas->drawRectCoords(0, 0, SkIntToScalar(100), SkIntToScalar(100), paint);
+ paint.setShader(fShader);
+ canvas->drawRectCoords(0, 0, SkIntToScalar(100), SkIntToScalar(100), paint);
+
+ canvas->translate(SkIntToScalar(110), 0);
+
+ int w = fBitmap.width();
+ int h = fBitmap.height();
+ w = 120;
+ h = 80;
+ r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
+
+ paint.setShader(NULL);
+ canvas->drawRect(r, paint);
+ paint.setShader(make_bitmapfade(fBitmap))->unref();
+ canvas->drawRect(r, paint);
+
+ paint.setShader(new SkTransparentShader)->unref();
+ canvas->drawRect(r, paint);
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ this->inval(NULL);
+ return this->INHERITED::onFindClickHandler(x, y);
+ }
+
+ virtual bool onClick(Click* click) {
+ return this->INHERITED::onClick(click);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new ShaderView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleShapes.cpp b/samplecode/SampleShapes.cpp
new file mode 100644
index 0000000..dc10f1a
--- /dev/null
+++ b/samplecode/SampleShapes.cpp
@@ -0,0 +1,160 @@
+#include "SampleCode.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkPicture.h"
+#include "SkStream.h"
+#include "SkView.h"
+
+#define DO_AA true
+
+#include "SkRectShape.h"
+#include "SkGroupShape.h"
+
+static SkRect make_rect(int l, int t, int r, int b) {
+ SkRect rect;
+ rect.set(SkIntToScalar(l), SkIntToScalar(t),
+ SkIntToScalar(r), SkIntToScalar(b));
+ return rect;
+}
+
+static SkShape* make_shape0(bool red) {
+ SkRectShape* s = new SkRectShape;
+ s->setRect(make_rect(10, 10, 90, 90));
+ if (red) {
+ s->paint().setColor(SK_ColorRED);
+ }
+ s->paint().setAntiAlias(DO_AA);
+ return s;
+}
+
+static SkShape* make_shape1() {
+ SkRectShape* s = new SkRectShape;
+ s->setOval(make_rect(10, 10, 90, 90));
+ s->paint().setColor(SK_ColorBLUE);
+ s->paint().setAntiAlias(DO_AA);
+ return s;
+}
+
+static SkShape* make_shape2() {
+ SkRectShape* s = new SkRectShape;
+ s->setRRect(make_rect(10, 10, 90, 90),
+ SkIntToScalar(20), SkIntToScalar(20));
+ s->paint().setColor(SK_ColorGREEN);
+ s->paint().setAntiAlias(DO_AA);
+ return s;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class ShapesView : public SampleView {
+ SkGroupShape fGroup;
+ SkMatrixRef* fMatrixRefs[4];
+public:
+ ShapesView() {
+ SkMatrix m;
+ fGroup.appendShape(make_shape0(false))->unref();
+ m.setRotate(SkIntToScalar(30), SkIntToScalar(50), SkIntToScalar(50));
+ m.postTranslate(0, SkIntToScalar(120));
+ fGroup.appendShape(make_shape0(true), m)->unref();
+
+ m.setTranslate(SkIntToScalar(120), 0);
+ fGroup.appendShape(make_shape1(), m)->unref();
+ m.postTranslate(0, SkIntToScalar(120));
+ fGroup.appendShape(make_shape2(), m)->unref();
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(fMatrixRefs); i++) {
+ SkSafeRef(fMatrixRefs[i] = fGroup.getShapeMatrixRef(i));
+ }
+
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+ virtual ~ShapesView() {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(fMatrixRefs); i++) {
+ SkSafeUnref(fMatrixRefs[i]);
+ }
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Shapes");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawpicture(SkCanvas* canvas, SkPicture& pict) {
+#if 0
+ SkDynamicMemoryWStream ostream;
+ pict.serialize(&ostream);
+
+ SkMemoryStream istream(ostream.getStream(), ostream.getOffset());
+ SkPicture* newPict = new SkPicture(&istream);
+ canvas->drawPicture(*newPict);
+ newPict->unref();
+#else
+ canvas->drawPicture(pict);
+#endif
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkScalar angle = SampleCode::GetAnimScalar(SkIntToScalar(180),
+ SkIntToScalar(360));
+
+ SkMatrix saveM = *fMatrixRefs[3];
+ SkScalar c = SkIntToScalar(50);
+ fMatrixRefs[3]->preRotate(angle, c, c);
+
+ const SkScalar dx = 350;
+ const SkScalar dy = 500;
+ const int N = 1;
+ for (int v = -N; v <= N; v++) {
+ for (int h = -N; h <= N; h++) {
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->translate(h * dx, v * dy);
+
+ SkMatrix matrix;
+
+ SkGroupShape* gs = new SkGroupShape;
+ SkAutoUnref aur(gs);
+ gs->appendShape(&fGroup);
+ matrix.setScale(-SK_Scalar1, SK_Scalar1);
+ matrix.postTranslate(SkIntToScalar(220), SkIntToScalar(240));
+ gs->appendShape(&fGroup, matrix);
+ matrix.setTranslate(SkIntToScalar(240), 0);
+ matrix.preScale(SK_Scalar1*2, SK_Scalar1*2);
+ gs->appendShape(&fGroup, matrix);
+
+#if 0
+ canvas->drawShape(gs);
+#else
+ SkPicture* pict = new SkPicture;
+ SkCanvas* cv = pict->beginRecording(1000, 1000);
+ cv->scale(SK_ScalarHalf, SK_ScalarHalf);
+ cv->drawShape(gs);
+ cv->translate(SkIntToScalar(680), SkIntToScalar(480));
+ cv->scale(-SK_Scalar1, SK_Scalar1);
+ cv->drawShape(gs);
+ pict->endRecording();
+
+ drawpicture(canvas, *pict);
+ pict->unref();
+#endif
+
+ }}
+
+ *fMatrixRefs[3] = saveM;
+ this->inval(NULL);
+}
+
+private:
+ typedef SampleView INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new ShapesView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleSkLayer.cpp b/samplecode/SampleSkLayer.cpp
new file mode 100644
index 0000000..11976e9
--- /dev/null
+++ b/samplecode/SampleSkLayer.cpp
@@ -0,0 +1,239 @@
+#include "SampleCode.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkView.h"
+#include "SkLayer.h"
+
+#include "SkMatrix44.h"
+static void test_inv(const char label[], const SkMatrix44& mat) {
+ SkDebugf("%s\n", label);
+ mat.dump();
+
+ SkMatrix44 inv;
+ if (mat.invert(&inv)) {
+ inv.dump();
+ } else {
+ SkDebugf("--- invert failed\n");
+ }
+
+ SkMatrix44 a, b;
+ a.setConcat(mat, inv);
+ b.setConcat(inv, mat);
+ SkDebugf("concat mat with inverse pre=%d post=%d\n", a.isIdentity(), b.isIdentity());
+ if (!a.isIdentity()) {
+ a.dump();
+ }
+ if (!b.isIdentity()) {
+ b.dump();
+ }
+ SkDebugf("\n");
+}
+
+static void test_map(SkScalar x0, SkScalar y0, SkScalar z0,
+ const SkMatrix44& mat,
+ SkScalar x1, SkScalar y1, SkScalar z1) {
+ SkVector4 src, dst;
+ src.set(x0, y0, z0);
+ dst = mat * src;
+ SkDebugf("map: src: %g %g %g dst: %g %g %g (%g) expected: %g %g %g match: %d\n",
+ x0, y0, z0,
+ dst.fData[0], dst.fData[1], dst.fData[2], dst.fData[3],
+ x1, y1, z1,
+ dst.fData[0] == x1 && dst.fData[1] == y1 && dst.fData[2] == z1);
+}
+
+static void test_33(const SkMatrix44& mat,
+ SkScalar x0, SkScalar x1, SkScalar x2,
+ SkScalar y0, SkScalar y1, SkScalar y2) {
+ SkMatrix dst = mat;
+ if (dst[0] != x0 || dst[1] != x1 || dst[2] != x2 ||
+ dst[3] != y0 || dst[4] != y1 || dst[5] != y2) {
+ SkString str;
+ dst.toDumpString(&str);
+ SkDebugf("3x3: expected 3x3 [%g %g %g] [%g %g %g] bug got %s\n",
+ x0, x1, x2, y0, y1, y2, str.c_str());
+ }
+}
+
+static void test44() {
+ SkMatrix44 m0, m1, m2;
+
+ test_inv("identity", m0);
+ m0.setTranslate(2,3,4);
+ test_inv("translate", m0);
+ m0.setScale(2,3,4);
+ test_inv("scale", m0);
+ m0.postTranslate(5, 6, 7);
+ test_inv("postTranslate", m0);
+ m0.setScale(2,3,4);
+ m1.setTranslate(5, 6, 7);
+ m0.setConcat(m0, m1);
+ test_inv("postTranslate2", m0);
+ m0.setScale(2,3,4);
+ m0.preTranslate(5, 6, 7);
+ test_inv("preTranslate", m0);
+
+ m0.setScale(2, 4, 6);
+ m0.postScale(SkDoubleToMScalar(0.5));
+ test_inv("scale/postscale to 1,2,3", m0);
+
+ m0.reset();
+ test_map(1, 0, 0, m0, 1, 0, 0);
+ test_map(0, 1, 0, m0, 0, 1, 0);
+ test_map(0, 0, 1, m0, 0, 0, 1);
+ m0.setScale(2, 3, 4);
+ test_map(1, 0, 0, m0, 2, 0, 0);
+ test_map(0, 1, 0, m0, 0, 3, 0);
+ test_map(0, 0, 1, m0, 0, 0, 4);
+ m0.setTranslate(2, 3, 4);
+ test_map(0, 0, 0, m0, 2, 3, 4);
+ m0.preScale(5, 6, 7);
+ test_map(1, 0, 0, m0, 7, 3, 4);
+ test_map(0, 1, 0, m0, 2, 9, 4);
+ test_map(0, 0, 1, m0, 2, 3, 11);
+
+ SkMScalar deg = 45;
+ m0.setRotateDegreesAbout(0, 0, 1, deg);
+ test_map(1, 0, 0, m0, 0.707106769, -0.707106769, 0);
+
+ m0.reset();
+ test_33(m0, 1, 0, 0, 0, 1, 0);
+ m0.setTranslate(3, 4, 5);
+ test_33(m0, 1, 0, 3, 0, 1, 4);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void dump_layers(const SkLayer* layer, int tab = 0) {
+ SkMatrix matrix;
+ SkString matrixStr;
+
+ layer->getLocalTransform(&matrix);
+ matrix.toDumpString(&matrixStr);
+
+ for (int j = 0; j < tab; j++) {
+ SkDebugf(" ");
+ }
+ SkDebugf("layer=%p parent=%p size=[%g %g] transform=%s\n",
+ layer, layer->getParent(), layer->getWidth(), layer->getHeight(),
+ matrixStr.c_str());
+ for (int i = 0; i < layer->countChildren(); i++) {
+ dump_layers(layer->getChild(i), tab + 4);
+ }
+}
+
+class TestLayer : public SkLayer {
+public:
+ TestLayer(SkColor c) : fColor(c) {}
+
+protected:
+ virtual void onDraw(SkCanvas* canvas, SkScalar opacity) {
+ SkRect r;
+ r.set(0, 0, this->getWidth(), this->getHeight());
+
+ SkPaint paint;
+ paint.setColor(fColor);
+ paint.setAlpha(SkScalarRound(opacity * 255));
+
+ canvas->drawRect(r, paint);
+ }
+
+private:
+ SkColor fColor;
+};
+
+class SkLayerView : public SkView {
+private:
+ SkLayer* fRootLayer;
+ SkLayer* fLastChild;
+public:
+ SkLayerView() {
+ test44();
+ static const int W = 600;
+ static const int H = 440;
+ static const struct {
+ int fWidth;
+ int fHeight;
+ SkColor fColor;
+ int fPosX;
+ int fPosY;
+ } gData[] = {
+ { 120, 80, SK_ColorRED, 0, 0 },
+ { 120, 80, SK_ColorGREEN, W - 120, 0 },
+ { 120, 80, SK_ColorBLUE, 0, H - 80 },
+ { 120, 80, SK_ColorMAGENTA, W - 120, H - 80 },
+ };
+
+ fRootLayer = new TestLayer(0xFFDDDDDD);
+ fRootLayer->setSize(W, H);
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gData); i++) {
+ SkLayer* child = new TestLayer(gData[i].fColor);
+ child->setSize(gData[i].fWidth, gData[i].fHeight);
+ child->setPosition(gData[i].fPosX, gData[i].fPosY);
+ fRootLayer->addChild(child)->unref();
+ }
+
+ SkLayer* child = new TestLayer(0xFFDD8844);
+ child->setSize(120, 80);
+ child->setPosition(fRootLayer->getWidth()/2 - child->getWidth()/2,
+ fRootLayer->getHeight()/2 - child->getHeight()/2);
+ child->setAnchorPoint(SK_ScalarHalf, SK_ScalarHalf);
+ {
+ SkMatrix m;
+ m.setRotate(SkIntToScalar(30));
+ child->setMatrix(m);
+ }
+ fLastChild = child;
+ fRootLayer->addChild(child)->unref();
+
+ if (false) {
+ SkMatrix matrix;
+ matrix.setScale(0.5, 0.5);
+ fRootLayer->setMatrix(matrix);
+ }
+
+// dump_layers(fRootLayer);
+ }
+
+ virtual ~SkLayerView() {
+ SkSafeUnref(fRootLayer);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "SkLayer");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ canvas->drawColor(SK_ColorWHITE);
+
+ canvas->translate(20, 20);
+ fRootLayer->draw(canvas);
+
+ // visual test of getLocalTransform
+ if (true) {
+ SkMatrix matrix;
+ fLastChild->localToGlobal(&matrix);
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(5);
+ paint.setColor(0x88FF0000);
+ canvas->concat(matrix);
+ canvas->drawRect(SkRect::MakeSize(fLastChild->getSize()), paint);
+ }
+ }
+
+private:
+ typedef SkView INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new SkLayerView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleSlides.cpp b/samplecode/SampleSlides.cpp
new file mode 100644
index 0000000..3b7d05b
--- /dev/null
+++ b/samplecode/SampleSlides.cpp
@@ -0,0 +1,804 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkPaint.h"
+
+#define BG_COLOR 0xFFDDDDDD
+
+typedef void (*SlideProc)(SkCanvas*);
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "Sk1DPathEffect.h"
+#include "Sk2DPathEffect.h"
+#include "SkCornerPathEffect.h"
+#include "SkDashPathEffect.h"
+#include "SkDiscretePathEffect.h"
+
+static void compose_pe(SkPaint* paint) {
+ SkPathEffect* pe = paint->getPathEffect();
+ SkPathEffect* corner = new SkCornerPathEffect(25);
+ SkPathEffect* compose;
+ if (pe) {
+ compose = new SkComposePathEffect(pe, corner);
+ corner->unref();
+ } else {
+ compose = corner;
+ }
+ paint->setPathEffect(compose)->unref();
+}
+
+static void hair_pe(SkPaint* paint) {
+ paint->setStrokeWidth(0);
+}
+
+static void hair2_pe(SkPaint* paint) {
+ paint->setStrokeWidth(0);
+ compose_pe(paint);
+}
+
+static void stroke_pe(SkPaint* paint) {
+ paint->setStrokeWidth(12);
+ compose_pe(paint);
+}
+
+static void dash_pe(SkPaint* paint) {
+ SkScalar inter[] = { 20, 10, 10, 10 };
+ paint->setStrokeWidth(12);
+ paint->setPathEffect(new SkDashPathEffect(inter, SK_ARRAY_COUNT(inter),
+ 0))->unref();
+ compose_pe(paint);
+}
+
+static const int gXY[] = {
+4, 0, 0, -4, 8, -4, 12, 0, 8, 4, 0, 4
+};
+
+static void scale(SkPath* path, SkScalar scale) {
+ SkMatrix m;
+ m.setScale(scale, scale);
+ path->transform(m);
+}
+
+static void one_d_pe(SkPaint* paint) {
+ SkPath path;
+ path.moveTo(SkIntToScalar(gXY[0]), SkIntToScalar(gXY[1]));
+ for (unsigned i = 2; i < SK_ARRAY_COUNT(gXY); i += 2)
+ path.lineTo(SkIntToScalar(gXY[i]), SkIntToScalar(gXY[i+1]));
+ path.close();
+ path.offset(SkIntToScalar(-6), 0);
+ scale(&path, 1.5);
+
+ paint->setPathEffect(new SkPath1DPathEffect(path, SkIntToScalar(21), 0,
+ SkPath1DPathEffect::kRotate_Style))->unref();
+ compose_pe(paint);
+}
+
+typedef void (*PE_Proc)(SkPaint*);
+static const PE_Proc gPE[] = { hair_pe, hair2_pe, stroke_pe, dash_pe, one_d_pe };
+
+static void fill_pe(SkPaint* paint) {
+ paint->setStyle(SkPaint::kFill_Style);
+ paint->setPathEffect(NULL);
+}
+
+static void discrete_pe(SkPaint* paint) {
+ paint->setPathEffect(new SkDiscretePathEffect(10, 4))->unref();
+}
+
+class TilePathEffect : public Sk2DPathEffect {
+ static SkMatrix make_mat() {
+ SkMatrix m;
+ m.setScale(12, 12);
+ return m;
+ }
+public:
+ TilePathEffect() : Sk2DPathEffect(make_mat()) {}
+
+protected:
+ virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) {
+ dst->addCircle(loc.fX, loc.fY, 5);
+ }
+};
+
+static void tile_pe(SkPaint* paint) {
+ paint->setPathEffect(new TilePathEffect)->unref();
+}
+
+static const PE_Proc gPE2[] = { fill_pe, discrete_pe, tile_pe };
+
+static void patheffect_slide(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+
+ SkPath path;
+ path.moveTo(20, 20);
+ path.lineTo(70, 120);
+ path.lineTo(120, 30);
+ path.lineTo(170, 80);
+ path.lineTo(240, 50);
+
+ size_t i;
+ canvas->save();
+ for (i = 0; i < SK_ARRAY_COUNT(gPE); i++) {
+ gPE[i](&paint);
+ canvas->drawPath(path, paint);
+ canvas->translate(0, 75);
+ }
+ canvas->restore();
+
+ path.reset();
+ SkRect r = { 0, 0, 250, 120 };
+ path.addOval(r, SkPath::kCW_Direction);
+ r.inset(50, 50);
+ path.addRect(r, SkPath::kCCW_Direction);
+
+ canvas->translate(320, 20);
+ for (i = 0; i < SK_ARRAY_COUNT(gPE2); i++) {
+ gPE2[i](&paint);
+ canvas->drawPath(path, paint);
+ canvas->translate(0, 160);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkGradientShader.h"
+
+struct GradData {
+ int fCount;
+ const SkColor* fColors;
+ const SkScalar* fPos;
+};
+
+static const SkColor gColors[] = {
+SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
+};
+static const SkScalar gPos0[] = { 0, SK_Scalar1 };
+static const SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
+static const SkScalar gPos2[] = {
+0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1
+};
+
+static const GradData gGradData[] = {
+{ 2, gColors, NULL },
+{ 2, gColors, gPos0 },
+{ 2, gColors, gPos1 },
+{ 5, gColors, NULL },
+{ 5, gColors, gPos2 }
+};
+
+static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, SkUnitMapper* mapper) {
+ return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
+ data.fCount, tm, mapper);
+}
+
+static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, SkUnitMapper* mapper) {
+ SkPoint center;
+ center.set(SkScalarAve(pts[0].fX, pts[1].fX),
+ SkScalarAve(pts[0].fY, pts[1].fY));
+ return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
+ data.fPos, data.fCount, tm, mapper);
+}
+
+static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, SkUnitMapper* mapper) {
+ SkPoint center;
+ center.set(SkScalarAve(pts[0].fX, pts[1].fX),
+ SkScalarAve(pts[0].fY, pts[1].fY));
+ return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
+ data.fPos, data.fCount, mapper);
+}
+
+static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, SkUnitMapper* mapper) {
+ SkPoint center0, center1;
+ center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
+ SkScalarAve(pts[0].fY, pts[1].fY));
+ center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
+ SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
+ return SkGradientShader::CreateTwoPointRadial(
+ center1, (pts[1].fX - pts[0].fX) / 7,
+ center0, (pts[1].fX - pts[0].fX) / 2,
+ data.fColors, data.fPos, data.fCount, tm, mapper);
+}
+
+typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
+ SkShader::TileMode tm, SkUnitMapper* mapper);
+static const GradMaker gGradMakers[] = {
+ MakeLinear, MakeRadial, MakeSweep, Make2Radial
+};
+
+static void gradient_slide(SkCanvas* canvas) {
+ SkPoint pts[2] = {
+ { 0, 0 },
+ { SkIntToScalar(100), SkIntToScalar(100) }
+ };
+ SkShader::TileMode tm = SkShader::kClamp_TileMode;
+ SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setDither(true);
+
+ canvas->translate(SkIntToScalar(20), SkIntToScalar(10));
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
+ canvas->save();
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); j++) {
+ SkShader* shader = gGradMakers[j](pts, gGradData[i], tm, NULL);
+ paint.setShader(shader);
+ canvas->drawRect(r, paint);
+ shader->unref();
+ canvas->translate(0, SkIntToScalar(120));
+ }
+ canvas->restore();
+ canvas->translate(SkIntToScalar(120), 0);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkPathMeasure.h"
+
+static SkScalar getpathlen(const SkPath& path) {
+ SkPathMeasure meas(path, false);
+ return meas.getLength();
+}
+
+static void textonpath_slide(SkCanvas* canvas) {
+ const char* text = "Displacement";
+ size_t len =strlen(text);
+ SkPath path;
+ path.moveTo(100, 300);
+ path.quadTo(300, 100, 500, 300);
+ path.offset(0, -100);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setTextSize(40);
+
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawPath(path, paint);
+ paint.setStyle(SkPaint::kFill_Style);
+
+ SkScalar x = 50;
+ paint.setColor(0xFF008800);
+ canvas->drawTextOnPathHV(text, len, path,
+ x, paint.getTextSize()*2/3, paint);
+ paint.setColor(SK_ColorRED);
+ canvas->drawTextOnPathHV(text, len, path,
+ x + 60, 0, paint);
+ paint.setColor(SK_ColorBLUE);
+ canvas->drawTextOnPathHV(text, len, path,
+ x + 120, -paint.getTextSize()*2/3, paint);
+
+ path.offset(0, 200);
+ paint.setTextAlign(SkPaint::kRight_Align);
+
+ text = "Matrices";
+ len = strlen(text);
+ SkScalar pathLen = getpathlen(path);
+ SkMatrix matrix;
+
+ paint.setColor(SK_ColorBLACK);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawPath(path, paint);
+ paint.setStyle(SkPaint::kFill_Style);
+
+ paint.setTextSize(50);
+ canvas->drawTextOnPath(text, len, path, NULL, paint);
+
+ paint.setColor(SK_ColorRED);
+ matrix.setScale(-SK_Scalar1, SK_Scalar1);
+ matrix.postTranslate(pathLen, 0);
+ canvas->drawTextOnPath(text, len, path, &matrix, paint);
+
+ paint.setColor(SK_ColorBLUE);
+ matrix.setScale(SK_Scalar1, -SK_Scalar1);
+ canvas->drawTextOnPath(text, len, path, &matrix, paint);
+
+ paint.setColor(0xFF008800);
+ matrix.setScale(-SK_Scalar1, -SK_Scalar1);
+ matrix.postTranslate(pathLen, 0);
+ canvas->drawTextOnPath(text, len, path, &matrix, paint);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkImageDecoder.h"
+#include "SkOSFile.h"
+#include "SkRandom.h"
+#include "SkStream.h"
+#include "SkNinePatch.h"
+
+static SkShader* make_shader0(SkIPoint* size) {
+ SkBitmap bm;
+
+ SkImageDecoder::DecodeFile("/skimages/logo.gif", &bm);
+ size->set(bm.width(), bm.height());
+ return SkShader::CreateBitmapShader(bm, SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode);
+}
+
+static SkShader* make_shader1(const SkIPoint& size) {
+ SkPoint pts[] = { { 0, 0 },
+ { SkIntToScalar(size.fX), SkIntToScalar(size.fY) } };
+ SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorRED };
+ return SkGradientShader::CreateLinear(pts, colors, NULL,
+ SK_ARRAY_COUNT(colors), SkShader::kMirror_TileMode, NULL);
+}
+
+class Rec {
+public:
+ SkCanvas::VertexMode fMode;
+ int fCount;
+ SkPoint* fVerts;
+ SkPoint* fTexs;
+
+ Rec() : fCount(0), fVerts(NULL), fTexs(NULL) {}
+ ~Rec() { delete[] fVerts; delete[] fTexs; }
+};
+
+void make_tris(Rec* rec) {
+ int n = 10;
+ SkRandom rand;
+
+ rec->fMode = SkCanvas::kTriangles_VertexMode;
+ rec->fCount = n * 3;
+ rec->fVerts = new SkPoint[rec->fCount];
+
+ for (int i = 0; i < n; i++) {
+ SkPoint* v = &rec->fVerts[i*3];
+ for (int j = 0; j < 3; j++) {
+ v[j].set(rand.nextUScalar1() * 250, rand.nextUScalar1() * 250);
+ }
+ }
+}
+
+void make_fan(Rec* rec, int texWidth, int texHeight) {
+ const SkScalar tx = SkIntToScalar(texWidth);
+ const SkScalar ty = SkIntToScalar(texHeight);
+ const int n = 24;
+
+ rec->fMode = SkCanvas::kTriangleFan_VertexMode;
+ rec->fCount = n + 2;
+ rec->fVerts = new SkPoint[rec->fCount];
+ rec->fTexs = new SkPoint[rec->fCount];
+
+ SkPoint* v = rec->fVerts;
+ SkPoint* t = rec->fTexs;
+
+ v[0].set(0, 0);
+ t[0].set(0, 0);
+ for (int i = 0; i < n; i++) {
+ SkScalar cos;
+ SkScalar sin = SkScalarSinCos(SK_ScalarPI * 2 * i / n, &cos);
+ v[i+1].set(cos, sin);
+ t[i+1].set(i*tx/n, ty);
+ }
+ v[n+1] = v[1];
+ t[n+1].set(tx, ty);
+
+ SkMatrix m;
+ m.setScale(SkIntToScalar(100), SkIntToScalar(100));
+ m.postTranslate(SkIntToScalar(110), SkIntToScalar(110));
+ m.mapPoints(v, rec->fCount);
+}
+
+void make_strip(Rec* rec, int texWidth, int texHeight) {
+ const SkScalar tx = SkIntToScalar(texWidth);
+ const SkScalar ty = SkIntToScalar(texHeight);
+ const int n = 24;
+
+ rec->fMode = SkCanvas::kTriangleStrip_VertexMode;
+ rec->fCount = 2 * (n + 1);
+ rec->fVerts = new SkPoint[rec->fCount];
+ rec->fTexs = new SkPoint[rec->fCount];
+
+ SkPoint* v = rec->fVerts;
+ SkPoint* t = rec->fTexs;
+
+ for (int i = 0; i < n; i++) {
+ SkScalar cos;
+ SkScalar sin = SkScalarSinCos(SK_ScalarPI * 2 * i / n, &cos);
+ v[i*2 + 0].set(cos/2, sin/2);
+ v[i*2 + 1].set(cos, sin);
+
+ t[i*2 + 0].set(tx * i / n, ty);
+ t[i*2 + 1].set(tx * i / n, 0);
+ }
+ v[2*n + 0] = v[0];
+ v[2*n + 1] = v[1];
+
+ t[2*n + 0].set(tx, ty);
+ t[2*n + 1].set(tx, 0);
+
+ SkMatrix m;
+ m.setScale(SkIntToScalar(100), SkIntToScalar(100));
+ m.postTranslate(SkIntToScalar(110), SkIntToScalar(110));
+ m.mapPoints(v, rec->fCount);
+}
+
+static void mesh_slide(SkCanvas* canvas) {
+ Rec fRecs[3];
+ SkIPoint size;
+
+ SkShader* fShader0 = make_shader0(&size);
+ SkShader* fShader1 = make_shader1(size);
+
+ SkAutoUnref aur0(fShader0);
+ SkAutoUnref aur1(fShader1);
+
+ make_strip(&fRecs[0], size.fX, size.fY);
+ make_fan(&fRecs[1], size.fX, size.fY);
+ make_tris(&fRecs[2]);
+
+ SkPaint paint;
+ paint.setDither(true);
+ paint.setFilterBitmap(true);
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(fRecs); i++) {
+ canvas->save();
+
+ paint.setShader(NULL);
+ canvas->drawVertices(fRecs[i].fMode, fRecs[i].fCount,
+ fRecs[i].fVerts, fRecs[i].fTexs,
+ NULL, NULL, NULL, 0, paint);
+
+ canvas->translate(SkIntToScalar(210), 0);
+
+ paint.setShader(fShader0);
+ canvas->drawVertices(fRecs[i].fMode, fRecs[i].fCount,
+ fRecs[i].fVerts, fRecs[i].fTexs,
+ NULL, NULL, NULL, 0, paint);
+
+ canvas->translate(SkIntToScalar(210), 0);
+
+ paint.setShader(fShader1);
+ canvas->drawVertices(fRecs[i].fMode, fRecs[i].fCount,
+ fRecs[i].fVerts, fRecs[i].fTexs,
+ NULL, NULL, NULL, 0, paint);
+ canvas->restore();
+
+ canvas->translate(0, SkIntToScalar(250));
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkGradientShader.h"
+#include "SkLayerRasterizer.h"
+#include "SkBlurMaskFilter.h"
+
+static void r0(SkLayerRasterizer* rast, SkPaint& p)
+{
+ p.setMaskFilter(SkBlurMaskFilter::Create(SkIntToScalar(3),
+ SkBlurMaskFilter::kNormal_BlurStyle))->unref();
+ rast->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
+
+ p.setMaskFilter(NULL);
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(SK_Scalar1);
+ rast->addLayer(p);
+
+ p.setAlpha(0x11);
+ p.setStyle(SkPaint::kFill_Style);
+ p.setXfermodeMode(SkXfermode::kSrc_Mode);
+ rast->addLayer(p);
+}
+
+static void r1(SkLayerRasterizer* rast, SkPaint& p)
+{
+ rast->addLayer(p);
+
+ p.setAlpha(0x40);
+ p.setXfermodeMode(SkXfermode::kSrc_Mode);
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(SK_Scalar1*2);
+ rast->addLayer(p);
+}
+
+static void r2(SkLayerRasterizer* rast, SkPaint& p)
+{
+ p.setStyle(SkPaint::kStrokeAndFill_Style);
+ p.setStrokeWidth(SK_Scalar1*4);
+ rast->addLayer(p);
+
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(SK_Scalar1*3/2);
+ p.setXfermodeMode(SkXfermode::kClear_Mode);
+ rast->addLayer(p);
+}
+
+static void r3(SkLayerRasterizer* rast, SkPaint& p)
+{
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(SK_Scalar1*3);
+ rast->addLayer(p);
+
+ p.setAlpha(0x20);
+ p.setStyle(SkPaint::kFill_Style);
+ p.setXfermodeMode(SkXfermode::kSrc_Mode);
+ rast->addLayer(p);
+}
+
+static void r4(SkLayerRasterizer* rast, SkPaint& p)
+{
+ p.setAlpha(0x60);
+ rast->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
+
+ p.setAlpha(0xFF);
+ p.setXfermodeMode(SkXfermode::kClear_Mode);
+ rast->addLayer(p, SK_Scalar1*3/2, SK_Scalar1*3/2);
+
+ p.setXfermode(NULL);
+ rast->addLayer(p);
+}
+
+#include "SkDiscretePathEffect.h"
+
+static void r5(SkLayerRasterizer* rast, SkPaint& p)
+{
+ rast->addLayer(p);
+
+ p.setPathEffect(new SkDiscretePathEffect(SK_Scalar1*4, SK_Scalar1*3))->unref();
+ p.setXfermodeMode(SkXfermode::kSrcOut_Mode);
+ rast->addLayer(p);
+}
+
+static void r6(SkLayerRasterizer* rast, SkPaint& p)
+{
+ rast->addLayer(p);
+
+ p.setAntiAlias(false);
+ SkLayerRasterizer* rast2 = new SkLayerRasterizer;
+ r5(rast2, p);
+ p.setRasterizer(rast2)->unref();
+ p.setXfermodeMode(SkXfermode::kClear_Mode);
+ rast->addLayer(p);
+}
+
+#include "Sk2DPathEffect.h"
+
+class Dot2DPathEffect : public Sk2DPathEffect {
+public:
+ Dot2DPathEffect(SkScalar radius, const SkMatrix& matrix)
+ : Sk2DPathEffect(matrix), fRadius(radius) {}
+
+ virtual void flatten(SkFlattenableWriteBuffer& buffer)
+ {
+ this->INHERITED::flatten(buffer);
+
+ buffer.writeScalar(fRadius);
+ }
+ virtual Factory getFactory() { return CreateProc; }
+
+protected:
+ virtual void next(const SkPoint& loc, int u, int v, SkPath* dst)
+ {
+ dst->addCircle(loc.fX, loc.fY, fRadius);
+ }
+
+ Dot2DPathEffect(SkFlattenableReadBuffer& buffer) : Sk2DPathEffect(buffer)
+ {
+ fRadius = buffer.readScalar();
+ }
+private:
+ SkScalar fRadius;
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer)
+ {
+ return new Dot2DPathEffect(buffer);
+ }
+
+ typedef Sk2DPathEffect INHERITED;
+};
+
+static void r7(SkLayerRasterizer* rast, SkPaint& p)
+{
+ SkMatrix lattice;
+ lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
+ lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
+ p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*4, lattice))->unref();
+ rast->addLayer(p);
+}
+
+static void r8(SkLayerRasterizer* rast, SkPaint& p)
+{
+ rast->addLayer(p);
+
+ SkMatrix lattice;
+ lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
+ lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
+ p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*2, lattice))->unref();
+ p.setXfermodeMode(SkXfermode::kClear_Mode);
+ rast->addLayer(p);
+
+ p.setPathEffect(NULL);
+ p.setXfermode(NULL);
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(SK_Scalar1);
+ rast->addLayer(p);
+}
+
+class Line2DPathEffect : public Sk2DPathEffect {
+public:
+ Line2DPathEffect(SkScalar width, const SkMatrix& matrix)
+ : Sk2DPathEffect(matrix), fWidth(width) {}
+
+ virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
+ {
+ if (this->INHERITED::filterPath(dst, src, width))
+ {
+ *width = fWidth;
+ return true;
+ }
+ return false;
+ }
+
+ virtual Factory getFactory() { return CreateProc; }
+ virtual void flatten(SkFlattenableWriteBuffer& buffer)
+ {
+ this->INHERITED::flatten(buffer);
+ buffer.writeScalar(fWidth);
+ }
+protected:
+ virtual void nextSpan(int u, int v, int ucount, SkPath* dst)
+ {
+ if (ucount > 1)
+ {
+ SkPoint src[2], dstP[2];
+
+ src[0].set(SkIntToScalar(u) + SK_ScalarHalf,
+ SkIntToScalar(v) + SK_ScalarHalf);
+ src[1].set(SkIntToScalar(u+ucount) + SK_ScalarHalf,
+ SkIntToScalar(v) + SK_ScalarHalf);
+ this->getMatrix().mapPoints(dstP, src, 2);
+
+ dst->moveTo(dstP[0]);
+ dst->lineTo(dstP[1]);
+ }
+ }
+
+ Line2DPathEffect(SkFlattenableReadBuffer& buffer) : Sk2DPathEffect(buffer)
+ {
+ fWidth = buffer.readScalar();
+ }
+
+private:
+ SkScalar fWidth;
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer)
+ {
+ return new Line2DPathEffect(buffer);
+ }
+
+ typedef Sk2DPathEffect INHERITED;
+};
+
+static void r9(SkLayerRasterizer* rast, SkPaint& p)
+{
+ rast->addLayer(p);
+
+ SkMatrix lattice;
+ lattice.setScale(SK_Scalar1, SK_Scalar1*6, 0, 0);
+ lattice.postRotate(SkIntToScalar(30), 0, 0);
+ p.setPathEffect(new Line2DPathEffect(SK_Scalar1*2, lattice))->unref();
+ p.setXfermodeMode(SkXfermode::kClear_Mode);
+ rast->addLayer(p);
+
+ p.setPathEffect(NULL);
+ p.setXfermode(NULL);
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(SK_Scalar1);
+ rast->addLayer(p);
+}
+
+typedef void (*raster_proc)(SkLayerRasterizer*, SkPaint&);
+
+static const raster_proc gRastProcs[] = {
+ r0, r1, r2, r3, r4, r5, r6, r7, r8, r9
+};
+
+static void apply_shader(SkPaint* paint, int index) {
+ raster_proc proc = gRastProcs[index];
+ SkPaint p;
+ SkLayerRasterizer* rast = new SkLayerRasterizer;
+
+ p.setAntiAlias(true);
+ proc(rast, p);
+ paint->setRasterizer(rast)->unref();
+ paint->setColor(SK_ColorBLUE);
+}
+
+#include "SkTypeface.h"
+
+static void texteffect_slide(SkCanvas* canvas) {
+ const char* str = "Google";
+ size_t len = strlen(str);
+ SkScalar x = 20;
+ SkScalar y = 80;
+ SkPaint paint;
+ paint.setTypeface(SkTypeface::CreateFromName("Georgia", SkTypeface::kItalic));
+ paint.setTextSize(75);
+ paint.setAntiAlias(true);
+ paint.setColor(SK_ColorBLUE);
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRastProcs); i++) {
+ apply_shader(&paint, i);
+ canvas->drawText(str, len, x, y, paint);
+ y += 80;
+ if (i == 4) {
+ x += 320;
+ y = 80;
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkImageEncoder.h"
+
+static const SlideProc gProc[] = {
+ patheffect_slide,
+ gradient_slide,
+ textonpath_slide,
+ mesh_slide,
+ texteffect_slide
+};
+
+class SlideView : public SampleView {
+ int fIndex;
+public:
+ SlideView() {
+ fIndex = 0;
+
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, 1024, 768);
+ bm.allocPixels();
+ SkCanvas canvas(bm);
+ SkScalar s = SkIntToScalar(1024) / 640;
+ canvas.scale(s, s);
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gProc); i++) {
+ canvas.save();
+ canvas.drawColor(BG_COLOR);
+ gProc[i](&canvas);
+ canvas.restore();
+ SkString str;
+ str.printf("/skimages/slide_%d.png", i);
+ SkImageEncoder::EncodeFile(str.c_str(), bm, SkImageEncoder::kPNG_Type, 100);
+ }
+ this->setBGColor(BG_COLOR);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Slides");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ gProc[fIndex](canvas);
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ fIndex = (fIndex + 1) % SK_ARRAY_COUNT(gProc);
+ this->inval(NULL);
+ return NULL;
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new SlideView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleSpiral.cpp b/samplecode/SampleSpiral.cpp
new file mode 100644
index 0000000..1a41440
--- /dev/null
+++ b/samplecode/SampleSpiral.cpp
@@ -0,0 +1,56 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+
+class SpiralView : public SampleView {
+public:
+ SpiralView() {
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Spiral");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkScalarHalf(SkIntToScalar(3)));
+ paint.setStyle(SkPaint::kFill_Style);
+
+ SkRect r;
+ SkScalar l,t,x,y;
+ l = SampleCode::GetAnimScalar(SkIntToScalar(10),
+ SkIntToScalar(400));
+ t = SampleCode::GetAnimScalar(SkIntToScalar(5),
+ SkIntToScalar(200));
+
+ canvas->translate(320,240);
+ for (int i = 0; i < 35; i++) {
+ paint.setColor(0xFFF00FF0 - i * 0x04000000);
+ SkScalar step = SK_ScalarPI / (55 - i);
+ SkScalar angle = t * step;
+ x = (20 + SkIntToScalar(i) * 5) * SkScalarSinCos(angle, &y);
+ y *= (20 + SkIntToScalar(i) * 5);
+ r.set(x, y, x + SkIntToScalar(10), y + SkIntToScalar(10));
+ canvas->drawRect(r, paint);
+ }
+
+ this->inval(NULL);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new SpiralView; }
+static SkViewRegister reg(MyFactory); \ No newline at end of file
diff --git a/samplecode/SampleStrokePath.cpp b/samplecode/SampleStrokePath.cpp
new file mode 100644
index 0000000..ae630ef
--- /dev/null
+++ b/samplecode/SampleStrokePath.cpp
@@ -0,0 +1,217 @@
+#include "SampleCode.h"
+#include "SkCanvas.h"
+#include "SkParsePath.h"
+#include "SkPath.h"
+#include "SkRandom.h"
+#include "SkView.h"
+
+#include "SkBlurMaskFilter.h"
+
+static void test_huge_stroke(SkCanvas* canvas) {
+ SkRect srcR = { 0, 0, 72000, 54000 };
+ SkRect dstR = { 0, 0, 640, 480 };
+
+ SkPath path;
+ path.moveTo(17600, 8000);
+ path.lineTo(52800, 8000);
+ path.lineTo(52800, 41600);
+ path.lineTo(17600, 41600);
+ path.close();
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStrokeWidth(8000);
+ paint.setStrokeMiter(10);
+ paint.setStrokeCap(SkPaint::kButt_Cap);
+ paint.setStrokeJoin(SkPaint::kRound_Join);
+ paint.setStyle(SkPaint::kStroke_Style);
+
+ SkMatrix matrix;
+ matrix.setRectToRect(srcR, dstR, SkMatrix::kCenter_ScaleToFit);
+ canvas->concat(matrix);
+
+ canvas->drawPath(path, paint);
+}
+
+#if 0
+#include "SkBlurMask.h"
+static void test_blur() {
+ uint8_t cell[9];
+ memset(cell, 0xFF, sizeof(cell));
+ SkMask src;
+ src.fImage = cell;
+ src.fFormat = SkMask::kA8_Format;
+ SkMask dst;
+
+ for (int y = 1; y <= 3; y++) {
+ for (int x = 1; x <= 3; x++) {
+ src.fBounds.set(0, 0, x, y);
+ src.fRowBytes = src.fBounds.width();
+
+ SkScalar radius = 1.f;
+
+ printf("src [%d %d %d %d] radius %g\n", src.fBounds.fLeft, src.fBounds.fTop,
+ src.fBounds.fRight, src.fBounds.fBottom, radius);
+
+ SkBlurMask::Blur(&dst, src, radius, SkBlurMask::kNormal_Style);
+ uint8_t* dstPtr = dst.fImage;
+
+ for (int y = 0; y < dst.fBounds.height(); y++) {
+ for (int x = 0; x < dst.fBounds.width(); x++) {
+ printf(" %02X", dstPtr[x]);
+ }
+ printf("\n");
+ dstPtr += dst.fRowBytes;
+ }
+ }
+ }
+}
+#endif
+
+static void scale_to_width(SkPath* path, SkScalar dstWidth) {
+ const SkRect& bounds = path->getBounds();
+ SkScalar scale = dstWidth / bounds.width();
+ SkMatrix matrix;
+
+ matrix.setScale(scale, scale);
+ path->transform(matrix);
+}
+
+static const struct {
+ SkPaint::Style fStyle;
+ SkPaint::Join fJoin;
+ int fStrokeWidth;
+} gRec[] = {
+ { SkPaint::kFill_Style, SkPaint::kMiter_Join, 0 },
+ { SkPaint::kStroke_Style, SkPaint::kMiter_Join, 0 },
+ { SkPaint::kStroke_Style, SkPaint::kMiter_Join, 10 },
+ { SkPaint::kStrokeAndFill_Style, SkPaint::kMiter_Join, 10 },
+};
+
+class StrokePathView : public SampleView {
+ SkScalar fWidth;
+ SkPath fPath;
+public:
+ StrokePathView() {
+// test_blur();
+ fWidth = SkIntToScalar(120);
+
+#if 0
+ const char str[] =
+ "M 0, 3"
+ "C 10, -10, 30, -10, 0, 28"
+ "C -30, -10, -10, -10, 0, 3"
+ "Z";
+ SkParsePath::FromSVGString(str, &fPath);
+#else
+ fPath.addCircle(0, 0, SkIntToScalar(50), SkPath::kCW_Direction);
+ fPath.addCircle(0, SkIntToScalar(-50), SkIntToScalar(30), SkPath::kCW_Direction);
+#endif
+
+ scale_to_width(&fPath, fWidth);
+ const SkRect& bounds = fPath.getBounds();
+ fPath.offset(-bounds.fLeft, -bounds.fTop);
+
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "StrokePath");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ SkRandom rand;
+
+ void drawSet(SkCanvas* canvas, SkPaint* paint) {
+ SkAutoCanvasRestore acr(canvas, true);
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) {
+ paint->setStyle(gRec[i].fStyle);
+ paint->setStrokeJoin(gRec[i].fJoin);
+ paint->setStrokeWidth(SkIntToScalar(gRec[i].fStrokeWidth));
+ canvas->drawPath(fPath, *paint);
+ canvas->translate(fWidth * 5 / 4, 0);
+ }
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ test_huge_stroke(canvas); return;
+ canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ if (true) {
+ canvas->drawColor(SK_ColorBLACK);
+
+ paint.setTextSize(24);
+ paint.setColor(SK_ColorWHITE);
+ canvas->translate(10, 30);
+
+ static const SkBlurMaskFilter::BlurStyle gStyle[] = {
+ SkBlurMaskFilter::kNormal_BlurStyle,
+ SkBlurMaskFilter::kInner_BlurStyle,
+ SkBlurMaskFilter::kOuter_BlurStyle,
+ SkBlurMaskFilter::kSolid_BlurStyle,
+ };
+ for (int x = 0; x < 5; x++) {
+ SkMaskFilter* mf;
+ SkScalar radius = 4;
+ for (int y = 0; y < 10; y++) {
+ if (x) {
+ mf = SkBlurMaskFilter::Create(radius, gStyle[x - 1]);
+ paint.setMaskFilter(mf)->unref();
+ }
+ canvas->drawText("Title Bar", 9, x*SkIntToScalar(100), y*SkIntToScalar(30), paint);
+ radius *= 0.75f;
+ }
+
+ }
+ return;
+ }
+
+ paint.setColor(SK_ColorBLUE);
+
+#if 1
+ SkPath p;
+ float r = rand.nextUScalar1() + 0.5f;
+ SkScalar x = 0, y = 0;
+ p.moveTo(x, y);
+#if 0
+ p.cubicTo(x-75*r, y+75*r, x-40*r, y+125*r, x, y+85*r);
+ p.cubicTo(x+40*r, y+125*r, x+75*r, y+75*r, x, y);
+#else
+ p.cubicTo(x+75*r, y+75*r, x+40*r, y+125*r, x, y+85*r);
+ p.cubicTo(x-40*r, y+125*r, x-75*r, y+75*r, x, y);
+#endif
+ p.close();
+ fPath = p;
+ fPath.offset(100, 0);
+#endif
+
+ fPath.setFillType(SkPath::kWinding_FillType);
+ drawSet(canvas, &paint);
+
+ canvas->translate(0, fPath.getBounds().height() * 5 / 4);
+ fPath.setFillType(SkPath::kEvenOdd_FillType);
+ drawSet(canvas, &paint);
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ this->inval(NULL);
+ return this->INHERITED::onFindClickHandler(x, y);
+ }
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new StrokePathView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleStrokeRect.cpp b/samplecode/SampleStrokeRect.cpp
new file mode 100644
index 0000000..20c9e2c
--- /dev/null
+++ b/samplecode/SampleStrokeRect.cpp
@@ -0,0 +1,69 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkPaint.h"
+
+class StrokeRectSample : public SampleView {
+public:
+ StrokeRectSample() {}
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Stroke Rects");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkIntToScalar(20));
+
+ SkPaint hair;
+ hair.setStyle(SkPaint::kStroke_Style);
+ hair.setColor(SK_ColorRED);
+
+ static const SkISize gSize[] = {
+ { 100, 50 },
+ { 100, 0 },
+ { 0, 50 },
+ { 0, 0 }
+ };
+
+ static const SkPaint::Join gJoin[] = {
+ SkPaint::kMiter_Join,
+ SkPaint::kRound_Join,
+ SkPaint::kBevel_Join
+ };
+
+ canvas->translate(paint.getStrokeWidth(), paint.getStrokeWidth());
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gJoin); ++i) {
+ paint.setStrokeJoin(gJoin[i]);
+
+ canvas->save();
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gSize); ++j) {
+ SkRect r = SkRect::MakeWH(SkIntToScalar(gSize[j].fWidth),
+ SkIntToScalar(gSize[j].fHeight));
+ canvas->drawRect(r, paint);
+ canvas->drawRect(r, hair);
+ canvas->translate(0, SkIntToScalar(100));
+ }
+ canvas->restore();
+ canvas->translate(SkIntToScalar(150), 0);
+ }
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new StrokeRectSample; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleStrokeText.cpp b/samplecode/SampleStrokeText.cpp
new file mode 100644
index 0000000..bcb9e4f
--- /dev/null
+++ b/samplecode/SampleStrokeText.cpp
@@ -0,0 +1,140 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "Sk64.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkKernel33MaskFilter.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"
+
+static void lettersToBitmap(SkBitmap* dst, const char chars[],
+ const SkPaint& original, SkBitmap::Config config) {
+ SkPath path;
+ SkScalar x = 0;
+ SkScalar width;
+ SkPath p;
+ for (size_t i = 0; i < strlen(chars); i++) {
+ original.getTextPath(&chars[i], 1, x, 0, &p);
+ path.addPath(p);
+ original.getTextWidths(&chars[i], 1, &width);
+ x += width;
+ }
+ SkRect bounds = path.getBounds();
+ SkScalar sw = -original.getStrokeWidth();
+ bounds.inset(sw, sw);
+ path.offset(-bounds.fLeft, -bounds.fTop);
+ bounds.offset(-bounds.fLeft, -bounds.fTop);
+
+ int w = SkScalarRound(bounds.width());
+ int h = SkScalarRound(bounds.height());
+ SkPaint paint(original);
+ SkBitmap src;
+ src.setConfig(config, w, h);
+ src.allocPixels();
+ src.eraseColor(0);
+ {
+ SkCanvas canvas(src);
+ paint.setAntiAlias(true);
+ paint.setColor(SK_ColorBLACK);
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas.drawPath(path, paint);
+ }
+
+ dst->setConfig(config, w, h);
+ dst->allocPixels();
+ dst->eraseColor(SK_ColorWHITE);
+ {
+ SkCanvas canvas(*dst);
+ paint.setXfermodeMode(SkXfermode::kDstATop_Mode);
+ canvas.drawBitmap(src, 0, 0, &paint);
+ paint.setColor(original.getColor());
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas.drawPath(path, paint);
+ }
+}
+
+static void lettersToBitmap2(SkBitmap* dst, const char chars[],
+ const SkPaint& original, SkBitmap::Config config) {
+ SkPath path;
+ SkScalar x = 0;
+ SkScalar width;
+ SkPath p;
+ for (size_t i = 0; i < strlen(chars); i++) {
+ original.getTextPath(&chars[i], 1, x, 0, &p);
+ path.addPath(p);
+ original.getTextWidths(&chars[i], 1, &width);
+ x += width;
+ }
+ SkRect bounds = path.getBounds();
+ SkScalar sw = -original.getStrokeWidth();
+ bounds.inset(sw, sw);
+ path.offset(-bounds.fLeft, -bounds.fTop);
+ bounds.offset(-bounds.fLeft, -bounds.fTop);
+
+ int w = SkScalarRound(bounds.width());
+ int h = SkScalarRound(bounds.height());
+ SkPaint paint(original);
+
+ paint.setAntiAlias(true);
+ paint.setXfermodeMode(SkXfermode::kDstATop_Mode);
+ paint.setColor(original.getColor());
+ paint.setStyle(SkPaint::kStroke_Style);
+
+ dst->setConfig(config, w, h);
+ dst->allocPixels();
+ dst->eraseColor(SK_ColorWHITE);
+
+ SkCanvas canvas(*dst);
+ canvas.drawPath(path, paint);
+}
+
+class StrokeTextView : public SampleView {
+ bool fAA;
+public:
+ StrokeTextView() : fAA(false) {
+ this->setBGColor(0xFFCC8844);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "StrokeText");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkBitmap bm;
+ SkPaint paint;
+
+ paint.setStrokeWidth(SkIntToScalar(6));
+ paint.setTextSize(SkIntToScalar(80));
+// paint.setTypeface(Typeface.DEFAULT_BOLD);
+
+ lettersToBitmap(&bm, "Test Case", paint, SkBitmap::kARGB_4444_Config);
+
+ canvas->drawBitmap(bm, 0, 0);
+ }
+
+private:
+
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new StrokeTextView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleTests.cpp b/samplecode/SampleTests.cpp
new file mode 100644
index 0000000..4ce8640
--- /dev/null
+++ b/samplecode/SampleTests.cpp
@@ -0,0 +1,111 @@
+utils#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+
+#include "test.h"
+
+namespace skiatest {
+
+class MyReporter : public Reporter {
+protected:
+ virtual void onStart(Test* test) {}
+ virtual void onReport(const char desc[], Reporter::Result result) {
+ SkASSERT(Reporter::kPassed == result);
+ }
+ virtual void onEnd(Test* test) {}
+};
+
+class Iter {
+public:
+ Iter(Reporter* r) : fReporter(r) {
+ r->ref();
+ fReg = TestRegistry::Head();
+ }
+
+ ~Iter() {
+ fReporter->unref();
+ }
+
+ Test* next() {
+ if (fReg) {
+ TestRegistry::Factory fact = fReg->factory();
+ fReg = fReg->next();
+ Test* test = fact(NULL);
+ test->setReporter(fReporter);
+ return test;
+ }
+ return NULL;
+ }
+
+ static int Count() {
+ const TestRegistry* reg = TestRegistry::Head();
+ int count = 0;
+ while (reg) {
+ count += 1;
+ reg = reg->next();
+ }
+ return count;
+ }
+
+private:
+ Reporter* fReporter;
+ const TestRegistry* fReg;
+};
+}
+
+class TestsView : public SkView {
+public:
+ TestsView() {}
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Tests");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(SK_ColorWHITE);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ this->drawBG(canvas);
+
+ skiatest::MyReporter reporter;
+ skiatest::Iter iter(&reporter);
+ skiatest::Test* test;
+
+ while ((test = iter.next()) != NULL) {
+ test->run();
+ SkDELETE(test);
+ }
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ this->inval(NULL);
+
+ return this->INHERITED::onFindClickHandler(x, y);
+ }
+
+ virtual bool onClick(Click* click) {
+ this->inval(NULL);
+ return this->INHERITED::onClick(click);
+ }
+
+ virtual bool handleKey(SkKey key) {
+ this->inval(NULL);
+ return true;
+ }
+
+private:
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new TestsView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleText.cpp b/samplecode/SampleText.cpp
new file mode 100644
index 0000000..2676530
--- /dev/null
+++ b/samplecode/SampleText.cpp
@@ -0,0 +1,396 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "Sk64.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkKernel33MaskFilter.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"
+
+static const int gKernel[3][3] = {
+// { -1, -2, -1 }, { -2, 12, -2 }, { -1, -2, -1 }
+ { 1, 2, 1 }, { 2, 64-12, 2 }, { 1, 2, 1 }
+};
+static const int gShift = 6;
+
+class ReduceNoise : public SkKernel33ProcMaskFilter {
+public:
+ ReduceNoise(int percent256) : SkKernel33ProcMaskFilter(percent256) {}
+ virtual uint8_t computeValue(uint8_t* const* srcRows)
+ {
+ int c = srcRows[1][1];
+ int min = 255, max = 0;
+ for (int i = 0; i < 3; i++)
+ for (int j = 0; j < 3; j++)
+ if (i != 1 || j != 1)
+ {
+ int v = srcRows[i][j];
+ if (max < v)
+ max = v;
+ if (min > v)
+ min = v;
+ }
+ if (c > max) c = max;
+ // if (c < min) c = min;
+ return c;
+ }
+ virtual Factory getFactory() { return Create; }
+private:
+ ReduceNoise(SkFlattenableReadBuffer& rb) : SkKernel33ProcMaskFilter(rb) {}
+ static SkFlattenable* Create(SkFlattenableReadBuffer& rb) {
+ return new ReduceNoise(rb);
+ }
+};
+
+class Darken : public SkKernel33ProcMaskFilter {
+public:
+ Darken(int percent256) : SkKernel33ProcMaskFilter(percent256) {}
+ virtual uint8_t computeValue(uint8_t* const* srcRows)
+ {
+ int c = srcRows[1][1];
+ float f = c / 255.f;
+
+ if (c >= 0) {
+ f = sqrtf(f);
+ } else {
+ f *= f;
+ }
+ SkASSERT(f >= 0 && f <= 1);
+ return (int)(f * 255);
+ }
+ virtual Factory getFactory() { return Create; }
+private:
+ Darken(SkFlattenableReadBuffer& rb) : SkKernel33ProcMaskFilter(rb) {}
+ static SkFlattenable* Create(SkFlattenableReadBuffer& rb) {
+ return new Darken(rb);
+ }
+};
+
+static SkMaskFilter* makemf() { return new Darken(0x30); }
+
+static void test_breakText() {
+ SkPaint paint;
+ const char* text = "sdfkljAKLDFJKEWkldfjlk#$%&sdfs.dsj";
+ size_t length = strlen(text);
+ SkScalar width = paint.measureText(text, length);
+
+ SkScalar mm = 0;
+ SkScalar nn = 0;
+ for (SkScalar w = 0; w <= width; w += SK_Scalar1) {
+ SkScalar m;
+ size_t n = paint.breakText(text, length, w, &m,
+ SkPaint::kBackward_TextBufferDirection);
+
+ SkASSERT(n <= length);
+ SkASSERT(m <= width);
+
+ if (n == 0) {
+ SkASSERT(m == 0);
+ } else {
+ // now assert that we're monotonic
+ if (n == nn) {
+ SkASSERT(m == mm);
+ } else {
+ SkASSERT(n > nn);
+ SkASSERT(m > mm);
+ }
+ }
+ nn = SkIntToScalar(n);
+ mm = m;
+ }
+
+ SkDEBUGCODE(size_t length2 =) paint.breakText(text, length, width, &mm);
+ SkASSERT(length2 == length);
+ SkASSERT(mm == width);
+}
+
+static SkRandom gRand;
+
+class SkPowerMode : public SkXfermode {
+public:
+ SkPowerMode(SkScalar exponent) { this->init(exponent); }
+
+ virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count,
+ const SkAlpha aa[]);
+
+ typedef SkFlattenable* (*Factory)(SkFlattenableReadBuffer&);
+
+ // overrides for SkFlattenable
+ virtual Factory getFactory() { return Create; }
+ virtual void flatten(SkFlattenableWriteBuffer& b) {
+ // this->INHERITED::flatten(b); How can we know if this is legal????
+ b.write32(SkScalarToFixed(fExp));
+ }
+
+private:
+ SkScalar fExp; // user's value
+ uint8_t fTable[256]; // cache
+
+ void init(SkScalar exponent);
+ SkPowerMode(SkFlattenableReadBuffer& b) : SkXfermode(b) {
+ // read the exponent
+ this->init(SkFixedToScalar(b.readS32()));
+ }
+ static SkFlattenable* Create(SkFlattenableReadBuffer& b) {
+ return SkNEW_ARGS(SkPowerMode, (b));
+ }
+
+ typedef SkXfermode INHERITED;
+};
+
+void SkPowerMode::init(SkScalar e) {
+ fExp = e;
+ float ee = SkScalarToFloat(e);
+
+ printf("------ %g\n", ee);
+ for (int i = 0; i < 256; i++) {
+ float x = i / 255.f;
+ // printf(" %d %g", i, x);
+ x = powf(x, ee);
+ // printf(" %g", x);
+ int xx = SkScalarRound(SkFloatToScalar(x * 255));
+ // printf(" %d\n", xx);
+ fTable[i] = SkToU8(xx);
+ }
+}
+
+void SkPowerMode::xfer16(uint16_t dst[], const SkPMColor src[], int count,
+ const SkAlpha aa[]) {
+ for (int i = 0; i < count; i++) {
+ SkPMColor c = src[i];
+ int r = SkGetPackedR32(c);
+ int g = SkGetPackedG32(c);
+ int b = SkGetPackedB32(c);
+ r = fTable[r];
+ g = fTable[g];
+ b = fTable[b];
+ dst[i] = SkPack888ToRGB16(r, g, b);
+ }
+}
+
+static const struct {
+ const char* fName;
+ uint32_t fFlags;
+ bool fFlushCache;
+} gHints[] = {
+ { "Linear", SkPaint::kLinearText_Flag, false },
+ { "Normal", 0, true },
+ { "Subpixel", SkPaint::kSubpixelText_Flag, true }
+};
+
+static int count_char_points(const SkPaint& paint, char c) {
+ SkPath path;
+
+ paint.getTextPath(&c, 1, 0, 0, &path);
+ return path.getPoints(NULL, 0);
+}
+
+static int gOld, gNew, gCount;
+
+static void dump(int c, int oldc, int newc) {
+ if (oldc != newc) {
+ gOld += oldc;
+ gNew += newc;
+ gCount += 1;
+ printf("char %c: old = %3d, new = %3d, reduction %g%%\n", c, oldc, newc, 100. * (oldc - newc) / oldc);
+ }
+}
+
+static void tab(int n) {
+// printf("[%d] ", n); return;
+ SkASSERT(n >= 0);
+ for (int i = 0; i < n; i++)
+ printf(" ");
+}
+
+static void draw_rgn(const SkRegion& rgn, SkCanvas* canvas, const SkPaint& paint) {
+ SkRect r;
+ SkRegion::Iterator iter(rgn);
+
+ for (; !iter.done(); iter.next()) {
+ r.set(iter.rect());
+ canvas->drawRect(r, paint);
+ }
+}
+
+static void test_break(SkCanvas* canvas, const char text[], size_t length,
+ SkScalar x, SkScalar y, const SkPaint& paint,
+ SkScalar clickX) {
+ SkPaint linePaint;
+
+ linePaint.setAntiAlias(true);
+
+ SkScalar measured;
+
+ if (paint.breakText(text, length, clickX - x, &measured,
+ SkPaint::kForward_TextBufferDirection)) {
+ linePaint.setColor(SK_ColorRED);
+ canvas->drawLine(x, y, x + measured, y, linePaint);
+ }
+
+ x += paint.measureText(text, length);
+ if (paint.breakText(text, length, x - clickX, &measured,
+ SkPaint::kBackward_TextBufferDirection)) {
+ linePaint.setColor(SK_ColorBLUE);
+ canvas->drawLine(x - measured, y, x, y, linePaint);
+ }
+}
+
+static void DrawTheText(SkCanvas* canvas, const char text[], size_t length,
+ SkScalar x, SkScalar y, const SkPaint& paint,
+ SkScalar clickX, SkMaskFilter* mf) {
+ SkPaint p(paint);
+
+#if 0
+ canvas->drawText(text, length, x, y, paint);
+#else
+ {
+ SkPoint pts[1000];
+ SkScalar xpos = x;
+ SkASSERT(length <= SK_ARRAY_COUNT(pts));
+ for (size_t i = 0; i < length; i++) {
+ pts[i].set(xpos, y), xpos += paint.getTextSize();
+ }
+ canvas->drawPosText(text, length, pts, paint);
+ }
+#endif
+
+ p.setSubpixelText(true);
+ x += SkIntToScalar(180);
+ canvas->drawText(text, length, x, y, p);
+
+#ifdef SK_DEBUG
+ if (true) {
+ // p.setMaskFilter(mf);
+ p.setSubpixelText(false);
+ p.setLinearText(true);
+ x += SkIntToScalar(180);
+ canvas->drawText(text, length, x, y, p);
+ }
+#endif
+}
+
+class TextSpeedView : public SampleView {
+public:
+ TextSpeedView() {
+ fMF = makemf();
+
+ fHints = 0;
+ fClickX = 0;
+
+ test_breakText();
+ }
+
+ virtual ~TextSpeedView() {
+ SkSafeUnref(fMF);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Text");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ static void make_textstrip(SkBitmap* bm) {
+ bm->setConfig(SkBitmap::kRGB_565_Config, 200, 18);
+ bm->allocPixels();
+ bm->eraseColor(SK_ColorWHITE);
+
+ SkCanvas canvas(*bm);
+ SkPaint paint;
+ const char* s = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit";
+
+ paint.setFlags(paint.getFlags() | SkPaint::kAntiAlias_Flag
+ | SkPaint::kDevKernText_Flag);
+ paint.setTextSize(SkIntToScalar(14));
+ canvas.drawText(s, strlen(s), SkIntToScalar(8), SkIntToScalar(14), paint);
+ }
+
+ static void fill_pts(SkPoint pts[], size_t n, SkRandom* rand) {
+ for (size_t i = 0; i < n; i++)
+ pts[i].set(rand->nextUScalar1() * 640, rand->nextUScalar1() * 480);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkAutoCanvasRestore restore(canvas, false);
+ {
+ SkRect r;
+ r.set(0, 0, SkIntToScalar(1000), SkIntToScalar(20));
+ // canvas->saveLayer(&r, NULL, SkCanvas::kHasAlphaLayer_SaveFlag);
+ }
+
+ SkPaint paint;
+// const uint16_t glyphs[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 };
+ int index = fHints % SK_ARRAY_COUNT(gHints);
+ index = 1;
+// const char* style = gHints[index].fName;
+
+// canvas->translate(0, SkIntToScalar(50));
+
+ // canvas->drawText(style, strlen(style), SkIntToScalar(20), SkIntToScalar(20), paint);
+
+ SkSafeUnref(paint.setTypeface(SkTypeface::CreateFromFile("/skimages/samplefont.ttf")));
+ paint.setAntiAlias(true);
+ paint.setFlags(paint.getFlags() | gHints[index].fFlags);
+
+ SkRect clip;
+ clip.set(SkIntToScalar(25), SkIntToScalar(34), SkIntToScalar(88), SkIntToScalar(155));
+
+ const char* text = "Hamburgefons";
+ size_t length = strlen(text);
+
+ SkScalar y = SkIntToScalar(0);
+ for (int i = 9; i <= 24; i++) {
+ paint.setTextSize(SkIntToScalar(i) /*+ (gRand.nextU() & 0xFFFF)*/);
+ for (SkScalar dx = 0; dx <= SkIntToScalar(3)/4;
+ dx += SkIntToScalar(1) /* /4 */) {
+ y += paint.getFontSpacing();
+ DrawTheText(canvas, text, length, SkIntToScalar(20) + dx, y,
+ paint, fClickX, fMF);
+ }
+ }
+ if (gHints[index].fFlushCache) {
+// SkGraphics::SetFontCacheUsed(0);
+ }
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ fClickX = x;
+ this->inval(NULL);
+ return this->INHERITED::onFindClickHandler(x, y);
+ }
+
+ virtual bool onClick(Click* click) {
+ return this->INHERITED::onClick(click);
+ }
+
+private:
+ int fHints;
+ SkScalar fClickX;
+ SkMaskFilter* fMF;
+
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new TextSpeedView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleTextAlpha.cpp b/samplecode/SampleTextAlpha.cpp
new file mode 100644
index 0000000..ccfed68
--- /dev/null
+++ b/samplecode/SampleTextAlpha.cpp
@@ -0,0 +1,114 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkBlurMaskFilter.h"
+#include "SkCanvas.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 "SkXfermode.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+
+#include "SkOSFile.h"
+#include "SkStream.h"
+
+static void check_for_nonwhite(const SkBitmap& bm, int alpha) {
+ if (bm.config() != SkBitmap::kRGB_565_Config) {
+ return;
+ }
+
+ for (int y = 0; y < bm.height(); y++) {
+ for (int x = 0; x < bm.width(); x++) {
+ uint16_t c = *bm.getAddr16(x, y);
+ if (c != 0xFFFF) {
+ SkDebugf("------ nonwhite alpha=%x [%d %d] %x\n", alpha, x, y, c);
+ return;
+ }
+ }
+ }
+}
+
+class TextAlphaView : public SampleView {
+public:
+ TextAlphaView() {
+ fByte = 0xFF;
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SkString str("TextAlpha");
+ SampleCode::TitleR(evt, str.c_str());
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ const char* str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ SkPaint paint;
+ SkScalar x = SkIntToScalar(10);
+ SkScalar y = SkIntToScalar(20);
+
+ paint.setFlags(0x105);
+
+ paint.setARGB(fByte, 0xFF, 0xFF, 0xFF);
+
+ paint.setMaskFilter(SkBlurMaskFilter::Create(SkIntToScalar(3),
+ SkBlurMaskFilter::kNormal_BlurStyle));
+ paint.getMaskFilter()->unref();
+
+ SkRandom rand;
+
+ for (int ps = 6; ps <= 35; ps++) {
+ paint.setColor(rand.nextU() | (0xFF << 24));
+ paint.setTextSize(SkIntToScalar(ps));
+ paint.setTextSize(SkIntToScalar(24));
+ canvas->drawText(str, strlen(str), x, y, paint);
+ y += paint.getFontMetrics(NULL);
+ }
+ //check_for_nonwhite(canvas->getDevice()->accessBitmap(), fByte);
+ //SkDebugf("------ byte %x\n", fByte);
+
+ if (false) {
+ fByte += 1;
+ fByte &= 0xFF;
+ this->inval(NULL);
+ }
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ return new Click(this);
+ }
+
+ virtual bool onClick(Click* click) {
+ int y = click->fICurr.fY;
+ if (y < 0) {
+ y = 0;
+ } else if (y > 255) {
+ y = 255;
+ }
+ fByte = y;
+ this->inval(NULL);
+ return true;
+ }
+
+private:
+ int fByte;
+
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new TextAlphaView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleTextBox.cpp b/samplecode/SampleTextBox.cpp
new file mode 100644
index 0000000..37a6be0
--- /dev/null
+++ b/samplecode/SampleTextBox.cpp
@@ -0,0 +1,91 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkBlurMaskFilter.h"
+#include "SkCanvas.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 "SkXfermode.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+#include "SkTextBox.h"
+#include "SkOSFile.h"
+#include "SkStream.h"
+#include "SkKey.h"
+
+#ifdef SK_BUILD_FOR_WIN
+extern SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT&);
+#endif
+
+static const char gText[] =
+ "When in the Course of human events it becomes necessary for one people "
+ "to dissolve the political bands which have connected them with another "
+ "and to assume among the powers of the earth, the separate and equal "
+ "station to which the Laws of Nature and of Nature's God entitle them, "
+ "a decent respect to the opinions of mankind requires that they should "
+ "declare the causes which impel them to the separation.";
+
+class TextBoxView : public SampleView {
+public:
+ TextBoxView() {
+#ifdef SK_BUILD_FOR_WIN
+ LOGFONT lf;
+ sk_bzero(&lf, sizeof(lf));
+ lf.lfHeight = 9;
+ SkTypeface* tf0 = SkCreateTypefaceFromLOGFONT(lf);
+ lf.lfHeight = 12;
+ SkTypeface* tf1 = SkCreateTypefaceFromLOGFONT(lf);
+ // we assert that different sizes should not affect which face we get
+ SkASSERT(tf0 == tf1);
+ tf0->unref();
+ tf1->unref();
+#endif
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SkString str("TextBox");
+ SampleCode::TitleR(evt, str.c_str());
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkScalar margin = 20;
+ SkTextBox tbox;
+ tbox.setMode(SkTextBox::kLineBreak_Mode);
+ tbox.setBox(margin, margin,
+ this->width() - margin, this->height() - margin);
+ tbox.setSpacing(SkIntToScalar(3)/3, 0);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setLCDRenderText(true);
+ tbox.setText(gText, strlen(gText), paint);
+
+ for (int i = 9; i < 24; i += 2) {
+ paint.setTextSize(SkIntToScalar(i));
+ tbox.draw(canvas);
+ canvas->translate(0, tbox.getTextHeight() + paint.getFontSpacing());
+ }
+ }
+
+private:
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new TextBoxView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleTextEffects.cpp b/samplecode/SampleTextEffects.cpp
new file mode 100644
index 0000000..f256b2e
--- /dev/null
+++ b/samplecode/SampleTextEffects.cpp
@@ -0,0 +1,397 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTypeface.h"
+#include "SkAvoidXfermode.h"
+
+static inline SkPMColor rgb2gray(SkPMColor c) {
+ unsigned r = SkGetPackedR32(c);
+ unsigned g = SkGetPackedG32(c);
+ unsigned b = SkGetPackedB32(c);
+
+ unsigned x = (r * 5 + g * 7 + b * 4) >> 4;
+
+ return SkPackARGB32(0, x, x, x) | (c & (SK_A32_MASK << SK_A32_SHIFT));
+}
+
+class SkGrayScaleColorFilter : public SkColorFilter {
+public:
+ virtual void filterSpan(const SkPMColor src[], int count,
+ SkPMColor result[]) {
+ for (int i = 0; i < count; i++) {
+ result[i] = rgb2gray(src[i]);
+ }
+ }
+};
+
+class SkChannelMaskColorFilter : public SkColorFilter {
+public:
+ SkChannelMaskColorFilter(U8CPU redMask, U8CPU greenMask, U8CPU blueMask) {
+ fMask = SkPackARGB32(0xFF, redMask, greenMask, blueMask);
+ }
+
+ virtual void filterSpan(const SkPMColor src[], int count,
+ SkPMColor result[]) {
+ SkPMColor mask = fMask;
+ for (int i = 0; i < count; i++) {
+ result[i] = src[i] & mask;
+ }
+ }
+
+private:
+ SkPMColor fMask;
+};
+
+///////////////////////////////////////////////////////////
+
+#include "SkGradientShader.h"
+#include "SkLayerRasterizer.h"
+#include "SkBlurMaskFilter.h"
+
+static void r0(SkLayerRasterizer* rast, SkPaint& p) {
+ p.setMaskFilter(SkBlurMaskFilter::Create(SkIntToScalar(3),
+ SkBlurMaskFilter::kNormal_BlurStyle))->unref();
+ rast->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
+
+ p.setMaskFilter(NULL);
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(SK_Scalar1);
+ rast->addLayer(p);
+
+ p.setAlpha(0x11);
+ p.setStyle(SkPaint::kFill_Style);
+ p.setXfermodeMode(SkXfermode::kSrc_Mode);
+ rast->addLayer(p);
+}
+
+static void r1(SkLayerRasterizer* rast, SkPaint& p) {
+ rast->addLayer(p);
+
+ p.setAlpha(0x40);
+ p.setXfermodeMode(SkXfermode::kSrc_Mode);
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(SK_Scalar1*2);
+ rast->addLayer(p);
+}
+
+static void r2(SkLayerRasterizer* rast, SkPaint& p) {
+ p.setStyle(SkPaint::kStrokeAndFill_Style);
+ p.setStrokeWidth(SK_Scalar1*4);
+ rast->addLayer(p);
+
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(SK_Scalar1*3/2);
+ p.setXfermodeMode(SkXfermode::kClear_Mode);
+ rast->addLayer(p);
+}
+
+static void r3(SkLayerRasterizer* rast, SkPaint& p) {
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(SK_Scalar1*3);
+ rast->addLayer(p);
+
+ p.setAlpha(0x20);
+ p.setStyle(SkPaint::kFill_Style);
+ p.setXfermodeMode(SkXfermode::kSrc_Mode);
+ rast->addLayer(p);
+}
+
+static void r4(SkLayerRasterizer* rast, SkPaint& p) {
+ p.setAlpha(0x60);
+ rast->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
+
+ p.setAlpha(0xFF);
+ p.setXfermodeMode(SkXfermode::kClear_Mode);
+ rast->addLayer(p, SK_Scalar1*3/2, SK_Scalar1*3/2);
+
+ p.setXfermode(NULL);
+ rast->addLayer(p);
+}
+
+#include "SkDiscretePathEffect.h"
+
+static void r5(SkLayerRasterizer* rast, SkPaint& p) {
+ rast->addLayer(p);
+
+ p.setPathEffect(new SkDiscretePathEffect(SK_Scalar1*4, SK_Scalar1*3))->unref();
+ p.setXfermodeMode(SkXfermode::kSrcOut_Mode);
+ rast->addLayer(p);
+}
+
+static void r6(SkLayerRasterizer* rast, SkPaint& p) {
+ rast->addLayer(p);
+
+ p.setAntiAlias(false);
+ SkLayerRasterizer* rast2 = new SkLayerRasterizer;
+ r5(rast2, p);
+ p.setRasterizer(rast2)->unref();
+ p.setXfermodeMode(SkXfermode::kClear_Mode);
+ rast->addLayer(p);
+}
+
+#include "Sk2DPathEffect.h"
+
+class Dot2DPathEffect : public Sk2DPathEffect {
+public:
+ Dot2DPathEffect(SkScalar radius, const SkMatrix& matrix)
+ : Sk2DPathEffect(matrix), fRadius(radius) {}
+
+ virtual void flatten(SkFlattenableWriteBuffer& buffer) {
+ this->INHERITED::flatten(buffer);
+
+ buffer.writeScalar(fRadius);
+ }
+ virtual Factory getFactory() { return CreateProc; }
+
+protected:
+ virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) {
+ dst->addCircle(loc.fX, loc.fY, fRadius);
+ }
+
+ Dot2DPathEffect(SkFlattenableReadBuffer& buffer) : Sk2DPathEffect(buffer) {
+ fRadius = buffer.readScalar();
+ }
+private:
+ SkScalar fRadius;
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return new Dot2DPathEffect(buffer);
+ }
+
+ typedef Sk2DPathEffect INHERITED;
+};
+
+static void r7(SkLayerRasterizer* rast, SkPaint& p) {
+ SkMatrix lattice;
+ lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
+ lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
+ p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*4, lattice))->unref();
+ rast->addLayer(p);
+}
+
+static void r8(SkLayerRasterizer* rast, SkPaint& p) {
+ rast->addLayer(p);
+
+ SkMatrix lattice;
+ lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
+ lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
+ p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*2, lattice))->unref();
+ p.setXfermodeMode(SkXfermode::kClear_Mode);
+ rast->addLayer(p);
+
+ p.setPathEffect(NULL);
+ p.setXfermode(NULL);
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(SK_Scalar1);
+ rast->addLayer(p);
+}
+
+class Line2DPathEffect : public Sk2DPathEffect {
+public:
+ Line2DPathEffect(SkScalar width, const SkMatrix& matrix)
+ : Sk2DPathEffect(matrix), fWidth(width) {}
+
+ virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width) {
+ if (this->INHERITED::filterPath(dst, src, width)) {
+ *width = fWidth;
+ return true;
+ }
+ return false;
+ }
+
+ virtual Factory getFactory() { return CreateProc; }
+ virtual void flatten(SkFlattenableWriteBuffer& buffer) {
+ this->INHERITED::flatten(buffer);
+ buffer.writeScalar(fWidth);
+ }
+
+protected:
+ virtual void nextSpan(int u, int v, int ucount, SkPath* dst) {
+ if (ucount > 1) {
+ SkPoint src[2], dstP[2];
+
+ src[0].set(SkIntToScalar(u) + SK_ScalarHalf,
+ SkIntToScalar(v) + SK_ScalarHalf);
+ src[1].set(SkIntToScalar(u+ucount) + SK_ScalarHalf,
+ SkIntToScalar(v) + SK_ScalarHalf);
+ this->getMatrix().mapPoints(dstP, src, 2);
+
+ dst->moveTo(dstP[0]);
+ dst->lineTo(dstP[1]);
+ }
+ }
+
+ Line2DPathEffect(SkFlattenableReadBuffer& buffer) : Sk2DPathEffect(buffer) {
+ fWidth = buffer.readScalar();
+ }
+
+private:
+ SkScalar fWidth;
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return new Line2DPathEffect(buffer);
+ }
+
+ typedef Sk2DPathEffect INHERITED;
+};
+
+static void r9(SkLayerRasterizer* rast, SkPaint& p) {
+ rast->addLayer(p);
+
+ SkMatrix lattice;
+ lattice.setScale(SK_Scalar1, SK_Scalar1*6, 0, 0);
+ lattice.postRotate(SkIntToScalar(30), 0, 0);
+ p.setPathEffect(new Line2DPathEffect(SK_Scalar1*2, lattice))->unref();
+ p.setXfermodeMode(SkXfermode::kClear_Mode);
+ rast->addLayer(p);
+
+ p.setPathEffect(NULL);
+ p.setXfermode(NULL);
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(SK_Scalar1);
+ rast->addLayer(p);
+}
+
+typedef void (*raster_proc)(SkLayerRasterizer*, SkPaint&);
+
+static const raster_proc gRastProcs[] = {
+ r0, r1, r2, r3, r4, r5, r6, r7, r8, r9
+};
+
+static const struct {
+ SkColor fMul, fAdd;
+} gLightingColors[] = {
+ { 0x808080, 0x800000 }, // general case
+ { 0x707070, 0x707070 }, // no-pin case
+ { 0xFFFFFF, 0x800000 }, // just-add case
+ { 0x808080, 0x000000 }, // just-mul case
+ { 0xFFFFFF, 0x000000 } // identity case
+};
+
+#include "SkXfermode.h"
+
+static unsigned color_dist16(uint16_t a, uint16_t b) {
+ unsigned dr = SkAbs32(SkPacked16ToR32(a) - SkPacked16ToR32(b));
+ unsigned dg = SkAbs32(SkPacked16ToG32(a) - SkPacked16ToG32(b));
+ unsigned db = SkAbs32(SkPacked16ToB32(a) - SkPacked16ToB32(b));
+
+ return SkMax32(dr, SkMax32(dg, db));
+}
+
+static unsigned scale_dist(unsigned dist, unsigned scale) {
+ dist >>= 6;
+ dist = (dist << 2) | dist;
+ dist = (dist << 4) | dist;
+ return dist;
+
+// return SkAlphaMul(dist, scale);
+}
+
+static void apply_shader(SkPaint* paint, int index) {
+ raster_proc proc = gRastProcs[index];
+ if (proc)
+ {
+ SkPaint p;
+ SkLayerRasterizer* rast = new SkLayerRasterizer;
+
+ p.setAntiAlias(true);
+ proc(rast, p);
+ paint->setRasterizer(rast)->unref();
+ }
+
+#if 0
+ SkScalar dir[] = { SK_Scalar1, SK_Scalar1, SK_Scalar1 };
+ paint->setMaskFilter(SkBlurMaskFilter::CreateEmboss(dir, SK_Scalar1/4, SkIntToScalar(4), SkIntToScalar(3)))->unref();
+#endif
+ paint->setColor(SK_ColorBLUE);
+}
+
+static int gRastIndex;
+
+class TextEffectView : public SampleView {
+ SkTypeface* fFace;
+public:
+ TextEffectView() {
+ fFace = SkTypeface::CreateFromFile("/Users/reed/Downloads/p052024l.pfb");
+ }
+
+ virtual ~TextEffectView() {
+ SkSafeUnref(fFace);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Text Effects");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ canvas->save();
+// canvas->scale(SK_Scalar1*2, SK_Scalar1*2, 0, 0);
+
+ SkPaint paint;
+
+ paint.setAntiAlias(true);
+ paint.setTextSize(SkIntToScalar(56));
+ paint.setTypeface(SkTypeface::CreateFromName("sans-serif",
+ SkTypeface::kBold));
+
+ SkScalar x = SkIntToScalar(20);
+ SkScalar y = paint.getTextSize();
+
+ SkString str("TextEffects");
+
+ paint.setTypeface(fFace);
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRastProcs); i++) {
+ apply_shader(&paint, i);
+
+ // paint.setMaskFilter(NULL);
+ // paint.setColor(SK_ColorBLACK);
+
+#if 1
+ int index = i % SK_ARRAY_COUNT(gLightingColors);
+ paint.setColorFilter(SkColorFilter::CreateLightingFilter(
+ gLightingColors[index].fMul,
+ gLightingColors[index].fAdd))->unref();
+#endif
+
+ canvas->drawText(str.c_str(), str.size(), x, y, paint);
+
+ y += paint.getFontSpacing();
+ }
+
+ canvas->restore();
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ gRastIndex = (gRastIndex + 1) % SK_ARRAY_COUNT(gRastProcs);
+ this->inval(NULL);
+
+ return this->INHERITED::onFindClickHandler(x, y);
+ }
+
+ virtual bool onClick(Click* click) {
+ return this->INHERITED::onClick(click);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new TextEffectView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleTextOnPath.cpp b/samplecode/SampleTextOnPath.cpp
new file mode 100644
index 0000000..96e8c9a
--- /dev/null
+++ b/samplecode/SampleTextOnPath.cpp
@@ -0,0 +1,284 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPackBits.h"
+#include "SkPath.h"
+#include "SkPathMeasure.h"
+#include "SkRandom.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTypeface.h"
+#include "SkAvoidXfermode.h"
+
+#define REPEAT_COUNT 0
+
+static const char gText[] = "Hamburgefons";
+
+static bool gDevKern;
+
+static void rand_text(char text[], SkRandom& rand, size_t count) {
+ for (size_t i = 0; i < count; i++) {
+ text[i] = rand.nextU() & 0x7F;
+ }
+}
+
+static SkScalar sum_widths(const SkScalar widths[], int count) {
+ SkScalar w = 0;
+ for (int i = 0; i < count; i++) {
+ w += widths[i];
+ }
+ return w;
+}
+
+static void test_measure(const SkPaint& paint) {
+ char text[256];
+ SkScalar widths[256];
+ SkRect rects[256];
+ SkRect bounds;
+ int count = 256;
+
+ SkRandom rand;
+
+ for (int i = 0; i < 100; i++) {
+ rand_text(text, rand, 256);
+ paint.getTextWidths(text, count, widths, NULL);
+ SkDEBUGCODE(SkScalar tw0 = sum_widths(widths, count);)
+ paint.getTextWidths(text, count, widths, rects);
+ SkDEBUGCODE(SkScalar tw1 = sum_widths(widths, count);)
+ SkASSERT(tw0 == tw1);
+
+ SkDEBUGCODE(SkScalar w0 = paint.measureText(text, count, NULL);)
+ SkDEBUGCODE(SkScalar w1 = paint.measureText(text, count, &bounds);)
+ SkASSERT(w0 == w1);
+ SkASSERT(w0 == tw0);
+
+ SkRect r = rects[0];
+ SkScalar x = 0;
+ for (int j = 1; j < count; j++) {
+ x += widths[j-1];
+ rects[j].offset(x, 0);
+ r.join(rects[j]);
+ }
+ SkASSERT(r == bounds);
+
+ if (r != bounds) {
+ printf("flags=%x i=%d [%g %g %g %g] [%g %g %g %g]\n",
+ paint.getFlags(), i,
+ SkScalarToFloat(r.fLeft),
+ SkScalarToFloat(r.fTop),
+ SkScalarToFloat(r.fRight),
+ SkScalarToFloat(r.fBottom),
+ SkScalarToFloat(bounds.fLeft),
+ SkScalarToFloat(bounds.fTop),
+ SkScalarToFloat(bounds.fRight),
+ SkScalarToFloat(bounds.fBottom));
+ }
+ }
+}
+
+static void test_measure() {
+ SkPaint paint;
+
+ for (int i = 0; i <= SkPaint::kAllFlags; i++) {
+ paint.setFlags(i);
+ test_measure(paint);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+static void test_textBounds(SkCanvas* canvas) {
+// canvas->scale(SK_Scalar1/2, SK_Scalar1/2);
+
+// canvas->rotate(SkIntToScalar(30));
+
+ gDevKern = !gDevKern;
+
+ SkScalar x = SkIntToScalar(50);
+ SkScalar y = SkIntToScalar(150);
+ SkScalar w[100];
+ SkRect r[100], bounds;
+
+ SkPaint paint;
+ paint.setTextSize(SkIntToScalar(64));
+ paint.setAntiAlias(true);
+ paint.setDevKernText(gDevKern);
+
+ (void)paint.measureText(gText, strlen(gText), &bounds, NULL);
+ paint.setColor(SK_ColorGREEN);
+ bounds.offset(x, y);
+ canvas->drawRect(bounds, paint);
+
+ int count = paint.getTextWidths(gText, strlen(gText), w, r);
+
+ paint.setColor(SK_ColorRED);
+ for (int i = 0; i < count; i++) {
+ r[i].offset(x, y);
+ canvas->drawRect(r[i], paint);
+ x += w[i];
+ }
+ x = SkIntToScalar(50);
+ paint.setColor(gDevKern ? SK_ColorDKGRAY : SK_ColorBLACK);
+ canvas->drawText(gText, strlen(gText), x, y, paint);
+}
+
+static void create_src(SkBitmap* bitmap, SkBitmap::Config config) {
+ bitmap->setConfig(config, 100, 100);
+ bitmap->allocPixels();
+ bitmap->eraseColor(0);
+
+ SkCanvas canvas(*bitmap);
+ SkPaint paint;
+
+ paint.setAntiAlias(true);
+ canvas.drawCircle(SkIntToScalar(50), SkIntToScalar(50),
+ SkIntToScalar(50), paint);
+}
+
+static void blur(SkBitmap* dst, const SkBitmap& src, SkScalar radius) {
+ *dst = src;
+}
+
+static void test_bitmap_blur(SkCanvas* canvas) {
+ SkBitmap src, dst;
+
+ create_src(&src, SkBitmap::kARGB_8888_Config);
+ blur(&dst, src, SkIntToScalar(4));
+
+ SkPaint paint;
+
+ paint.setColor(SK_ColorRED);
+
+ canvas->drawBitmap(dst, SkIntToScalar(30), SkIntToScalar(60), &paint);
+}
+
+static SkScalar getpathlen(const SkPath& path) {
+ SkPathMeasure meas(path, false);
+ return meas.getLength();
+}
+
+static void test_textpathmatrix(SkCanvas* canvas) {
+ SkPaint paint;
+ SkPath path;
+ SkMatrix matrix;
+
+ path.moveTo(SkIntToScalar(200), SkIntToScalar(300));
+ path.quadTo(SkIntToScalar(400), SkIntToScalar(100),
+ SkIntToScalar(600), SkIntToScalar(300));
+
+ paint.setAntiAlias(true);
+
+ paint.setStyle(SkPaint::kStroke_Style);
+ // canvas->drawPath(path, paint);
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setTextSize(SkIntToScalar(48));
+ paint.setTextAlign(SkPaint::kRight_Align);
+
+ const char* text = "Reflection";
+ size_t len = strlen(text);
+ SkScalar pathLen = getpathlen(path);
+
+ canvas->drawTextOnPath(text, len, path, NULL, paint);
+
+ paint.setColor(SK_ColorRED);
+ matrix.setScale(-SK_Scalar1, SK_Scalar1);
+ matrix.postTranslate(pathLen, 0);
+ canvas->drawTextOnPath(text, len, path, &matrix, paint);
+
+ paint.setColor(SK_ColorBLUE);
+ matrix.setScale(SK_Scalar1, -SK_Scalar1);
+ canvas->drawTextOnPath(text, len, path, &matrix, paint);
+
+ paint.setColor(SK_ColorGREEN);
+ matrix.setScale(-SK_Scalar1, -SK_Scalar1);
+ matrix.postTranslate(pathLen, 0);
+ canvas->drawTextOnPath(text, len, path, &matrix, paint);
+}
+
+class TextOnPathView : public SampleView {
+public:
+ SkPath fPath;
+ SkScalar fHOffset;
+
+ TextOnPathView() {
+ SkRect r;
+ r.set(SkIntToScalar(100), SkIntToScalar(100),
+ SkIntToScalar(300), SkIntToScalar(300));
+ fPath.addOval(r);
+ fPath.offset(SkIntToScalar(200), 0);
+
+ fHOffset = SkIntToScalar(50);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Text On Path");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+
+ paint.setAntiAlias(true);
+ paint.setTextSize(SkIntToScalar(50));
+
+ for (int j = 0; j < REPEAT_COUNT; j++) {
+ SkScalar x = fHOffset;
+
+ paint.setColor(SK_ColorBLACK);
+ canvas->drawTextOnPathHV(gText, sizeof(gText)-1, fPath,
+ x, paint.getTextSize()/2, paint);
+
+ paint.setColor(SK_ColorRED);
+ canvas->drawTextOnPathHV(gText, sizeof(gText)-1, fPath,
+ x + SkIntToScalar(50), 0, paint);
+
+ paint.setColor(SK_ColorBLUE);
+ canvas->drawTextOnPathHV(gText, sizeof(gText)-1, fPath,
+ x + SkIntToScalar(100), -paint.getTextSize()/2, paint);
+ }
+
+ paint.setColor(SK_ColorGREEN);
+ paint.setStyle(SkPaint::kStroke_Style);
+// canvas->drawPath(fPath, paint);
+
+ canvas->translate(0, SkIntToScalar(100));
+ test_textpathmatrix(canvas);
+
+ if (REPEAT_COUNT > 1)
+ this->inval(NULL);
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ fHints += 1;
+ this->inval(NULL);
+ return this->INHERITED::onFindClickHandler(x, y);
+ }
+
+ virtual bool onClick(Click* click) {
+ return this->INHERITED::onClick(click);
+ }
+
+private:
+ int fHints;
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() {
+ return new TextOnPathView;
+}
+
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleTextureDomain.cpp b/samplecode/SampleTextureDomain.cpp
new file mode 100755
index 0000000..be000f9
--- /dev/null
+++ b/samplecode/SampleTextureDomain.cpp
@@ -0,0 +1,80 @@
+#include "SampleCode.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+
+namespace {
+SkBitmap make_bitmap() {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config , 5, 5);
+ bm.allocPixels();
+
+ for (int y = 0; y < bm.height(); y++) {
+ uint32_t* p = bm.getAddr32(0, y);
+ for (int x = 0; x < bm.width(); x++) {
+ p[x] = ((x + y) & 1) ? SK_ColorWHITE : SK_ColorBLACK;
+ }
+ }
+ bm.unlockPixels();
+ return bm;
+}
+} // unnamed namespace
+
+class TextureDomainView : public SampleView {
+ SkBitmap fBM;
+
+public:
+ TextureDomainView(){
+ fBM = make_bitmap();
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Texture Domian");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkIRect srcRect;
+ SkRect dstRect;
+ SkPaint paint;
+ paint.setFilterBitmap(true);
+
+ // Test that bitmap draws from malloc-backed bitmaps respect
+ // the constrained texture domain.
+ srcRect.setXYWH(1, 1, 3, 3);
+ dstRect.setXYWH(5.0f, 5.0f, 305.0f, 305.0f);
+ canvas->drawBitmapRect(fBM, &srcRect, dstRect, &paint);
+
+ // Test that bitmap draws across separate devices also respect
+ // the constrainted texture domain.
+ // Note: GPU-backed bitmaps follow a different rendering path
+ // when copying from one GPU device to another.
+ SkRefPtr<SkDevice> primaryDevice(canvas->getDevice());
+ SkRefPtr<SkDevice> secondDevice(canvas->createDevice(
+ SkBitmap::kARGB_8888_Config, 5, 5, true, true));
+ secondDevice->unref();
+ SkCanvas secondCanvas(secondDevice.get());
+
+ srcRect.setXYWH(1, 1, 3, 3);
+ dstRect.setXYWH(1.0f, 1.0f, 3.0f, 3.0f);
+ secondCanvas.drawBitmapRect(fBM, &srcRect, dstRect, &paint);
+
+ SkBitmap deviceBitmap = secondDevice->accessBitmap(false);
+
+ srcRect.setXYWH(1, 1, 3, 3);
+ dstRect.setXYWH(405.0f, 5.0f, 305.0f, 305.0f);
+ canvas->drawBitmapRect(deviceBitmap, &srcRect, dstRect, &paint);
+ }
+private:
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new TextureDomainView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleTiling.cpp b/samplecode/SampleTiling.cpp
new file mode 100644
index 0000000..4752ed1
--- /dev/null
+++ b/samplecode/SampleTiling.cpp
@@ -0,0 +1,162 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkPicture.h"
+#include "SkTypeface.h"
+
+// effects
+#include "SkGradientShader.h"
+#include "SkUnitMappers.h"
+#include "SkBlurDrawLooper.h"
+
+static void makebm(SkBitmap* bm, SkBitmap::Config config, int w, int h) {
+ bm->setConfig(config, w, h);
+ bm->allocPixels();
+ bm->eraseColor(0);
+
+ SkCanvas canvas(*bm);
+ SkPoint pts[] = { { 0, 0 }, { SkIntToScalar(w), SkIntToScalar(h) } };
+ SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
+ SkScalar pos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
+ SkPaint paint;
+
+ SkUnitMapper* um = NULL;
+
+ um = new SkCosineMapper;
+// um = new SkDiscreteMapper(12);
+
+ SkAutoUnref au(um);
+
+ paint.setDither(true);
+ paint.setShader(SkGradientShader::CreateLinear(pts, colors, pos,
+ SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode, um))->unref();
+ canvas.drawPaint(paint);
+}
+
+static void setup(SkPaint* paint, const SkBitmap& bm, bool filter,
+ SkShader::TileMode tmx, SkShader::TileMode tmy) {
+ SkShader* shader = SkShader::CreateBitmapShader(bm, tmx, tmy);
+ paint->setShader(shader)->unref();
+ paint->setFilterBitmap(filter);
+}
+
+static const SkBitmap::Config gConfigs[] = {
+ SkBitmap::kARGB_8888_Config,
+ SkBitmap::kRGB_565_Config,
+ SkBitmap::kARGB_4444_Config
+};
+static const int gWidth = 32;
+static const int gHeight = 32;
+
+class TilingView : public SampleView {
+ SkPicture fTextPicture;
+ SkBlurDrawLooper fLooper;
+public:
+ TilingView()
+ : fLooper(SkIntToScalar(1), SkIntToScalar(2), SkIntToScalar(2),
+ 0x88000000) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); i++) {
+ makebm(&fTexture[i], gConfigs[i], gWidth, gHeight);
+ }
+ }
+
+ SkBitmap fTexture[SK_ARRAY_COUNT(gConfigs)];
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Tiling");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkRect r = { 0, 0, SkIntToScalar(gWidth*2), SkIntToScalar(gHeight*2) };
+
+ static const char* gConfigNames[] = { "8888", "565", "4444" };
+
+ static const bool gFilters[] = { false, true };
+ static const char* gFilterNames[] = { "point", "bilinear" };
+
+ static const SkShader::TileMode gModes[] = { SkShader::kClamp_TileMode, SkShader::kRepeat_TileMode, SkShader::kMirror_TileMode };
+ static const char* gModeNames[] = { "C", "R", "M" };
+
+ SkScalar y = SkIntToScalar(24);
+ SkScalar x = SkIntToScalar(10);
+
+ SkCanvas* textCanvas = NULL;
+ if (fTextPicture.width() == 0) {
+ textCanvas = fTextPicture.beginRecording(1000, 1000);
+ }
+
+ if (textCanvas) {
+ for (size_t kx = 0; kx < SK_ARRAY_COUNT(gModes); kx++) {
+ for (size_t ky = 0; ky < SK_ARRAY_COUNT(gModes); ky++) {
+ SkPaint p;
+ SkString str;
+ p.setAntiAlias(true);
+ p.setDither(true);
+ p.setLooper(&fLooper);
+ str.printf("[%s,%s]", gModeNames[kx], gModeNames[ky]);
+
+ p.setTextAlign(SkPaint::kCenter_Align);
+ textCanvas->drawText(str.c_str(), str.size(), x + r.width()/2, y, p);
+
+ x += r.width() * 4 / 3;
+ }
+ }
+ }
+
+ y += SkIntToScalar(16);
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); i++) {
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gFilters); j++) {
+ x = SkIntToScalar(10);
+ for (size_t kx = 0; kx < SK_ARRAY_COUNT(gModes); kx++) {
+ for (size_t ky = 0; ky < SK_ARRAY_COUNT(gModes); ky++) {
+ SkPaint paint;
+ setup(&paint, fTexture[i], gFilters[j], gModes[kx], gModes[ky]);
+ paint.setDither(true);
+
+ canvas->save();
+ canvas->translate(x, y);
+ canvas->drawRect(r, paint);
+ canvas->restore();
+
+ x += r.width() * 4 / 3;
+ }
+ }
+ if (textCanvas) {
+ SkPaint p;
+ SkString str;
+ p.setAntiAlias(true);
+ p.setLooper(&fLooper);
+ str.printf("%s, %s", gConfigNames[i], gFilterNames[j]);
+ textCanvas->drawText(str.c_str(), str.size(), x, y + r.height() * 2 / 3, p);
+ }
+
+ y += r.height() * 4 / 3;
+ }
+ }
+
+ canvas->drawPicture(fTextPicture);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new TilingView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleTinyBitmap.cpp b/samplecode/SampleTinyBitmap.cpp
new file mode 100644
index 0000000..0841474
--- /dev/null
+++ b/samplecode/SampleTinyBitmap.cpp
@@ -0,0 +1,76 @@
+#include "SampleCode.h"
+#include "SkColorPriv.h"
+#include "SkShader.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkUtils.h"
+
+static SkBitmap make_bitmap() {
+ SkBitmap bm;
+ const int N = 1;
+ SkColorTable* ctable = new SkColorTable(N);
+
+ SkPMColor* c = ctable->lockColors();
+ for (int i = 0; i < N; i++) {
+ c[i] = SkPackARGB32(0x80, 0x80, 0, 0);
+ }
+ ctable->unlockColors(true);
+ bm.setConfig(SkBitmap::kIndex8_Config, 1, 1);
+ bm.allocPixels(ctable);
+ ctable->unref();
+
+ bm.lockPixels();
+ for (int y = 0; y < bm.height(); y++) {
+ uint8_t* p = bm.getAddr8(0, y);
+ for (int x = 0; x < bm.width(); x++) {
+ p[x] = 0;
+ }
+ }
+ bm.unlockPixels();
+ return bm;
+}
+
+class TinyBitmapView : public SampleView {
+ SkBitmap fBM;
+public:
+ TinyBitmapView() {
+ fBM = make_bitmap();
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "TinyBitmap");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ static void setBitmapOpaque(SkBitmap* bm, bool isOpaque) {
+ SkAutoLockPixels alp(*bm); // needed for ctable
+ bm->setIsOpaque(isOpaque);
+ SkColorTable* ctable = bm->getColorTable();
+ if (ctable) {
+ ctable->setIsOpaque(isOpaque);
+ }
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkShader* s = SkShader::CreateBitmapShader(fBM, SkShader::kRepeat_TileMode,
+ SkShader::kMirror_TileMode);
+ SkPaint paint;
+ paint.setShader(s)->unref();
+ canvas->drawPaint(paint);
+ }
+
+private:
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new TinyBitmapView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleTriangles.cpp b/samplecode/SampleTriangles.cpp
new file mode 100644
index 0000000..be9da8f
--- /dev/null
+++ b/samplecode/SampleTriangles.cpp
@@ -0,0 +1,118 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkConcaveToTriangles.h"
+
+#define SIZE SkIntToScalar(150)
+
+typedef void (*PathProc)(SkPath*);
+
+static void make_path0(SkPath* path) {
+ SkRect r;
+ r.set(0, 0, SIZE, SIZE);
+ path->addRect(r);
+}
+
+static void make_path1(SkPath* path) {
+ SkRect r;
+ r.set(0, 0, SIZE, SIZE);
+ path->addRoundRect(r, SIZE/4, SIZE/4);
+}
+
+static void make_path2(SkPath* path) {
+ SkRect r;
+ r.set(0, 0, SIZE, SIZE);
+ path->addOval(r);
+}
+
+static const PathProc gProcs[] = {
+ make_path0,
+ make_path1,
+ make_path2,
+};
+
+#define COUNT_PROCS SK_ARRAY_COUNT(gProcs)
+
+class TriangleView : public SkView {
+public:
+ SkPath fPaths[COUNT_PROCS];
+
+ TriangleView() {
+ for (size_t i = 0; i < COUNT_PROCS; i++) {
+ gProcs[i](&fPaths[i]);
+ }
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Triangles");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(SK_ColorGRAY);
+ }
+
+ static void draw_path(SkCanvas* canvas, const SkPaint& pathPaint,
+ const SkPath& path, const SkPaint& triPaint) {
+ canvas->drawPath(path, pathPaint);
+
+ int n = path.getPoints(NULL, 0);
+ SkPoint* pts = new SkPoint[n];
+ path.getPoints(pts, n);
+
+ SkTDArray<SkPoint> triangles;
+ if (SkConcaveToTriangles(n, pts, &triangles)) {
+ canvas->drawVertices(SkCanvas::kTriangles_VertexMode,
+ triangles.count(), triangles.begin(), NULL,
+ NULL, NULL, NULL, 0, triPaint);
+ }
+
+ SkPaint paint;
+ paint.setColor(SK_ColorGREEN);
+ paint.setStrokeWidth(SkIntToScalar(4));
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, n, pts, paint);
+ delete[] pts;
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ this->drawBG(canvas);
+
+ canvas->translate(SIZE/2, SIZE/2);
+
+ SkPaint pathPaint, triPaint;
+
+ pathPaint.setColor(SK_ColorBLUE);
+ pathPaint.setStrokeWidth(SIZE / 12);
+
+ triPaint.setColor(SK_ColorRED);
+ triPaint.setStyle(SkPaint::kStroke_Style);
+
+ for (size_t i = 0; i < COUNT_PROCS; i++) {
+ pathPaint.setStyle(SkPaint::kFill_Style);
+ draw_path(canvas, pathPaint, fPaths[i], triPaint);
+
+ canvas->save();
+ canvas->translate(0, SIZE * 6 / 5);
+
+ pathPaint.setStyle(SkPaint::kStroke_Style);
+ draw_path(canvas, pathPaint, fPaths[i], triPaint);
+
+ canvas->restore();
+ canvas->translate(SIZE * 6 / 5, 0);
+ }
+ }
+
+private:
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new TriangleView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleTypeface.cpp b/samplecode/SampleTypeface.cpp
new file mode 100644
index 0000000..63f1d5a
--- /dev/null
+++ b/samplecode/SampleTypeface.cpp
@@ -0,0 +1,128 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkTypeface.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "Sk1DPathEffect.h"
+#include "SkCornerPathEffect.h"
+#include "SkPathMeasure.h"
+#include "SkRandom.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkDither.h"
+#include "SkTypefaceCache.h"
+
+static int dither_4444(int x) {
+ return ((x << 1) - ((x >> 4 << 4) | (x >> 4))) >> 4;
+}
+
+/** Ensure that the max of the original and dithered value (for alpha) is always
+ >= any other dithered value. We apply this "max" in colorpriv.h when we
+ predither down to 4444, to be sure that we stay in legal premultiplied form
+ */
+static void test_4444_dither() {
+ int buckets[16];
+ sk_bzero(buckets, sizeof(buckets));
+
+ for (int a = 0; a <= 0xFF; a++) {
+ int da = dither_4444(a);
+ int maxa = SkMax32(a >> 4, da);
+ // SkDebugf("--- %02X %X\n", a, da);
+ buckets[da] += 1;
+ for (int c = 0; c <= a; c++) {
+ int dc = dither_4444(c);
+ if (maxa < dc) {
+ SkDebugf("------------ error a=%d da=%d c=%d dc=%d\n", a, da,
+ c, dc);
+ }
+ }
+ }
+ for (int i = 0; i < 16; i++) {
+ // SkDebugf("[%d] = %d\n", i, buckets[i]);
+ }
+}
+
+static const struct {
+ const char* fName;
+ SkTypeface::Style fStyle;
+} gFaces[] = {
+ { "sans-serif", SkTypeface::kNormal },
+ { "sans-serif", SkTypeface::kBold },
+ { "sans-serif", SkTypeface::kItalic },
+ { "sans-serif", SkTypeface::kBoldItalic },
+ { "serif", SkTypeface::kNormal },
+ { "serif", SkTypeface::kBold },
+ { "serif", SkTypeface::kItalic },
+ { "serif", SkTypeface::kBoldItalic },
+ { "monospace", SkTypeface::kNormal },
+ { "monospace", SkTypeface::kBold },
+ { "monospace", SkTypeface::kItalic },
+ { "monospace", SkTypeface::kBoldItalic },
+};
+
+static const int gFaceCount = SK_ARRAY_COUNT(gFaces);
+
+class TypefaceView : public SampleView {
+ SkTypeface* fFaces[gFaceCount];
+
+public:
+ TypefaceView() {
+ test_4444_dither();
+ for (int i = 0; i < gFaceCount; i++) {
+ fFaces[i] = SkTypeface::CreateFromName(gFaces[i].fName,
+ gFaces[i].fStyle);
+ }
+
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+ virtual ~TypefaceView() {
+ for (int i = 0; i < gFaceCount; i++) {
+ SkSafeUnref(fFaces[i]);
+ }
+
+ SkTypefaceCache::Dump();
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Typefaces");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setTextSize(SkIntToScalar(30));
+
+ const char* text = "Hamburgefons";
+ const size_t textLen = strlen(text);
+
+ SkScalar x = SkIntToScalar(10);
+ SkScalar dy = paint.getFontMetrics(NULL);
+ SkScalar y = dy;
+
+ paint.setLinearText(true);
+ for (int i = 0; i < gFaceCount; i++) {
+ paint.setTypeface(fFaces[i]);
+ canvas->drawText(text, textLen, x, y, paint);
+ y += dy;
+ }
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new TypefaceView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleUnitMapper.cpp b/samplecode/SampleUnitMapper.cpp
new file mode 100644
index 0000000..b20aece
--- /dev/null
+++ b/samplecode/SampleUnitMapper.cpp
@@ -0,0 +1,157 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkPaint.h"
+#include "SkUnitMappers.h"
+#include "SkCubicInterval.h"
+
+#include "SkWidgetViews.h"
+
+static SkStaticTextView* make_textview(SkView* parent,
+ const SkRect& bounds,
+ const SkPaint& paint) {
+ SkStaticTextView* view = new SkStaticTextView;
+ view->setMode(SkStaticTextView::kFixedSize_Mode);
+ view->setPaint(paint);
+ view->setVisibleP(true);
+ view->setSize(bounds.width(), bounds.height());
+ view->setLoc(bounds.fLeft, bounds.fTop);
+ parent->attachChildToFront(view)->unref();
+ return view;
+}
+
+static void set_scalar(SkStaticTextView* view, SkScalar value) {
+ SkString str;
+ str.appendScalar(value);
+ view->setText(str);
+}
+
+class UnitMapperView : public SampleView {
+ SkPoint fPts[4];
+ SkMatrix fMatrix;
+ SkStaticTextView* fViews[4];
+
+ void setViews() {
+ set_scalar(fViews[0], fPts[1].fX);
+ set_scalar(fViews[1], fPts[1].fY);
+ set_scalar(fViews[2], fPts[2].fX);
+ set_scalar(fViews[3], fPts[2].fY);
+ }
+
+public:
+ UnitMapperView() {
+ fPts[0].set(0, 0);
+ fPts[1].set(SK_Scalar1 / 3, SK_Scalar1 / 3);
+ fPts[2].set(SK_Scalar1 * 2 / 3, SK_Scalar1 * 2 / 3);
+ fPts[3].set(SK_Scalar1, SK_Scalar1);
+
+ fMatrix.setScale(SK_Scalar1 * 200, -SK_Scalar1 * 200);
+ fMatrix.postTranslate(SkIntToScalar(100), SkIntToScalar(300));
+
+ SkRect r = {
+ SkIntToScalar(350), SkIntToScalar(100),
+ SkIntToScalar(500), SkIntToScalar(130)
+ };
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setTextSize(SkIntToScalar(25));
+ for (int i = 0; i < 4; i++) {
+ fViews[i] = make_textview(this, r, paint);
+ r.offset(0, r.height());
+ }
+ this->setViews();
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "UnitMapper");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(0xFF8888FF);
+
+ SkRect r = { 0, 0, SK_Scalar1, SK_Scalar1 };
+
+ canvas->concat(fMatrix);
+ canvas->drawRect(r, paint);
+
+ paint.setColor(SK_ColorBLACK);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(0);
+ paint.setStrokeCap(SkPaint::kRound_Cap);
+
+ SkPath path;
+ path.moveTo(fPts[0]);
+ path.cubicTo(fPts[1], fPts[2], fPts[3]);
+ canvas->drawPath(path, paint);
+
+ paint.setColor(SK_ColorRED);
+ paint.setStrokeWidth(0);
+ canvas->drawLine(0, 0, SK_Scalar1, SK_Scalar1, paint);
+
+ paint.setColor(SK_ColorBLUE);
+ paint.setStrokeWidth(SK_Scalar1 / 60);
+ for (int i = 0; i < 50; i++) {
+ SkScalar x = i * SK_Scalar1 / 49;
+ canvas->drawPoint(x, SkEvalCubicInterval(&fPts[1], x), paint);
+ }
+
+ paint.setStrokeWidth(SK_Scalar1 / 20);
+ paint.setColor(SK_ColorGREEN);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, &fPts[1], paint);
+ }
+
+ SkPoint invertPt(SkScalar x, SkScalar y) {
+ SkPoint pt;
+ SkMatrix m;
+ fMatrix.invert(&m);
+ m.mapXY(x, y, &pt);
+ return pt;
+ }
+
+ int hittest(SkScalar x, SkScalar y) {
+ SkPoint target = { x, y };
+ SkPoint pts[2] = { fPts[1], fPts[2] };
+ fMatrix.mapPoints(pts, 2);
+ for (int i = 0; i < 2; i++) {
+ if (SkPoint::Distance(pts[i], target) < SkIntToScalar(4)) {
+ return i + 1;
+ }
+ }
+ return -1;
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ fDragIndex = hittest(x, y);
+ return fDragIndex >= 0 ? new Click(this) : NULL;
+ }
+
+ virtual bool onClick(Click* click) {
+ if (fDragIndex >= 0) {
+ fPts[fDragIndex] = invertPt(click->fCurr.fX, click->fCurr.fY);
+ this->setViews();
+ this->inval(NULL);
+ return true;
+ }
+ return false;
+ }
+
+private:
+ int fDragIndex;
+
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new UnitMapperView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleVertices.cpp b/samplecode/SampleVertices.cpp
new file mode 100644
index 0000000..74e757f
--- /dev/null
+++ b/samplecode/SampleVertices.cpp
@@ -0,0 +1,230 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.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 "SkXfermode.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+
+#include "SkOSFile.h"
+#include "SkStream.h"
+#include "SkNinePatch.h"
+
+static SkShader* make_shader0(SkIPoint* size) {
+ SkBitmap bm;
+ size->set(2, 2);
+ bm.setConfig(SkBitmap::kARGB_8888_Config, size->fX, size->fY);
+ SkPMColor color0 = SkPreMultiplyARGB(0x80, 0x80, 0xff, 0x80);
+ SkPMColor color1 = SkPreMultiplyARGB(0x40, 0xff, 0x00, 0xff);
+ bm.allocPixels();
+ bm.eraseColor(color0);
+ bm.lockPixels();
+ uint32_t* pixels = (uint32_t*) bm.getPixels();
+ pixels[0] = pixels[2] = color0;
+ pixels[1] = pixels[3] = color1;
+ bm.unlockPixels();
+
+ return SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+}
+
+static SkShader* make_shader1(const SkIPoint& size) {
+ SkPoint pts[] = { { 0, 0 },
+ { SkIntToScalar(size.fX), SkIntToScalar(size.fY) } };
+ SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorRED };
+ return SkGradientShader::CreateLinear(pts, colors, NULL,
+ SK_ARRAY_COUNT(colors), SkShader::kMirror_TileMode, NULL);
+}
+
+class VerticesView : public SampleView {
+ SkShader* fShader0;
+ SkShader* fShader1;
+
+public:
+ VerticesView() {
+ SkIPoint size;
+
+ fShader0 = make_shader0(&size);
+ fShader1 = make_shader1(size);
+
+ make_strip(&fRecs[0], size.fX, size.fY);
+ make_fan(&fRecs[1], size.fX, size.fY);
+ make_tris(&fRecs[2]);
+
+ fScale = SK_Scalar1;
+
+ this->setBGColor(SK_ColorGRAY);
+ }
+
+ virtual ~VerticesView() {
+ SkSafeUnref(fShader0);
+ SkSafeUnref(fShader1);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt))
+ {
+ SkString str("Vertices");
+ SampleCode::TitleR(evt, str.c_str());
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ SkScalar fScale;
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setDither(true);
+ paint.setFilterBitmap(true);
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(fRecs); i++) {
+ canvas->save();
+
+ paint.setShader(NULL);
+ canvas->drawVertices(fRecs[i].fMode, fRecs[i].fCount,
+ fRecs[i].fVerts, fRecs[i].fTexs,
+ NULL, NULL, NULL, 0, paint);
+
+ canvas->translate(SkIntToScalar(250), 0);
+
+ paint.setShader(fShader0);
+ canvas->drawVertices(fRecs[i].fMode, fRecs[i].fCount,
+ fRecs[i].fVerts, fRecs[i].fTexs,
+ NULL, NULL, NULL, 0, paint);
+
+ canvas->translate(SkIntToScalar(250), 0);
+
+ paint.setShader(fShader1);
+ canvas->drawVertices(fRecs[i].fMode, fRecs[i].fCount,
+ fRecs[i].fVerts, fRecs[i].fTexs,
+ NULL, NULL, NULL, 0, paint);
+ canvas->restore();
+
+ canvas->translate(0, SkIntToScalar(250));
+ }
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ return new Click(this);
+ }
+
+ virtual bool onClick(Click* click) {
+ // fCurrX = click->fICurr.fX;
+ // fCurrY = click->fICurr.fY;
+ this->inval(NULL);
+ return true;
+ }
+
+private:
+ struct Rec {
+ SkCanvas::VertexMode fMode;
+ int fCount;
+ SkPoint* fVerts;
+ SkPoint* fTexs;
+
+ Rec() : fCount(0), fVerts(NULL), fTexs(NULL) {}
+ ~Rec() { delete[] fVerts; delete[] fTexs; }
+ };
+
+ void make_tris(Rec* rec) {
+ int n = 10;
+ SkRandom rand;
+
+ rec->fMode = SkCanvas::kTriangles_VertexMode;
+ rec->fCount = n * 3;
+ rec->fVerts = new SkPoint[rec->fCount];
+
+ for (int i = 0; i < n; i++) {
+ SkPoint* v = &rec->fVerts[i*3];
+ for (int j = 0; j < 3; j++) {
+ v[j].set(rand.nextUScalar1() * 250, rand.nextUScalar1() * 250);
+ }
+ }
+ }
+
+ void make_fan(Rec* rec, int texWidth, int texHeight) {
+ const SkScalar tx = SkIntToScalar(texWidth);
+ const SkScalar ty = SkIntToScalar(texHeight);
+ const int n = 24;
+
+ rec->fMode = SkCanvas::kTriangleFan_VertexMode;
+ rec->fCount = n + 2;
+ rec->fVerts = new SkPoint[rec->fCount];
+ rec->fTexs = new SkPoint[rec->fCount];
+
+ SkPoint* v = rec->fVerts;
+ SkPoint* t = rec->fTexs;
+
+ v[0].set(0, 0);
+ t[0].set(0, 0);
+ for (int i = 0; i < n; i++) {
+ SkScalar cos;
+ SkScalar sin = SkScalarSinCos(SK_ScalarPI * 2 * i / n, &cos);
+ v[i+1].set(cos, sin);
+ t[i+1].set(i*tx/n, ty);
+ }
+ v[n+1] = v[1];
+ t[n+1].set(tx, ty);
+
+ SkMatrix m;
+ m.setScale(SkIntToScalar(100), SkIntToScalar(100));
+ m.postTranslate(SkIntToScalar(110), SkIntToScalar(110));
+ m.mapPoints(v, rec->fCount);
+ }
+
+ void make_strip(Rec* rec, int texWidth, int texHeight) {
+ const SkScalar tx = SkIntToScalar(texWidth);
+ const SkScalar ty = SkIntToScalar(texHeight);
+ const int n = 24;
+
+ rec->fMode = SkCanvas::kTriangleStrip_VertexMode;
+ rec->fCount = 2 * (n + 1);
+ rec->fVerts = new SkPoint[rec->fCount];
+ rec->fTexs = new SkPoint[rec->fCount];
+
+ SkPoint* v = rec->fVerts;
+ SkPoint* t = rec->fTexs;
+
+ for (int i = 0; i < n; i++) {
+ SkScalar cos;
+ SkScalar sin = SkScalarSinCos(SK_ScalarPI * 2 * i / n, &cos);
+ v[i*2 + 0].set(cos/2, sin/2);
+ v[i*2 + 1].set(cos, sin);
+
+ t[i*2 + 0].set(tx * i / n, ty);
+ t[i*2 + 1].set(tx * i / n, 0);
+ }
+ v[2*n + 0] = v[0];
+ v[2*n + 1] = v[1];
+
+ t[2*n + 0].set(tx, ty);
+ t[2*n + 1].set(tx, 0);
+
+ SkMatrix m;
+ m.setScale(SkIntToScalar(100), SkIntToScalar(100));
+ m.postTranslate(SkIntToScalar(110), SkIntToScalar(110));
+ m.mapPoints(v, rec->fCount);
+ }
+
+ Rec fRecs[3];
+
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new VerticesView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleWarp.cpp b/samplecode/SampleWarp.cpp
new file mode 100644
index 0000000..bf4ef0d
--- /dev/null
+++ b/samplecode/SampleWarp.cpp
@@ -0,0 +1,467 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkImageDecoder.h"
+
+#include "SkBlurMaskFilter.h"
+#include "SkTableMaskFilter.h"
+
+#define kNearlyZero (SK_Scalar1 / 8092)
+
+static void test_bigblur(SkCanvas* canvas) {
+ canvas->drawColor(SK_ColorBLACK);
+
+ SkBitmap orig, mask;
+ SkImageDecoder::DecodeFile("/skimages/app_icon.png", &orig);
+
+ SkMaskFilter* mf = SkBlurMaskFilter::Create(8, SkBlurMaskFilter::kNormal_BlurStyle);
+ SkPaint paint;
+ paint.setMaskFilter(mf)->unref();
+ SkIPoint offset;
+ orig.extractAlpha(&mask, &paint, &offset);
+
+ paint.setColor(0xFFBB8800);
+ paint.setColor(SK_ColorWHITE);
+
+ int i;
+ canvas->save();
+ float gamma = 0.8;
+ for (i = 0; i < 5; i++) {
+ paint.setMaskFilter(SkTableMaskFilter::CreateGamma(gamma))->unref();
+ canvas->drawBitmap(mask, 0, 0, &paint);
+ paint.setMaskFilter(NULL);
+ canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint);
+ gamma -= 0.1;
+ canvas->translate(120, 0);
+ }
+ canvas->restore();
+ canvas->translate(0, 160);
+
+ for (i = 0; i < 5; i++) {
+ paint.setMaskFilter(SkTableMaskFilter::CreateClip(i*30, 255 - 20))->unref();
+ canvas->drawBitmap(mask, 0, 0, &paint);
+ paint.setMaskFilter(NULL);
+ canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint);
+ canvas->translate(120, 0);
+ }
+
+#if 0
+ paint.setColor(0xFFFFFFFF);
+ canvas->drawBitmap(mask, 0, 0, &paint);
+ paint.setMaskFilter(NULL);
+ canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint);
+
+ canvas->translate(120, 0);
+
+ canvas->drawBitmap(mask, 0, 0, &paint);
+ canvas->drawBitmap(mask, 0, 0, &paint);
+ canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint);
+
+ canvas->translate(120, 0);
+
+ canvas->drawBitmap(mask, 0, 0, &paint);
+ canvas->drawBitmap(mask, 0, 0, &paint);
+ canvas->drawBitmap(mask, 0, 0, &paint);
+ canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint);
+
+ canvas->translate(120, 0);
+
+ canvas->drawBitmap(mask, 0, 0, &paint);
+ canvas->drawBitmap(mask, 0, 0, &paint);
+ canvas->drawBitmap(mask, 0, 0, &paint);
+ canvas->drawBitmap(mask, 0, 0, &paint);
+ canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint);
+
+ canvas->translate(120, 0);
+
+ canvas->drawBitmap(mask, 0, 0, &paint);
+ canvas->drawBitmap(mask, 0, 0, &paint);
+ canvas->drawBitmap(mask, 0, 0, &paint);
+ canvas->drawBitmap(mask, 0, 0, &paint);
+ canvas->drawBitmap(mask, 0, 0, &paint);
+ canvas->drawBitmap(orig, -offset.fX, -offset.fY, &paint);
+#endif
+}
+
+#include "SkMeshUtils.h"
+
+static SkPoint SkMakePoint(SkScalar x, SkScalar y) {
+ SkPoint pt;
+ pt.set(x, y);
+ return pt;
+}
+
+static SkPoint SkPointInterp(const SkPoint& a, const SkPoint& b, SkScalar t) {
+ return SkMakePoint(SkScalarInterp(a.fX, b.fX, t),
+ SkScalarInterp(a.fY, b.fY, t));
+}
+
+#include "SkBoundaryPatch.h"
+
+static void set_cubic(SkPoint pts[4], SkScalar x0, SkScalar y0,
+ SkScalar x3, SkScalar y3, SkScalar scale = 1) {
+ SkPoint tmp, tmp2;
+
+ pts[0].set(x0, y0);
+ pts[3].set(x3, y3);
+
+ tmp = SkPointInterp(pts[0], pts[3], SK_Scalar1/3);
+ tmp2 = pts[0] - tmp;
+ tmp2.rotateCW();
+ tmp2.scale(scale);
+ pts[1] = tmp + tmp2;
+
+ tmp = SkPointInterp(pts[0], pts[3], 2*SK_Scalar1/3);
+ tmp2 = pts[3] - tmp;
+ tmp2.rotateCW();
+ tmp2.scale(scale);
+ pts[2] = tmp + tmp2;
+}
+
+static void test_patch(SkCanvas* canvas, const SkBitmap& bm, SkScalar scale) {
+ SkCubicBoundary cubic;
+ set_cubic(cubic.fPts + 0, 0, 0, 100, 0, scale);
+ set_cubic(cubic.fPts + 3, 100, 0, 100, 100, scale);
+ set_cubic(cubic.fPts + 6, 100, 100, 0, 100, -scale);
+ set_cubic(cubic.fPts + 9, 0, 100, 0, 0, 0);
+
+ SkBoundaryPatch patch;
+ patch.setBoundary(&cubic);
+
+ const int Rows = 16;
+ const int Cols = 16;
+ SkPoint pts[Rows * Cols];
+ patch.evalPatch(pts, Rows, Cols);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setFilterBitmap(true);
+ paint.setStrokeWidth(1);
+ paint.setStrokeCap(SkPaint::kRound_Cap);
+
+ canvas->translate(50, 50);
+ canvas->scale(3, 3);
+
+ SkMeshUtils::Draw(canvas, bm, Rows, Cols, pts, NULL, paint);
+}
+
+static void test_drag(SkCanvas* canvas, const SkBitmap& bm,
+ const SkPoint& p0, const SkPoint& p1) {
+ SkCubicBoundary cubic;
+ set_cubic(cubic.fPts + 0, 0, 0, 100, 0, 0);
+ set_cubic(cubic.fPts + 3, 100, 0, 100, 100, 0);
+ set_cubic(cubic.fPts + 6, 100, 100, 0, 100, 0);
+ set_cubic(cubic.fPts + 9, 0, 100, 0, 0, 0);
+
+#if 0
+ cubic.fPts[1] += p1 - p0;
+ cubic.fPts[2] += p1 - p0;
+#else
+ SkScalar dx = p1.fX - p0.fX;
+ if (dx > 0) dx = 0;
+ SkScalar dy = p1.fY - p0.fY;
+ if (dy > 0) dy = 0;
+
+ cubic.fPts[1].fY += dy;
+ cubic.fPts[2].fY += dy;
+ cubic.fPts[10].fX += dx;
+ cubic.fPts[11].fX += dx;
+#endif
+
+ SkBoundaryPatch patch;
+ patch.setBoundary(&cubic);
+
+ const int Rows = 16;
+ const int Cols = 16;
+ SkPoint pts[Rows * Cols];
+ patch.evalPatch(pts, Rows, Cols);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setFilterBitmap(true);
+ paint.setStrokeWidth(1);
+ paint.setStrokeCap(SkPaint::kRound_Cap);
+
+ canvas->translate(50, 50);
+ canvas->scale(3, 3);
+
+ SkAutoCanvasRestore acr(canvas, true);
+
+ SkRect r = { 0, 0, 100, 100 };
+ canvas->clipRect(r);
+ SkMeshUtils::Draw(canvas, bm, Rows, Cols, pts, NULL, paint);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class Mesh {
+public:
+ Mesh();
+ ~Mesh();
+
+ Mesh& operator=(const Mesh& src);
+
+ void init(const SkRect& bounds, int rows, int cols,
+ const SkRect& texture);
+
+ const SkRect& bounds() const { return fBounds; }
+
+ int rows() const { return fRows; }
+ int cols() const { return fCols; }
+ SkPoint& pt(int row, int col) {
+ return fPts[row * (fRows + 1) + col];
+ }
+
+ void draw(SkCanvas*, const SkPaint&);
+ void drawWireframe(SkCanvas* canvas, const SkPaint& paint);
+
+private:
+ SkRect fBounds;
+ int fRows, fCols;
+ SkPoint* fPts;
+ SkPoint* fTex; // just points into fPts, not separately allocated
+ int fCount;
+ uint16_t* fIndices;
+ int fIndexCount;
+};
+
+Mesh::Mesh() : fPts(NULL), fCount(0), fIndices(NULL), fIndexCount(0) {}
+
+Mesh::~Mesh() {
+ delete[] fPts;
+ delete[] fIndices;
+}
+
+Mesh& Mesh::operator=(const Mesh& src) {
+ delete[] fPts;
+ delete[] fIndices;
+
+ fBounds = src.fBounds;
+ fRows = src.fRows;
+ fCols = src.fCols;
+
+ fCount = src.fCount;
+ fPts = new SkPoint[fCount * 2];
+ fTex = fPts + fCount;
+ memcpy(fPts, src.fPts, fCount * 2 * sizeof(SkPoint));
+
+ delete[] fIndices;
+ fIndexCount = src.fIndexCount;
+ fIndices = new uint16_t[fIndexCount];
+ memcpy(fIndices, src.fIndices, fIndexCount * sizeof(uint16_t));
+
+ return *this;
+}
+
+void Mesh::init(const SkRect& bounds, int rows, int cols,
+ const SkRect& texture) {
+ SkASSERT(rows > 0 && cols > 0);
+
+ fBounds = bounds;
+ fRows = rows;
+ fCols = cols;
+
+ delete[] fPts;
+ fCount = (rows + 1) * (cols + 1);
+ fPts = new SkPoint[fCount * 2];
+ fTex = fPts + fCount;
+
+ delete[] fIndices;
+ fIndexCount = rows * cols * 6;
+ fIndices = new uint16_t[fIndexCount];
+
+ SkPoint* pts = fPts;
+ const SkScalar dx = bounds.width() / rows;
+ const SkScalar dy = bounds.height() / cols;
+ SkPoint* tex = fTex;
+ const SkScalar dtx = texture.width() / rows;
+ const SkScalar dty = texture.height() / cols;
+ uint16_t* idx = fIndices;
+ int index = 0;
+ for (int y = 0; y <= cols; y++) {
+ for (int x = 0; x <= rows; x++) {
+ pts->set(bounds.fLeft + x*dx, bounds.fTop + y*dy);
+ pts += 1;
+ tex->set(texture.fLeft + x*dtx, texture.fTop + y*dty);
+ tex += 1;
+
+ if (y < cols && x < rows) {
+ *idx++ = index;
+ *idx++ = index + rows + 1;
+ *idx++ = index + 1;
+
+ *idx++ = index + 1;
+ *idx++ = index + rows + 1;
+ *idx++ = index + rows + 2;
+
+ index += 1;
+ }
+ }
+ index += 1;
+ }
+}
+
+void Mesh::draw(SkCanvas* canvas, const SkPaint& paint) {
+ canvas->drawVertices(SkCanvas::kTriangles_VertexMode, fCount,
+ fPts, fTex, NULL, NULL, fIndices, fIndexCount,
+ paint);
+}
+
+void Mesh::drawWireframe(SkCanvas* canvas, const SkPaint& paint) {
+ canvas->drawVertices(SkCanvas::kTriangles_VertexMode, fCount,
+ fPts, NULL, NULL, NULL, fIndices, fIndexCount,
+ paint);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class WarpView : public SkView {
+ Mesh fMesh, fOrig;
+ SkBitmap fBitmap;
+ SkMatrix fMatrix, fInverse;
+public:
+ WarpView() {
+ SkBitmap bm;
+// SkImageDecoder::DecodeFile("/skimages/marker.png", &bm);
+ SkImageDecoder::DecodeFile("/skimages/logo.gif", &bm);
+ // SkImageDecoder::DecodeFile("/beach_shot.JPG", &bm);
+ fBitmap = bm;
+
+ SkRect bounds, texture;
+ texture.set(0, 0, SkIntToScalar(fBitmap.width()),
+ SkIntToScalar(fBitmap.height()));
+ bounds = texture;
+
+// fMesh.init(bounds, fBitmap.width() / 40, fBitmap.height() / 40, texture);
+ fMesh.init(bounds, fBitmap.width()/16, fBitmap.height()/16, texture);
+ fOrig = fMesh;
+
+ fP0.set(0, 0);
+ fP1 = fP0;
+
+ fMatrix.setScale(2, 2);
+ fMatrix.invert(&fInverse);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Warp");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ static SkPoint apply_warp(const SkVector& drag, SkScalar dragLength,
+ const SkPoint& dragStart, const SkPoint& dragCurr,
+ const SkPoint& orig) {
+ SkVector delta = orig - dragCurr;
+ SkScalar length = SkPoint::Normalize(&delta);
+ if (length <= kNearlyZero) {
+ return orig;
+ }
+
+ const SkScalar period = 20;
+ const SkScalar mag = dragLength / 3;
+
+ SkScalar d = length / (period);
+ d = mag * SkScalarSin(d) / d;
+ SkScalar dx = delta.fX * d;
+ SkScalar dy = delta.fY * d;
+ SkScalar px = orig.fX + dx;
+ SkScalar py = orig.fY + dy;
+ return SkPoint::Make(px, py);
+ }
+
+ static SkPoint apply_warp2(const SkVector& drag, SkScalar dragLength,
+ const SkPoint& dragStart, const SkPoint& dragCurr,
+ const SkPoint& orig) {
+ SkVector delta = orig - dragCurr;
+ SkScalar length = SkPoint::Normalize(&delta);
+ if (length <= kNearlyZero) {
+ return orig;
+ }
+
+ const SkScalar period = 10 + dragLength/4;
+ const SkScalar mag = dragLength / 3;
+
+ SkScalar d = length / (period);
+ if (d > SK_ScalarPI) {
+ d = SK_ScalarPI;
+ }
+
+ d = -mag * SkScalarSin(d);
+
+ SkScalar dx = delta.fX * d;
+ SkScalar dy = delta.fY * d;
+ SkScalar px = orig.fX + dx;
+ SkScalar py = orig.fY + dy;
+ return SkPoint::Make(px, py);
+ }
+
+ typedef SkPoint (*WarpProc)(const SkVector& drag, SkScalar dragLength,
+ const SkPoint& dragStart, const SkPoint& dragCurr,
+ const SkPoint& orig);
+
+ void warp(const SkPoint& p0, const SkPoint& p1) {
+ WarpProc proc = apply_warp2;
+ SkPoint delta = p1 - p0;
+ SkScalar length = SkPoint::Normalize(&delta);
+ for (int y = 0; y < fMesh.rows(); y++) {
+ for (int x = 0; x < fMesh.cols(); x++) {
+ fMesh.pt(x, y) = proc(delta, length, p0, p1, fOrig.pt(x, y));
+ }
+ }
+ fP0 = p0;
+ fP1 = p1;
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ canvas->drawColor(SK_ColorLTGRAY);
+ // test_bigblur(canvas); return;
+
+ canvas->concat(fMatrix);
+
+ SkPaint paint;
+ paint.setFilterBitmap(true);
+ paint.setShader(SkShader::CreateBitmapShader(fBitmap,
+ SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode))->unref();
+ fMesh.draw(canvas, paint); //return;
+
+ paint.setShader(NULL);
+ paint.setColor(SK_ColorRED);
+ fMesh.draw(canvas, paint);
+
+ // test_drag(canvas, fBitmap, fP0, fP1);
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ return new Click(this);
+ }
+
+ virtual bool onClick(Click* click) {
+ SkPoint pts[2] = { click->fOrig, click->fCurr };
+ fInverse.mapPoints(pts, 2);
+ this->warp(pts[0], pts[1]);
+ this->inval(NULL);
+ return true;
+ }
+
+private:
+ SkIRect fBase, fRect;
+ SkPoint fP0, fP1;
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new WarpView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleXfermodes.cpp b/samplecode/SampleXfermodes.cpp
new file mode 100644
index 0000000..0a3c4c7
--- /dev/null
+++ b/samplecode/SampleXfermodes.cpp
@@ -0,0 +1,250 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "Sk64.h"
+#include "SkCornerPathEffect.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkKernel33MaskFilter.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 void setNamedTypeface(SkPaint* paint, const char name[]) {
+ SkTypeface* face = SkTypeface::CreateFromName(name, SkTypeface::kNormal);
+ paint->setTypeface(face);
+ SkSafeUnref(face);
+}
+
+#if 0
+static int newscale(U8CPU a, U8CPU b, int shift) {
+ unsigned prod = a * b + (1 << (shift - 1));
+ return (prod + (prod >> shift)) >> shift;
+}
+
+static void test_srcover565(SkCanvas* canvas) {
+ const int width = 32;
+ SkBitmap bm1, bm2, bm3;
+ bm1.setConfig(SkBitmap::kRGB_565_Config, width, 256); bm1.allocPixels(NULL);
+ bm2.setConfig(SkBitmap::kRGB_565_Config, width, 256); bm2.allocPixels(NULL);
+ bm3.setConfig(SkBitmap::kRGB_565_Config, width, 256); bm3.allocPixels(NULL);
+
+ int rgb = 0x18;
+ int r = rgb >> 3;
+ int g = rgb >> 2;
+ uint16_t dst = SkPackRGB16(r, g, r);
+ for (int alpha = 0; alpha <= 255; alpha++) {
+ SkPMColor pm = SkPreMultiplyARGB(alpha, rgb, rgb, rgb);
+ uint16_t newdst = SkSrcOver32To16(pm, dst);
+ sk_memset16(bm1.getAddr16(0, alpha), newdst, bm1.width());
+
+ int ia = 255 - alpha;
+ int iscale = SkAlpha255To256(ia);
+ int dr = (SkGetPackedR32(pm) + (r * iscale >> 5)) >> 3;
+ int dg = (SkGetPackedG32(pm) + (g * iscale >> 6)) >> 2;
+
+ sk_memset16(bm2.getAddr16(0, alpha), SkPackRGB16(dr, dg, dr), bm2.width());
+
+ int dr2 = (SkMulDiv255Round(alpha, rgb) + newscale(r, ia, 5)) >> 3;
+ int dg2 = (SkMulDiv255Round(alpha, rgb) + newscale(g, ia, 6)) >> 2;
+
+ sk_memset16(bm3.getAddr16(0, alpha), SkPackRGB16(dr2, dg2, dr2), bm3.width());
+
+// if (mr != dr || mg != dg)
+ {
+// SkDebugf("[%d] macro [%d %d] inline [%d %d] new [%d %d]\n", alpha, mr, mg, dr, dg, dr2, dg2);
+ }
+ }
+
+ SkScalar dx = SkIntToScalar(width+4);
+
+ canvas->drawBitmap(bm1, 0, 0, NULL); canvas->translate(dx, 0);
+ canvas->drawBitmap(bm2, 0, 0, NULL); canvas->translate(dx, 0);
+ canvas->drawBitmap(bm3, 0, 0, NULL); canvas->translate(dx, 0);
+
+ SkRect rect = { 0, 0, SkIntToScalar(bm1.width()), SkIntToScalar(bm1.height()) };
+ SkPaint p;
+ p.setARGB(0xFF, rgb, rgb, rgb);
+ canvas->drawRect(rect, p);
+}
+#endif
+
+static void make_bitmaps(int w, int h, SkBitmap* src, SkBitmap* dst) {
+ src->setConfig(SkBitmap::kARGB_8888_Config, w, h);
+ src->allocPixels();
+ src->eraseColor(0);
+
+ SkCanvas c(*src);
+ SkPaint p;
+ SkRect r;
+ SkScalar ww = SkIntToScalar(w);
+ SkScalar hh = SkIntToScalar(h);
+
+ p.setAntiAlias(true);
+ p.setColor(0xFFFFCC44);
+ r.set(0, 0, ww*3/4, hh*3/4);
+ c.drawOval(r, p);
+
+ dst->setConfig(SkBitmap::kARGB_8888_Config, w, h);
+ dst->allocPixels();
+ dst->eraseColor(0);
+ c.setBitmapDevice(*dst);
+
+ p.setColor(0xFF66AAFF);
+ r.set(ww/3, hh/3, ww*19/20, hh*19/20);
+ c.drawRect(r, p);
+}
+
+static uint16_t gBG[] = { 0xFFFF, 0xCCCF, 0xCCCF, 0xFFFF };
+
+class XfermodesView : public SampleView {
+ SkBitmap fBG;
+ SkBitmap fSrcB, fDstB;
+
+ void draw_mode(SkCanvas* canvas, SkXfermode* mode, int alpha,
+ SkScalar x, SkScalar y) {
+ SkPaint p;
+
+ canvas->drawBitmap(fSrcB, x, y, &p);
+ p.setAlpha(alpha);
+ p.setXfermode(mode);
+ canvas->drawBitmap(fDstB, x, y, &p);
+ }
+
+public:
+ const static int W = 64;
+ const static int H = 64;
+ XfermodesView() {
+ const int W = 64;
+ const int H = 64;
+
+ fBG.setConfig(SkBitmap::kARGB_4444_Config, 2, 2, 4);
+ fBG.setPixels(gBG);
+ fBG.setIsOpaque(true);
+
+ make_bitmaps(W, H, &fSrcB, &fDstB);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Xfermodes");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
+
+ const struct {
+ SkXfermode::Mode fMode;
+ const char* fLabel;
+ } gModes[] = {
+ { SkXfermode::kClear_Mode, "Clear" },
+ { SkXfermode::kSrc_Mode, "Src" },
+ { SkXfermode::kDst_Mode, "Dst" },
+ { SkXfermode::kSrcOver_Mode, "SrcOver" },
+ { SkXfermode::kDstOver_Mode, "DstOver" },
+ { SkXfermode::kSrcIn_Mode, "SrcIn" },
+ { SkXfermode::kDstIn_Mode, "DstIn" },
+ { SkXfermode::kSrcOut_Mode, "SrcOut" },
+ { SkXfermode::kDstOut_Mode, "DstOut" },
+ { SkXfermode::kSrcATop_Mode, "SrcATop" },
+ { SkXfermode::kDstATop_Mode, "DstATop" },
+ { SkXfermode::kXor_Mode, "Xor" },
+
+ { SkXfermode::kPlus_Mode, "Plus" },
+ { SkXfermode::kMultiply_Mode, "Multiply" },
+ { SkXfermode::kScreen_Mode, "Screen" },
+ { SkXfermode::kOverlay_Mode, "Overlay" },
+ { SkXfermode::kDarken_Mode, "Darken" },
+ { SkXfermode::kLighten_Mode, "Lighten" },
+ { SkXfermode::kColorDodge_Mode, "ColorDodge" },
+ { SkXfermode::kColorBurn_Mode, "ColorBurn" },
+ { SkXfermode::kHardLight_Mode, "HardLight" },
+ { SkXfermode::kSoftLight_Mode, "SoftLight" },
+ { SkXfermode::kDifference_Mode, "Difference" },
+ { SkXfermode::kExclusion_Mode, "Exclusion" },
+ };
+
+ const SkScalar w = SkIntToScalar(W);
+ const SkScalar h = SkIntToScalar(H);
+ SkShader* s = SkShader::CreateBitmapShader(fBG,
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+ SkMatrix m;
+ m.setScale(SkIntToScalar(6), SkIntToScalar(6));
+ s->setLocalMatrix(m);
+
+ SkPaint labelP;
+ labelP.setAntiAlias(true);
+ labelP.setLCDRenderText(true);
+ labelP.setTextAlign(SkPaint::kCenter_Align);
+ setNamedTypeface(&labelP, "Menlo Regular");
+// labelP.setTextSize(SkIntToScalar(11));
+
+ const int W = 5;
+
+ SkScalar x0 = 0;
+ for (int twice = 0; twice < 2; twice++) {
+ SkScalar x = x0, y = 0;
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
+ SkXfermode* mode = SkXfermode::Create(gModes[i].fMode);
+ SkAutoUnref aur(mode);
+ SkRect r;
+ r.set(x, y, x+w, y+h);
+
+ SkPaint p;
+ p.setStyle(SkPaint::kFill_Style);
+ p.setShader(s);
+ canvas->drawRect(r, p);
+
+ canvas->saveLayer(&r, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
+ // canvas->save();
+ draw_mode(canvas, mode, twice ? 0x88 : 0xFF, r.fLeft, r.fTop);
+ canvas->restore();
+
+ r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setShader(NULL);
+ canvas->drawRect(r, p);
+
+#if 1
+ canvas->drawText(gModes[i].fLabel, strlen(gModes[i].fLabel),
+ x + w/2, y - labelP.getTextSize()/2, labelP);
+#endif
+ x += w + SkIntToScalar(10);
+ if ((i % W) == W - 1) {
+ x = x0;
+ y += h + SkIntToScalar(30);
+ }
+ }
+ x0 += SkIntToScalar(400);
+ }
+ s->unref();
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new XfermodesView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleXfermodesBlur.cpp b/samplecode/SampleXfermodesBlur.cpp
new file mode 100644
index 0000000..166e4e5
--- /dev/null
+++ b/samplecode/SampleXfermodesBlur.cpp
@@ -0,0 +1,182 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "Sk64.h"
+#include "SkCornerPathEffect.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkKernel33MaskFilter.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"
+#include "SkBlurMaskFilter.h"
+
+static void setNamedTypeface(SkPaint* paint, const char name[]) {
+ SkTypeface* face = SkTypeface::CreateFromName(name, SkTypeface::kNormal);
+ paint->setTypeface(face);
+ SkSafeUnref(face);
+}
+
+static uint16_t gBG[] = { 0xFFFF, 0xCCCF, 0xCCCF, 0xFFFF };
+
+class XfermodesBlurView : public SampleView {
+ SkBitmap fBG;
+ SkBitmap fSrcB, fDstB;
+
+ void draw_mode(SkCanvas* canvas, SkXfermode* mode, int alpha,
+ SkScalar x, SkScalar y) {
+ SkPaint p;
+ SkMaskFilter* mf = SkBlurMaskFilter::Create(5, SkBlurMaskFilter::kNormal_BlurStyle, 0);
+ p.setMaskFilter(mf)->unref();
+
+ SkScalar ww = SkIntToScalar(W);
+ SkScalar hh = SkIntToScalar(H);
+
+ // draw a circle covering the upper
+ // left three quarters of the canvas
+ p.setColor(0xFFCC44FF);
+ SkRect r;
+ r.set(0, 0, ww*3/4, hh*3/4);
+ r.offset(x, y);
+ canvas->drawOval(r, p);
+
+ p.setXfermode(mode);
+
+ // draw a square overlapping the circle
+ // in the lower right of the canvas
+ p.setColor(0x00AA6633 | alpha << 24);
+ r.set(ww/3, hh/3, ww*19/20, hh*19/20);
+ r.offset(x, y);
+ canvas->drawRect(r, p);
+ }
+
+public:
+ const static int W = 64;
+ const static int H = 64;
+ XfermodesBlurView() {
+ const int W = 64;
+ const int H = 64;
+
+ fBG.setConfig(SkBitmap::kARGB_4444_Config, 2, 2, 4);
+ fBG.setPixels(gBG);
+ fBG.setIsOpaque(true);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "XfermodesBlur");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
+
+ const struct {
+ SkXfermode::Mode fMode;
+ const char* fLabel;
+ } gModes[] = {
+ { SkXfermode::kClear_Mode, "Clear" },
+ { SkXfermode::kSrc_Mode, "Src" },
+ { SkXfermode::kDst_Mode, "Dst" },
+ { SkXfermode::kSrcOver_Mode, "SrcOver" },
+ { SkXfermode::kDstOver_Mode, "DstOver" },
+ { SkXfermode::kSrcIn_Mode, "SrcIn" },
+ { SkXfermode::kDstIn_Mode, "DstIn" },
+ { SkXfermode::kSrcOut_Mode, "SrcOut" },
+ { SkXfermode::kDstOut_Mode, "DstOut" },
+ { SkXfermode::kSrcATop_Mode, "SrcATop" },
+ { SkXfermode::kDstATop_Mode, "DstATop" },
+ { SkXfermode::kXor_Mode, "Xor" },
+
+ { SkXfermode::kPlus_Mode, "Plus" },
+ /*{ SkXfermode::kMultiply_Mode, "Multiply" },
+ { SkXfermode::kScreen_Mode, "Screen" },
+ { SkXfermode::kOverlay_Mode, "Overlay" },
+ { SkXfermode::kDarken_Mode, "Darken" },
+ { SkXfermode::kLighten_Mode, "Lighten" },
+ { SkXfermode::kColorDodge_Mode, "ColorDodge" },
+ { SkXfermode::kColorBurn_Mode, "ColorBurn" },
+ { SkXfermode::kHardLight_Mode, "HardLight" },
+ { SkXfermode::kSoftLight_Mode, "SoftLight" },
+ { SkXfermode::kDifference_Mode, "Difference" },
+ { SkXfermode::kExclusion_Mode, "Exclusion" },*/
+ };
+
+ const SkScalar w = SkIntToScalar(W);
+ const SkScalar h = SkIntToScalar(H);
+ SkShader* s = SkShader::CreateBitmapShader(fBG,
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+ SkMatrix m;
+ m.setScale(SkIntToScalar(6), SkIntToScalar(6));
+ s->setLocalMatrix(m);
+
+ SkPaint labelP;
+ labelP.setAntiAlias(true);
+ labelP.setLCDRenderText(true);
+ labelP.setTextAlign(SkPaint::kCenter_Align);
+ setNamedTypeface(&labelP, "Menlo Regular");
+
+ const int W = 5;
+
+ SkScalar x0 = 0;
+ for (int twice = 0; twice < 2; twice++) {
+ SkScalar x = x0, y = 0;
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
+ SkXfermode* mode = SkXfermode::Create(gModes[i].fMode);
+ SkAutoUnref aur(mode);
+ SkRect r;
+ r.set(x, y, x+w, y+h);
+
+ SkPaint p;
+ p.setStyle(SkPaint::kFill_Style);
+ p.setShader(s);
+ canvas->drawRect(r, p);
+
+ canvas->saveLayer(&r, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
+ draw_mode(canvas, mode, twice ? 0x88 : 0xFF, r.fLeft, r.fTop);
+ canvas->restore();
+
+ r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setShader(NULL);
+ canvas->drawRect(r, p);
+
+ canvas->drawText(gModes[i].fLabel, strlen(gModes[i].fLabel),
+ x + w/2, y - labelP.getTextSize()/2, labelP);
+ x += w + SkIntToScalar(10);
+ if ((i % W) == W - 1) {
+ x = x0;
+ y += h + SkIntToScalar(30);
+ }
+ }
+ x0 += SkIntToScalar(400);
+ }
+ s->unref();
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new XfermodesBlurView; }
+static SkViewRegister reg(MyFactory);
diff --git a/samplecode/samplecode_files.mk b/samplecode/samplecode_files.mk
new file mode 100644
index 0000000..4c660e5
--- /dev/null
+++ b/samplecode/samplecode_files.mk
@@ -0,0 +1,69 @@
+SOURCE := \
+ SampleBitmapRect.cpp \
+ SamplePathClip.cpp \
+ SampleComplexClip.cpp \
+ SampleNinePatch.cpp \
+ SampleAvoid.cpp \
+ SampleMeasure.cpp \
+ SampleArc.cpp \
+ SampleRepeatTile.cpp \
+ SampleApp.cpp \
+ vertexdump.cpp \
+ SampleShapes.cpp \
+ SampleMipMap.cpp \
+ SampleLCD.cpp \
+ SampleCamera.cpp \
+ SampleVertices.cpp \
+ SampleFontScalerTest.cpp \
+ SampleBigGradient.cpp \
+ SampleAll.cpp \
+ SampleShaderText.cpp \
+ SamplePolyToPoly.cpp \
+ SampleBlur.cpp \
+ SampleHairline.cpp \
+ SampleCircle.cpp \
+ SampleOvalTest.cpp \
+ SampleLines.cpp \
+ SampleOverflow.cpp \
+ SampleStrokePath.cpp \
+ SampleSlides.cpp \
+ SampleLayers.cpp \
+ SampleTiling.cpp \
+ SampleTinyBitmap.cpp \
+ SampleXfermodes.cpp \
+ SampleDrawLooper.cpp \
+ SampleTextEffects.cpp \
+ SampleTextOnPath.cpp \
+ SampleDitherBitmap.cpp \
+ SampleExtractAlpha.cpp \
+ SampleDither.cpp \
+ SampleEncode.cpp \
+ SampleFontCache.cpp \
+ SampleGradients.cpp \
+ SampleTypeface.cpp \
+ SampleFillType.cpp \
+ SamplePath.cpp \
+ SampleLayerMask.cpp \
+ SampleStrokeText.cpp \
+ SamplePathEffects.cpp \
+ SampleTextAlpha.cpp \
+ ClockFaceView.cpp \
+ SampleEmboss.cpp \
+ SamplePoints.cpp \
+ SampleFilter2.cpp \
+ SamplePatch.cpp \
+ SampleFilter.cpp \
+ OverView.cpp \
+ SampleFuzz.cpp \
+ SampleShaders.cpp \
+ SampleText.cpp \
+ SampleTextBox.cpp \
+ SampleImage.cpp \
+ SampleMovie.cpp \
+ SampleImageDir.cpp \
+ SampleWarp.cpp \
+ SamplePageFlip.cpp \
+ SamplePicture.cpp \
+ SampleLineClipper.cpp \
+ SampleRegion.cpp \
+ SampleDecode.cpp \ Crashes
diff --git a/samplecode/vertexdump.cpp b/samplecode/vertexdump.cpp
new file mode 100644
index 0000000..c124ad8
--- /dev/null
+++ b/samplecode/vertexdump.cpp
@@ -0,0 +1,88 @@
+#include "SkPoint.h"
+
+void setup_vertexbug(SkPoint verts[], SkPoint texs[], uint16_t index[]);
+
+void setup_vertexbug(SkPoint verts[], SkPoint texs[], uint16_t index[]) {
+ verts[0].set(SkFloatToScalar(107), SkFloatToScalar(189));
+ texs[0].set(SkFloatToScalar(0), SkFloatToScalar(0));
+ verts[1].set(SkFloatToScalar(116), SkFloatToScalar(189));
+ texs[1].set(SkFloatToScalar(9), SkFloatToScalar(0));
+ verts[2].set(SkFloatToScalar(203), SkFloatToScalar(189));
+ texs[2].set(SkFloatToScalar(35), SkFloatToScalar(0));
+ verts[3].set(SkFloatToScalar(212), SkFloatToScalar(189));
+ texs[3].set(SkFloatToScalar(44), SkFloatToScalar(0));
+ verts[4].set(SkFloatToScalar(107), SkFloatToScalar(198));
+ texs[4].set(SkFloatToScalar(0), SkFloatToScalar(9));
+ verts[5].set(SkFloatToScalar(116), SkFloatToScalar(198));
+ texs[5].set(SkFloatToScalar(9), SkFloatToScalar(9));
+ verts[6].set(SkFloatToScalar(203), SkFloatToScalar(198));
+ texs[6].set(SkFloatToScalar(35), SkFloatToScalar(9));
+ verts[7].set(SkFloatToScalar(212), SkFloatToScalar(198));
+ texs[7].set(SkFloatToScalar(44), SkFloatToScalar(9));
+ verts[8].set(SkFloatToScalar(107), SkFloatToScalar(224));
+ texs[8].set(SkFloatToScalar(0), SkFloatToScalar(39));
+ verts[9].set(SkFloatToScalar(116), SkFloatToScalar(224));
+ texs[9].set(SkFloatToScalar(9), SkFloatToScalar(39));
+ verts[10].set(SkFloatToScalar(203), SkFloatToScalar(224));
+ texs[10].set(SkFloatToScalar(35), SkFloatToScalar(39));
+ verts[11].set(SkFloatToScalar(212), SkFloatToScalar(224));
+ texs[11].set(SkFloatToScalar(44), SkFloatToScalar(39));
+ verts[12].set(SkFloatToScalar(107), SkFloatToScalar(233));
+ texs[12].set(SkFloatToScalar(0), SkFloatToScalar(48));
+ verts[13].set(SkFloatToScalar(116), SkFloatToScalar(233));
+ texs[13].set(SkFloatToScalar(9), SkFloatToScalar(48));
+ verts[14].set(SkFloatToScalar(203), SkFloatToScalar(233));
+ texs[14].set(SkFloatToScalar(35), SkFloatToScalar(48));
+ verts[15].set(SkFloatToScalar(212), SkFloatToScalar(233));
+ texs[15].set(SkFloatToScalar(44), SkFloatToScalar(48));
+ index[0] = 0; index[1] = 5; index[2] = 1;
+ index[3] = 0; index[4] = 4; index[5] = 5;
+#if 0
+ index[6] = 1; index[7] = 6; index[8] = 2;
+#else
+ index[6] = 6; index[7] = 2; index[8] = 1;
+#endif
+ index[9] = 1; index[10] = 5; index[11] = 6;
+ index[12] = 2;
+ index[13] = 7;
+ index[14] = 3;
+ index[15] = 2;
+ index[16] = 6;
+ index[17] = 7;
+ index[18] = 4;
+ index[19] = 9;
+ index[20] = 5;
+ index[21] = 4;
+ index[22] = 8;
+ index[23] = 9;
+ index[24] = 5;
+ index[25] = 10;
+ index[26] = 6;
+ index[27] = 5;
+ index[28] = 9;
+ index[29] = 10;
+ index[30] = 6;
+ index[31] = 11;
+ index[32] = 7;
+ index[33] = 6;
+ index[34] = 10;
+ index[35] = 11;
+ index[36] = 8;
+ index[37] = 13;
+ index[38] = 9;
+ index[39] = 8;
+ index[40] = 12;
+ index[41] = 13;
+ index[42] = 9;
+ index[43] = 14;
+ index[44] = 10;
+ index[45] = 9;
+ index[46] = 13;
+ index[47] = 14;
+ index[48] = 10;
+ index[49] = 15;
+ index[50] = 11;
+ index[51] = 10;
+ index[52] = 14;
+ index[53] = 15;
+}