Add samples to Viewer.

This adds support with animation, assuming the sample has
implemented onAnimate. Event handling has not been
implemented.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2056343004

Committed: https://skia.googlesource.com/skia/+/76963e73704a42a18c29d6fbdcccb566e5c67658
Review-Url: https://codereview.chromium.org/2056343004
diff --git a/gyp/SampleApp.gyp b/gyp/SampleApp.gyp
index 45051af..347af56 100644
--- a/gyp/SampleApp.gyp
+++ b/gyp/SampleApp.gyp
@@ -20,140 +20,20 @@
         '../gm',       # needed to pull gm.h
         '../samplecode', # To pull SampleApp.h and SampleCode.h
         '../tools/debugger',
-        '../tools',
-        '../experimental',
       ],
       'includes': [
         'gmslides.gypi',
+        'samples.gypi',
       ],
       'sources': [
         '../gm/gm.cpp',
-        '../samplecode/GMSampleView.h',
-        '../samplecode/GMSampleView.cpp',
-        '../samplecode/ClockFaceView.cpp',
-        '../samplecode/OverView.cpp',
-        '../samplecode/OverView.h',
-        '../samplecode/PerlinPatch.cpp',
-        '../samplecode/Sample2PtRadial.cpp',
-        '../samplecode/SampleAAClip.cpp',
-        '../samplecode/SampleAAGeometry.cpp',
-        '../samplecode/SampleAARects.cpp',
-        '../samplecode/SampleAARectModes.cpp',
-        '../samplecode/SampleAll.cpp',
-        '../samplecode/SampleAnimatedText.cpp',
-        '../samplecode/SampleAnimBlur.cpp',
         '../samplecode/SampleApp.cpp',
-        '../samplecode/SampleArc.cpp',
-        '../samplecode/SampleAtlas.cpp',
-        '../samplecode/SampleBigBlur.cpp',
-        '../samplecode/SampleBigGradient.cpp',
-        '../samplecode/SampleBitmapRect.cpp',
-        '../samplecode/SampleBlur.cpp',
-        '../samplecode/SampleCamera.cpp',
-        '../samplecode/SampleChart.cpp',
-        '../samplecode/SampleCircle.cpp',
-        '../samplecode/SampleClip.cpp',
-        '../samplecode/SampleClipDrawMatch.cpp',
-        '../samplecode/SampleClock.cpp',
-        '../samplecode/SampleCode.h',
-        '../samplecode/SampleColorFilter.cpp',
-        '../samplecode/SampleComplexClip.cpp',
-        '../samplecode/SampleConcavePaths.cpp',
-        '../samplecode/SampleDegenerateTwoPtRadials.cpp',
-        '../samplecode/SampleDither.cpp',
-        '../samplecode/SampleDitherBitmap.cpp',
-        '../samplecode/SampleEffects.cpp',
-        '../samplecode/SampleEmboss.cpp',
-        '../samplecode/SampleFatBits.cpp',
-        '../samplecode/SampleFillType.cpp',
-        '../samplecode/SampleFilter.cpp',
-        '../samplecode/SampleFilter2.cpp',
-        '../samplecode/SampleFilterQuality.cpp',
-        '../samplecode/SampleFilterFuzz.cpp',
-        '../samplecode/SampleFontCache.cpp',
-        '../samplecode/SampleFontScalerTest.cpp',
-        '../samplecode/SampleFuzz.cpp',
-        '../samplecode/SampleGradients.cpp',
-        '../samplecode/SampleHairCurves.cpp',
-        '../samplecode/SampleHairline.cpp',
-        '../samplecode/SampleHairModes.cpp',
-        '../samplecode/SampleHT.cpp',
-        '../samplecode/SampleIdentityScale.cpp',
-        '../samplecode/SampleLayerMask.cpp',
-        '../samplecode/SampleLayers.cpp',
-        '../samplecode/SampleLCD.cpp',
-        '../samplecode/SampleLighting.cpp',
-        '../samplecode/SampleLines.cpp',
-        '../samplecode/SampleLitAtlas.cpp',
-        '../samplecode/SampleLua.cpp',
-        '../samplecode/SampleManyRects.cpp',
-        '../samplecode/SampleMeasure.cpp',
-        '../samplecode/SampleMegaStroke.cpp',
-        '../samplecode/SamplePatch.cpp',
-        '../samplecode/SamplePath.cpp',
-        '../samplecode/SamplePathClip.cpp',
-        '../samplecode/SamplePathFuzz.cpp',
-        '../samplecode/SamplePathEffects.cpp',
-        '../samplecode/SamplePathOverstroke.cpp',
-        '../samplecode/SamplePictFile.cpp',
-        '../samplecode/SamplePoints.cpp',
-        '../samplecode/SamplePolyToPoly.cpp',
-        '../samplecode/SampleQuadStroker.cpp',
-        '../samplecode/SampleRectanizer.cpp',
-        '../samplecode/SampleRegion.cpp',
-        '../samplecode/SampleRepeatTile.cpp',
-        '../samplecode/SampleShaders.cpp',
-        '../samplecode/SampleShaderText.cpp',
-        '../samplecode/SampleShip.cpp',
-        '../samplecode/SampleSkLayer.cpp',
-        '../samplecode/SampleSlides.cpp',
-        '../samplecode/SampleStringArt.cpp',
-        '../samplecode/SampleStrokePath.cpp',
-        '../samplecode/SampleSubpixelTranslate.cpp',
-        '../samplecode/SampleText.cpp',
-        '../samplecode/SampleTextAlpha.cpp',
-        '../samplecode/SampleTextBox.cpp',
-        '../samplecode/SampleTextOnPath.cpp',
-        '../samplecode/SampleTextureDomain.cpp',
-        '../samplecode/SampleTiling.cpp',
-        '../samplecode/SampleTinyBitmap.cpp',
-        '../samplecode/SampleUnpremul.cpp',
-        '../samplecode/SampleVertices.cpp',
-        '../samplecode/SampleXfermodesBlur.cpp',
-        '../samplecode/SampleXfer.cpp',
 
-        # DrawingBoard
-        #'../experimental/DrawingBoard/SkColorPalette.h',
-        #'../experimental/DrawingBoard/SkColorPalette.cpp',
-        #'../experimental/DrawingBoard/SkNetPipeController.h',
-        #'../experimental/DrawingBoard/SkNetPipeController.cpp',
-        #'../experimental/DrawingBoard/SampleDrawingClient.cpp',
-        #'../experimental/DrawingBoard/SampleDrawingServer.cpp',
-
-        # Networking
-        #'../experimental/Networking/SampleNetPipeReader.cpp',
-        #'../experimental/Networking/SkSockets.cpp',
-        #'../experimental/Networking/SkSockets.h',
-
-        # PerlinNoise2
-        '../experimental/SkPerlinNoiseShader2/SkPerlinNoiseShader2.cpp',
-        '../experimental/SkPerlinNoiseShader2/SkPerlinNoiseShader2.h',
-
-        # Lua
-        '../src/utils/SkLuaCanvas.cpp',
-        '../src/utils/SkLua.cpp',
-      ],
-      'sources!': [
-        '../samplecode/SampleSkLayer.cpp', #relies on SkMatrix44 which doesn't compile
-        '../samplecode/SampleFontCache.cpp',
       ],
       'dependencies': [
         'etc1.gyp:libetc1',
-        'experimental.gyp:experimental',
         'flags.gyp:flags',
         'jsoncpp.gyp:jsoncpp',
-        'lua.gyp:lua',
-        'pdf.gyp:pdf',
         'skia_lib.gyp:skia_lib',
         'gputest.gyp:skgputest',
         'tools.gyp:resources',
@@ -161,7 +41,6 @@
         'tools.gyp:timer',
         'tools.gyp:url_data_manager',
         'views.gyp:views',
-        'xml.gyp:xml',
       ],
       'msvs_settings': {
         'VCLinkerTool': {
diff --git a/gyp/samples.gypi b/gyp/samples.gypi
new file mode 100644
index 0000000..5a130d9
--- /dev/null
+++ b/gyp/samples.gypi
@@ -0,0 +1,140 @@
+# Copyright 2015 Google Inc.
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# Include this gypi to include all 'sample' files
+{
+  'include_dirs': [
+    '../include/views',
+    '../experimental',
+    '../samplecode',
+    '../tools',
+  ],
+  'sources': [
+    # Samples
+    '../samplecode/GMSampleView.h',
+    '../samplecode/GMSampleView.cpp',
+    '../samplecode/ClockFaceView.cpp',
+    '../samplecode/OverView.cpp',
+    '../samplecode/OverView.h',
+    '../samplecode/PerlinPatch.cpp',
+    '../samplecode/Sample2PtRadial.cpp',
+    '../samplecode/SampleAAClip.cpp',
+    '../samplecode/SampleAAGeometry.cpp',
+    '../samplecode/SampleAARects.cpp',
+    '../samplecode/SampleAARectModes.cpp',
+    '../samplecode/SampleAll.cpp',
+    '../samplecode/SampleAnimatedText.cpp',
+    '../samplecode/SampleAnimBlur.cpp',
+    '../samplecode/SampleArc.cpp',
+    '../samplecode/SampleAtlas.cpp',
+    '../samplecode/SampleBigBlur.cpp',
+    '../samplecode/SampleBigGradient.cpp',
+    '../samplecode/SampleBitmapRect.cpp',
+    '../samplecode/SampleBlur.cpp',
+    '../samplecode/SampleCamera.cpp',
+    '../samplecode/SampleChart.cpp',
+    '../samplecode/SampleCircle.cpp',
+    '../samplecode/SampleClip.cpp',
+    '../samplecode/SampleClipDrawMatch.cpp',
+    '../samplecode/SampleClock.cpp',
+    '../samplecode/SampleCode.cpp',
+    '../samplecode/SampleCode.h',
+    '../samplecode/SampleColorFilter.cpp',
+    '../samplecode/SampleComplexClip.cpp',
+    '../samplecode/SampleConcavePaths.cpp',
+    '../samplecode/SampleDegenerateTwoPtRadials.cpp',
+    '../samplecode/SampleDither.cpp',
+    '../samplecode/SampleDitherBitmap.cpp',
+    '../samplecode/SampleEffects.cpp',
+    '../samplecode/SampleEmboss.cpp',
+    '../samplecode/SampleFatBits.cpp',
+    '../samplecode/SampleFillType.cpp',
+    '../samplecode/SampleFilter.cpp',
+    '../samplecode/SampleFilter2.cpp',
+    '../samplecode/SampleFilterQuality.cpp',
+    '../samplecode/SampleFilterFuzz.cpp',
+    '../samplecode/SampleFontCache.cpp',
+    '../samplecode/SampleFontScalerTest.cpp',
+    '../samplecode/SampleFuzz.cpp',
+    '../samplecode/SampleGradients.cpp',
+    '../samplecode/SampleHairCurves.cpp',
+    '../samplecode/SampleHairline.cpp',
+    '../samplecode/SampleHairModes.cpp',
+    '../samplecode/SampleHT.cpp',
+    '../samplecode/SampleIdentityScale.cpp',
+    '../samplecode/SampleLayerMask.cpp',
+    '../samplecode/SampleLayers.cpp',
+    '../samplecode/SampleLCD.cpp',
+    '../samplecode/SampleLighting.cpp',
+    '../samplecode/SampleLines.cpp',
+    '../samplecode/SampleLitAtlas.cpp',
+    '../samplecode/SampleLua.cpp',
+    '../samplecode/SampleManyRects.cpp',
+    '../samplecode/SampleMeasure.cpp',
+    '../samplecode/SampleMegaStroke.cpp',
+    '../samplecode/SamplePatch.cpp',
+    '../samplecode/SamplePath.cpp',
+    '../samplecode/SamplePathClip.cpp',
+    '../samplecode/SamplePathFuzz.cpp',
+    '../samplecode/SamplePathEffects.cpp',
+    '../samplecode/SamplePictFile.cpp',
+    '../samplecode/SamplePoints.cpp',
+    '../samplecode/SamplePolyToPoly.cpp',
+    '../samplecode/SampleQuadStroker.cpp',
+    '../samplecode/SampleRectanizer.cpp',
+    '../samplecode/SampleRegion.cpp',
+    '../samplecode/SampleRepeatTile.cpp',
+    '../samplecode/SampleShaders.cpp',
+    '../samplecode/SampleShaderText.cpp',
+    '../samplecode/SampleShip.cpp',
+    '../samplecode/SampleSkLayer.cpp',
+    '../samplecode/SampleSlides.cpp',
+    '../samplecode/SampleStringArt.cpp',
+    '../samplecode/SampleStrokePath.cpp',
+    '../samplecode/SampleSubpixelTranslate.cpp',
+    '../samplecode/SampleText.cpp',
+    '../samplecode/SampleTextAlpha.cpp',
+    '../samplecode/SampleTextBox.cpp',
+    '../samplecode/SampleTextOnPath.cpp',
+    '../samplecode/SampleTextureDomain.cpp',
+    '../samplecode/SampleTiling.cpp',
+    '../samplecode/SampleTinyBitmap.cpp',
+    '../samplecode/SampleUnpremul.cpp',
+    '../samplecode/SampleVertices.cpp',
+    '../samplecode/SampleXfermodesBlur.cpp',
+    '../samplecode/SampleXfer.cpp',
+	
+    # DrawingBoard
+    #'../experimental/DrawingBoard/SkColorPalette.h',
+    #'../experimental/DrawingBoard/SkColorPalette.cpp',
+    #'../experimental/DrawingBoard/SkNetPipeController.h',
+    #'../experimental/DrawingBoard/SkNetPipeController.cpp',
+    #'../experimental/DrawingBoard/SampleDrawingClient.cpp',
+    #'../experimental/DrawingBoard/SampleDrawingServer.cpp',
+
+    # Networking
+    #'../experimental/Networking/SampleNetPipeReader.cpp',
+    #'../experimental/Networking/SkSockets.cpp',
+    #'../experimental/Networking/SkSockets.h',
+
+    # PerlinNoise2
+    '../experimental/SkPerlinNoiseShader2/SkPerlinNoiseShader2.cpp',
+    '../experimental/SkPerlinNoiseShader2/SkPerlinNoiseShader2.h',
+
+    # Lua
+    '../src/utils/SkLuaCanvas.cpp',
+    '../src/utils/SkLua.cpp',
+  ],
+  'sources!': [
+    '../samplecode/SampleSkLayer.cpp', #relies on SkMatrix44 which doesn't compi    
+    '../samplecode/SampleFontCache.cpp', #relies on pthread.h
+  ],      
+  'dependencies': [
+    'experimental.gyp:experimental',
+    'lua.gyp:lua',
+    'pdf.gyp:pdf',
+    'views.gyp:views',
+    'xml.gyp:xml',
+  ],
+}
diff --git a/gyp/viewer.gyp b/gyp/viewer.gyp
index 1013e07..012281a 100644
--- a/gyp/viewer.gyp
+++ b/gyp/viewer.gyp
@@ -14,26 +14,41 @@
       'type': 'executable',
       'includes' : [
         'gmslides.gypi',
+        'samples.gypi',
       ],
       'include_dirs': [
         '../bench',
         '../gm',
-        '../include/views',
         '../include/private',
         '../src/core',
         '../src/effects',
         '../src/gpu',
-        '../src/images',
         '../src/image',
+        '../src/images',
+        '../src/pathops',
         '../src/views/unix',
         '../tools/timer',
       ],
       'sources': [
         '../gm/gm.cpp',
-        '../src/views/SkTouchGesture.cpp',
-        '../src/views/unix/keysym2ucs.c',
         '<!@(python find.py ../tools/viewer "*.cpp")',
+
+        # views (subset of files for the Android build)
+        '../src/views/SkEvent.cpp',
+        '../src/views/SkEventSink.cpp',
+        '../src/views/SkOSMenu.cpp',
+        '../src/views/SkTagList.cpp',
+        '../src/views/SkTagList.h',
+        '../src/views/SkTouchGesture.cpp',
+        '../src/views/SkView.cpp',
+        '../src/views/SkViewPriv.cpp',
+        '../src/views/SkViewPriv.h',
+        '../src/views/unix/keysym2ucs.c',
       ],
+      'sources!': [
+        '../samplecode/SampleSkLayer.cpp', #relies on SkMatrix44 which doesn't compile
+        '../samplecode/SampleFontCache.cpp', #relies on pthread.h
+      ],      
       'dependencies': [
         'flags.gyp:flags',
         'gputest.gyp:skgputest',
@@ -52,6 +67,11 @@
             'android_deps.gyp:Android_EntryPoint',
             'android_deps.gyp:native_app_glue',
           ],
+          # views depends on SkOSWindow_android, which we don't want to include
+          # so we only include the minimum set of views files in sources
+          'dependencies!': [
+            'views.gyp:views',
+          ],
           'link_settings': {
             'libraries': [
               '-landroid',
@@ -66,11 +86,13 @@
           },
         }],
         ['skia_os != "android"', {
-          'sources/': [ ['exclude', '_android.(h|cpp)$'],
+          'sources/': [
+            ['exclude', '_android.(h|cpp)$'],
+            ['exclude', 'src/views'],
           ],
         }],
         ['skia_os != "linux"', {
-          'sources/': [ 
+          'sources/': [
             ['exclude', '_unix.(h|cpp)$'],
             ['exclude', 'keysym2ucs.c'],
           ],
diff --git a/samplecode/ClockFaceView.cpp b/samplecode/ClockFaceView.cpp
index ef0fec7..9cee95b 100644
--- a/samplecode/ClockFaceView.cpp
+++ b/samplecode/ClockFaceView.cpp
@@ -72,7 +72,14 @@
     : Sk2DPathEffect(matrix), fRadius(radius), fPts(pts) {}
 
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(Dot2DPathEffect)
-
+    class Registrar {
+    public:
+        Registrar() {
+            SkFlattenable::Register("Dot2DPathEffect",
+                                    Dot2DPathEffect::CreateProc,
+                                    Dot2DPathEffect::GetFlattenableType());
+        }
+    };
 protected:
     void begin(const SkIRect& uvBounds, SkPath* dst) const override {
         if (fPts) {
@@ -101,6 +108,8 @@
     typedef Sk2DPathEffect INHERITED;
 };
 
+static Dot2DPathEffect::Registrar gReg0;
+
 sk_sp<SkFlattenable> Dot2DPathEffect::CreateProc(SkReadBuffer& buffer) {
     SkMatrix matrix;
     buffer.readMatrix(&matrix);
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index 971044c..40ead74 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -400,45 +400,8 @@
 }
 //////////////////
 
-SkFuncViewFactory::SkFuncViewFactory(SkViewCreateFunc func)
-    : fCreateFunc(func) {
-}
-
-SkView* SkFuncViewFactory::operator() () const {
-    return (*fCreateFunc)();
-}
-
 #include "GMSampleView.h"
 
-SkGMSampleViewFactory::SkGMSampleViewFactory(GMFactoryFunc func)
-    : fFunc(func) {
-}
-
-SkView* SkGMSampleViewFactory::operator() () const {
-    skiagm::GM* gm = fFunc(nullptr);
-    gm->setMode(skiagm::GM::kSample_Mode);
-    return new GMSampleView(gm);
-}
-
-SkViewRegister* SkViewRegister::gHead;
-SkViewRegister::SkViewRegister(SkViewFactory* fact) : fFact(fact) {
-    fFact->ref();
-    fChain = gHead;
-    gHead = this;
-}
-
-SkViewRegister::SkViewRegister(SkViewCreateFunc func) {
-    fFact = new SkFuncViewFactory(func);
-    fChain = gHead;
-    gHead = this;
-}
-
-SkViewRegister::SkViewRegister(GMFactoryFunc func) {
-    fFact = new SkGMSampleViewFactory(func);
-    fChain = gHead;
-    gHead = this;
-}
-
 class AutoUnrefArray {
 public:
     AutoUnrefArray() {}
@@ -567,72 +530,6 @@
     typedef SkPaintFilterCanvas INHERITED;
 };
 
-//////////////////////////////////////////////////////////////////////////////
-
-#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";
-static const char gUpdateWindowTitleEvtName[] = "SampleCode_UpdateWindowTitle";
-
-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::RequestTitle(SkView* view, SkString* title) {
-    SkEvent evt(gTitleEvtName);
-    if (view->doQuery(&evt)) {
-        title->set(evt.findString(gTitleEvtName));
-        return true;
-    }
-    return false;
-}
-
-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);
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 enum TilingMode {
@@ -2214,60 +2111,6 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static const char is_sample_view_tag[] = "sample-is-sample-view";
-static const char repeat_count_tag[] = "sample-set-repeat-count";
-
-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::onEvent(const SkEvent& evt) {
-    if (evt.isType(repeat_count_tag)) {
-        fRepeatCount = 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);
-}
-
-void SampleView::onDraw(SkCanvas* canvas) {
-    if (!fHaveCalledOnceBeforeDraw) {
-        fHaveCalledOnceBeforeDraw = true;
-        this->onOnceBeforeDraw();
-    }
-    this->onDrawBackground(canvas);
-
-    for (int i = 0; i < fRepeatCount; i++) {
-        SkAutoCanvasRestore acr(canvas, true);
-        this->onDrawContent(canvas);
-#if SK_SUPPORT_GPU
-        // Ensure the GrContext doesn't batch across draw loops.
-        if (GrContext* context = canvas->getGrContext()) {
-            context->flush();
-        }
-#endif
-    }
-}
-
-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;
diff --git a/samplecode/SampleAtlas.cpp b/samplecode/SampleAtlas.cpp
index 7cf1bb3..3daf312 100644
--- a/samplecode/SampleAtlas.cpp
+++ b/samplecode/SampleAtlas.cpp
@@ -232,9 +232,11 @@
 
     void onDrawContent(SkCanvas* canvas) override {
         canvas->drawDrawable(fDrawable);
-        this->inval(nullptr);
     }
 
+    bool onAnimate(const SkAnimTimer&) override {
+        return true;
+    }
 #if 0
     // TODO: switch over to use this for our animation
     bool onAnimate(const SkAnimTimer& timer) override {
diff --git a/samplecode/SampleClock.cpp b/samplecode/SampleClock.cpp
index ae7462d..ff3a5b1 100644
--- a/samplecode/SampleClock.cpp
+++ b/samplecode/SampleClock.cpp
@@ -215,8 +215,10 @@
 #endif
 
         canvas->restore();
+    }
 
-        this->inval(nullptr);
+    bool onAnimate(const SkAnimTimer&) override {
+        return true;
     }
 
 private:
diff --git a/samplecode/SampleCode.cpp b/samplecode/SampleCode.cpp
new file mode 100644
index 0000000..7b9c0ff
--- /dev/null
+++ b/samplecode/SampleCode.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SampleCode.h"
+#include "SkCanvas.h"
+
+#if SK_SUPPORT_GPU
+#   include "GrContext.h"
+#   if SK_ANGLE
+#       include "gl/angle/GLTestContext_angle.h"
+#   endif
+#else
+class GrContext;
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+
+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::RequestTitle(SkView* view, SkString* title) {
+    SkEvent evt(gTitleEvtName);
+    if (view->doQuery(&evt)) {
+        title->set(evt.findString(gTitleEvtName));
+        return true;
+    }
+    return false;
+}
+
+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);
+}
+
+SkViewRegister* SkViewRegister::gHead;
+SkViewRegister::SkViewRegister(SkViewFactory* fact) : fFact(fact) {
+    fFact->ref();
+    fChain = gHead;
+    gHead = this;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkFuncViewFactory::SkFuncViewFactory(SkViewCreateFunc func)
+    : fCreateFunc(func) {
+}
+
+SkView* SkFuncViewFactory::operator() () const {
+    return (*fCreateFunc)();
+}
+
+#include "GMSampleView.h"
+
+SkGMSampleViewFactory::SkGMSampleViewFactory(GMFactoryFunc func)
+    : fFunc(func) {
+}
+
+SkView* SkGMSampleViewFactory::operator() () const {
+    skiagm::GM* gm = fFunc(nullptr);
+    gm->setMode(skiagm::GM::kSample_Mode);
+    return new GMSampleView(gm);
+}
+
+SkViewRegister::SkViewRegister(SkViewCreateFunc func) {
+    fFact = new SkFuncViewFactory(func);
+    fChain = gHead;
+    gHead = this;
+}
+
+SkViewRegister::SkViewRegister(GMFactoryFunc func) {
+    fFact = new SkGMSampleViewFactory(func);
+    fChain = gHead;
+    gHead = this;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static const char is_sample_view_tag[] = "sample-is-sample-view";
+static const char repeat_count_tag[] = "sample-set-repeat-count";
+
+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::onEvent(const SkEvent& evt) {
+    if (evt.isType(repeat_count_tag)) {
+        fRepeatCount = 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);
+}
+
+void SampleView::onDraw(SkCanvas* canvas) {
+    if (!fHaveCalledOnceBeforeDraw) {
+        fHaveCalledOnceBeforeDraw = true;
+        this->onOnceBeforeDraw();
+    }
+    this->onDrawBackground(canvas);
+
+    for (int i = 0; i < fRepeatCount; i++) {
+        SkAutoCanvasRestore acr(canvas, true);
+        this->onDrawContent(canvas);
+#if SK_SUPPORT_GPU
+        // Ensure the GrContext doesn't batch across draw loops.
+        if (GrContext* context = canvas->getGrContext()) {
+            context->flush();
+        }
+#endif
+    }
+}
+
+void SampleView::onDrawBackground(SkCanvas* canvas) {
+    canvas->drawColor(fBGColor);
+}
+
diff --git a/samplecode/SampleCode.h b/samplecode/SampleCode.h
index e4ccfb2..fe72e4b 100644
--- a/samplecode/SampleCode.h
+++ b/samplecode/SampleCode.h
@@ -21,6 +21,15 @@
     static SkView*          SK_MACRO_APPEND_LINE(F_)() { code } \
     static SkViewRegister   SK_MACRO_APPEND_LINE(R_)(SK_MACRO_APPEND_LINE(F_));
 
+#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";
+static const char gUpdateWindowTitleEvtName[] = "SampleCode_UpdateWindowTitle";
 
 class SampleCode {
 public:
diff --git a/src/fonts/SkTestScalerContext.cpp b/src/fonts/SkTestScalerContext.cpp
index a274856..ebe2ee1 100644
--- a/src/fonts/SkTestScalerContext.cpp
+++ b/src/fonts/SkTestScalerContext.cpp
@@ -20,7 +20,7 @@
 SkTestFont::SkTestFont(const SkTestFontData& fontData)
     : INHERITED()
     , fCharCodes(fontData.fCharCodes)
-    , fCharCodesCount(fontData.fCharCodesCount)
+    , fCharCodesCount(fontData.fCharCodes ? fontData.fCharCodesCount : 0)
     , fWidths(fontData.fWidths)
     , fMetrics(fontData.fMetrics)
     , fName(fontData.fName)
diff --git a/tools/viewer/ImageSlide.cpp b/tools/viewer/ImageSlide.cpp
index 4a03185..de5ce4c 100644
--- a/tools/viewer/ImageSlide.cpp
+++ b/tools/viewer/ImageSlide.cpp
@@ -35,7 +35,7 @@
     }
 }
 
-void ImageSlide::load() {
+void ImageSlide::load(SkScalar, SkScalar) {
     sk_sp<SkData> encoded = SkData::MakeFromFileName(fPath.c_str());
     fImage = SkImage::MakeFromEncoded(encoded);
     fImage->asLegacyBitmap(&fOriginalBitmap, SkImage::kRO_LegacyBitmapMode);
diff --git a/tools/viewer/ImageSlide.h b/tools/viewer/ImageSlide.h
index 88254dd..0dd816e 100644
--- a/tools/viewer/ImageSlide.h
+++ b/tools/viewer/ImageSlide.h
@@ -21,7 +21,7 @@
     SkISize getDimensions() const override;
 
     void draw(SkCanvas* canvas) override;
-    void load() override;
+    void load(SkScalar winWidth, SkScalar winHeight) override;
     void unload() override;
 
 private:
diff --git a/tools/viewer/SKPSlide.cpp b/tools/viewer/SKPSlide.cpp
index 6a9899b..9419253 100644
--- a/tools/viewer/SKPSlide.cpp
+++ b/tools/viewer/SKPSlide.cpp
@@ -48,7 +48,7 @@
     return pic;
 }
 
-void SKPSlide::load() {
+void SKPSlide::load(SkScalar, SkScalar) {
     fPic = read_picture(fPath.c_str());
     fCullRect = fPic->cullRect().roundOut();
 }
diff --git a/tools/viewer/SKPSlide.h b/tools/viewer/SKPSlide.h
index 42845fa..ff92ed1 100644
--- a/tools/viewer/SKPSlide.h
+++ b/tools/viewer/SKPSlide.h
@@ -19,7 +19,7 @@
     SkISize getDimensions() const override { return fCullRect.size(); }
 
     void draw(SkCanvas* canvas) override;
-    void load() override;
+    void load(SkScalar winWidth, SkScalar winHeight) override;
     void unload() override;
 
 private:
diff --git a/tools/viewer/SampleSlide.cpp b/tools/viewer/SampleSlide.cpp
new file mode 100755
index 0000000..5e02ff1
--- /dev/null
+++ b/tools/viewer/SampleSlide.cpp
@@ -0,0 +1,45 @@
+/*
+* Copyright 2016 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#include "SampleSlide.h"
+
+#include "SkCanvas.h"
+#include "SkCommonFlags.h"
+#include "SkOSFile.h"
+#include "SkStream.h"
+
+SampleSlide::SampleSlide(const SkViewFactory* factory) : fViewFactory(factory) {
+    SkView* view = (*factory)();
+    SampleCode::RequestTitle(view, &fName);
+    view->unref();
+}
+
+SampleSlide::~SampleSlide() {}
+
+void SampleSlide::draw(SkCanvas* canvas) {
+    fView->draw(canvas);
+}
+
+void SampleSlide::load(SkScalar winWidth, SkScalar winHeight) {
+    fView = (*fViewFactory)();
+    fView->setVisibleP(true);
+    fView->setClipToBounds(false);
+    fView->setSize(winWidth, winHeight);
+}
+
+void SampleSlide::unload() {
+    fView->unref();
+    fView = nullptr;
+}
+
+#if defined(SK_BUILD_FOR_ANDROID)
+// these are normally defined in SkOSWindow_unix, but we don't
+// want to include that
+void SkEvent::SignalNonEmptyQueue() {}
+
+void SkEvent::SignalQueueTimer(SkMSec delay) {}
+#endif
diff --git a/tools/viewer/SampleSlide.h b/tools/viewer/SampleSlide.h
new file mode 100755
index 0000000..3d772d0
--- /dev/null
+++ b/tools/viewer/SampleSlide.h
@@ -0,0 +1,34 @@
+/*
+* Copyright 2016 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#ifndef SampleSlide_DEFINED
+#define SampleSlide_DEFINED
+
+#include "Slide.h"
+#include "SampleCode.h"
+
+class SampleSlide : public Slide {
+public:
+    SampleSlide(const SkViewFactory* factory);
+    ~SampleSlide() override;
+
+    void draw(SkCanvas* canvas) override;
+    void load(SkScalar winWidth, SkScalar winHeight) override;
+    void unload() override;
+    bool animate(const SkAnimTimer& timer) override {
+        if (SampleView::IsSampleView(fView)) {
+            return ((SampleView*)fView)->animate(timer);
+        }
+        return false;
+    }
+
+private:
+    const SkViewFactory*   fViewFactory;
+    SkView*                fView;
+};
+
+#endif
diff --git a/tools/viewer/Slide.h b/tools/viewer/Slide.h
index cdc225b..bc0ffd4 100644
--- a/tools/viewer/Slide.h
+++ b/tools/viewer/Slide.h
@@ -19,11 +19,13 @@
 public:
     virtual ~Slide() {}
 
-    virtual SkISize getDimensions() const = 0;
+    virtual SkISize getDimensions() const {
+        return SkISize::Make(0, 0);
+    }
 
     virtual void draw(SkCanvas* canvas) = 0;
     virtual bool animate(const SkAnimTimer&) { return false;  }
-    virtual void load() {}
+    virtual void load(SkScalar winWidth, SkScalar winHeight) {}
     virtual void unload() {}
 
     SkString getName() { return fName; }
diff --git a/tools/viewer/Viewer.cpp b/tools/viewer/Viewer.cpp
index 7052a3a..43697f8 100644
--- a/tools/viewer/Viewer.cpp
+++ b/tools/viewer/Viewer.cpp
@@ -9,6 +9,7 @@
 
 #include "GMSlide.h"
 #include "ImageSlide.h"
+#include "SampleSlide.h"
 #include "SKPSlide.h"
 
 #include "SkCanvas.h"
@@ -205,6 +206,14 @@
         fSlides[fSlides.count() - i - 1] = temp;
     }
 
+    // samples
+    const SkViewRegister* reg = SkViewRegister::Head();
+    while (reg) {
+        sk_sp<Slide> slide(new SampleSlide(reg->factory()));
+        fSlides.push_back(slide);
+        reg = reg->next();
+    }
+
     // SKPs
     for (int i = 0; i < FLAGS_skps.count(); i++) {
         if (SkStrEndsWith(FLAGS_skps[i], ".skp")) {
@@ -270,7 +279,7 @@
     }
 
     // prepare dimensions for image slides
-    fSlides[fCurrentSlide]->load();
+    fSlides[fCurrentSlide]->load(SkIntToScalar(fWindow->width()), SkIntToScalar(fWindow->height()));
 
     fGesture.reset();
     fDefaultMatrix.reset();