Unreviewed changes to the gm tests for paths. Each test is broken into four
smaller images to avoid problems with XPS on Windows hanging on large images.

git-svn-id: http://skia.googlecode.com/svn/trunk@2911 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/cubicpaths.cpp b/gm/cubicpaths.cpp
index 80e38ca..e8c38d1 100644
--- a/gm/cubicpaths.cpp
+++ b/gm/cubicpaths.cpp
@@ -10,26 +10,26 @@
 #include "SkRandom.h"
 
 namespace skiagm {
-
-class CubicPathsGM : public GM {
+class ZeroCubicPathGM : public GM {
 public:
-    CubicPathsGM() {}
+    ZeroCubicPathGM() {}
 
 protected:
     SkString onShortName() {
-        return SkString("cubicpaths");
+        return SkString("zerocubicpath");
     }
         
-    SkISize onISize() { return make_isize(1800, 1110); }
+    SkISize onISize() { return make_isize(1240, 390); }
     
     void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
-                  const SkRect& clip,SkPaint::Cap cap,
+                  const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
                   SkPaint::Style style, SkPath::FillType fill,
                   SkScalar strokeWidth) {
         path.setFillType(fill);
         SkPaint paint;
         paint.setStrokeCap(cap);
         paint.setStrokeWidth(strokeWidth);
+        paint.setStrokeJoin(join);
         paint.setColor(color);
         paint.setStyle(style);
         canvas->save();
@@ -59,50 +59,33 @@
             {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
         };
         struct CapAndName {
-            SkPaint::Cap fCap;
-            const char*  fName;
+            SkPaint::Cap  fCap;
+            SkPaint::Join fJoin;
+            const char*   fName;
         };
         static const CapAndName gCaps[] = {
-            {SkPaint::kButt_Cap, "Butt"},
-            {SkPaint::kRound_Cap, "Round"},
-            {SkPaint::kSquare_Cap, "Square"},
+            {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
+            {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
+            {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
         };
         struct PathAndName {
             SkPath      fPath;
             const char* fName;
         };
-        PathAndName gPaths[4];
-        gPaths[0].fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[0].fPath.cubicTo(50*SK_Scalar1, 15*SK_Scalar1,
-                                50*SK_Scalar1, 15*SK_Scalar1,
-                                50*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[0].fName = "moveTo-zerocubic";
-        gPaths[1].fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[1].fPath.cubicTo(50*SK_Scalar1, 15*SK_Scalar1,
-                                50*SK_Scalar1, 15*SK_Scalar1,
-                                50*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[1].fPath.close();
-        gPaths[1].fName = "moveTo-zerocubic-close";
-        gPaths[2].fPath.moveTo(30*SK_Scalar1, 10*SK_Scalar1);
-        gPaths[2].fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1,
-                                60*SK_Scalar1, 20*SK_Scalar1,
-                                70*SK_Scalar1, 10*SK_Scalar1);
-        gPaths[2].fName = "moveTo-cubic";
-        gPaths[3].fPath.moveTo(30*SK_Scalar1, 10*SK_Scalar1);
-        gPaths[3].fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1,
-                                60*SK_Scalar1, 20*SK_Scalar1,
-                                70*SK_Scalar1, 10*SK_Scalar1);
-        gPaths[3].fPath.close();
-        gPaths[3].fName = "moveTo-cubic-close";
+        PathAndName path;
+        path.fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
+        path.fPath.cubicTo(50*SK_Scalar1, 15*SK_Scalar1,
+                           50*SK_Scalar1, 15*SK_Scalar1,
+                           50*SK_Scalar1, 15*SK_Scalar1);
+        path.fName = "moveTo-zerocubic";
 
         SkPaint titlePaint;
         titlePaint.setColor(SK_ColorBLACK);
         titlePaint.setAntiAlias(true);
         titlePaint.setLCDRenderText(true);
         titlePaint.setTextSize(15 * SK_Scalar1);
-        const char title[] = "Cubic Paths Drawn Into Rectangle Clips With "
-                             "Indicated Style, Fill and Linecaps, "
-                             "with random stroke widths";
+        const char title[] = "Zero-Length Cubic Drawn Into Rectangle Clips With "
+                             "Indicated Style, Fill and Linecaps, with stroke width 10";
         canvas->drawText(title, strlen(title),
                             20 * SK_Scalar1,
                             20 * SK_Scalar1,
@@ -113,61 +96,481 @@
         canvas->save();
         canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
         canvas->save();
-        for (size_t path = 0; path < SK_ARRAY_COUNT(gPaths); ++path) {
-            if (0 < path) {
-                canvas->translate(0, (rect.height() + 60 * SK_Scalar1) * 3);
+        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+            if (0 < cap) {
+                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
             }
             canvas->save();
-            for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
-                if (0 < cap) {
-                    canvas->translate((rect.width() + 40 * SK_Scalar1) * 4, 0);
+            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+                if (0 < fill) {
+                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
                 }
                 canvas->save();
                 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
                     if (0 < style) {
-                        canvas->translate(0, rect.height() + 60 * SK_Scalar1);
+                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
                     }
-                    canvas->save();
-                    for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
-                        if (0 < fill) {
-                            canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
-                        }
         
-                        SkColor color = 0xff007000;
-                        this->drawPath(gPaths[path].fPath, canvas, color, rect,
-                                       gCaps[cap].fCap, gStyles[style].fStyle,
-                                       gFills[fill].fFill, SK_Scalar1*10);
+                    SkColor color = 0xff007000;
+                    this->drawPath(path.fPath, canvas, color, rect,
+                                    gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
+                                    gFills[fill].fFill, SK_Scalar1*10);
         
-                        SkPaint rectPaint;
-                        rectPaint.setColor(SK_ColorBLACK);
-                        rectPaint.setStyle(SkPaint::kStroke_Style);
-                        rectPaint.setStrokeWidth(-1);
-                        rectPaint.setAntiAlias(true);
-                        canvas->drawRect(rect, rectPaint);
+                    SkPaint rectPaint;
+                    rectPaint.setColor(SK_ColorBLACK);
+                    rectPaint.setStyle(SkPaint::kStroke_Style);
+                    rectPaint.setStrokeWidth(-1);
+                    rectPaint.setAntiAlias(true);
+                    canvas->drawRect(rect, rectPaint);
         
-                        SkPaint labelPaint;
-                        labelPaint.setColor(color);
-                        labelPaint.setAntiAlias(true);
-                        labelPaint.setLCDRenderText(true);
-                        labelPaint.setTextSize(10 * SK_Scalar1);
-                        canvas->drawText(gStyles[style].fName,
-                                         strlen(gStyles[style].fName),
-                                         0, rect.height() + 12 * SK_Scalar1,
-                                         labelPaint);
-                        canvas->drawText(gFills[fill].fName,
-                                         strlen(gFills[fill].fName),
-                                         0, rect.height() + 24 * SK_Scalar1,
-                                         labelPaint);
-                        canvas->drawText(gCaps[cap].fName,
-                                         strlen(gCaps[cap].fName),
-                                         0, rect.height() + 36 * SK_Scalar1,
-                                         labelPaint);
-                        canvas->drawText(gPaths[path].fName,
-                                         strlen(gPaths[path].fName),
-                                         0, rect.height() + 48 * SK_Scalar1,
-                                         labelPaint);
+                    SkPaint labelPaint;
+                    labelPaint.setColor(color);
+                    labelPaint.setAntiAlias(true);
+                    labelPaint.setLCDRenderText(true);
+                    labelPaint.setTextSize(10 * SK_Scalar1);
+                    canvas->drawText(gStyles[style].fName,
+                                        strlen(gStyles[style].fName),
+                                        0, rect.height() + 12 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gFills[fill].fName,
+                                        strlen(gFills[fill].fName),
+                                        0, rect.height() + 24 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gCaps[cap].fName,
+                                        strlen(gCaps[cap].fName),
+                                        0, rect.height() + 36 * SK_Scalar1,
+                                        labelPaint);
+                }
+                canvas->restore();
+            }
+            canvas->restore();
+        }
+        canvas->restore();
+        canvas->restore();
+    }
+    
+private:
+    typedef GM INHERITED;
+};
+
+class ZeroCubicClosePathGM : public GM {
+public:
+    ZeroCubicClosePathGM() {}
+
+protected:
+    SkString onShortName() {
+        return SkString("zerocubicclosepath");
+    }
+        
+    SkISize onISize() { return make_isize(1240, 390); }
+    
+    void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
+                  const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
+                  SkPaint::Style style, SkPath::FillType fill,
+                  SkScalar strokeWidth) {
+        path.setFillType(fill);
+        SkPaint paint;
+        paint.setStrokeCap(cap);
+        paint.setStrokeWidth(strokeWidth);
+        paint.setStrokeJoin(join);
+        paint.setColor(color);
+        paint.setStyle(style);
+        canvas->save();
+        canvas->clipRect(clip);
+        canvas->drawPath(path, paint);
+        canvas->restore();
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        struct FillAndName {
+            SkPath::FillType fFill;
+            const char*      fName;
+        };
+        static const FillAndName gFills[] = {
+            {SkPath::kWinding_FillType, "Winding"},
+            {SkPath::kEvenOdd_FillType, "Even / Odd"},
+            {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+            {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+        };
+        struct StyleAndName {
+            SkPaint::Style fStyle;
+            const char*    fName;
+        };
+        static const StyleAndName gStyles[] = {
+            {SkPaint::kFill_Style, "Fill"},
+            {SkPaint::kStroke_Style, "Stroke"},
+            {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+        };
+        struct CapAndName {
+            SkPaint::Cap  fCap;
+            SkPaint::Join fJoin;
+            const char*   fName;
+        };
+        static const CapAndName gCaps[] = {
+            {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
+            {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
+            {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
+        };
+        struct PathAndName {
+            SkPath      fPath;
+            const char* fName;
+        };
+        PathAndName path;
+        path.fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
+        path.fPath.cubicTo(50*SK_Scalar1, 15*SK_Scalar1,
+                           50*SK_Scalar1, 15*SK_Scalar1,
+                           50*SK_Scalar1, 15*SK_Scalar1);
+        path.fPath.close();
+        path.fName = "moveTo-zerocubic-close";
+
+        SkPaint titlePaint;
+        titlePaint.setColor(SK_ColorBLACK);
+        titlePaint.setAntiAlias(true);
+        titlePaint.setLCDRenderText(true);
+        titlePaint.setTextSize(15 * SK_Scalar1);
+        const char title[] = "Zero-Length Cubic Closed Drawn Into Rectangle Clips With "
+                             "Indicated Style, Fill and Linecaps, with stroke width 10";
+        canvas->drawText(title, strlen(title),
+                            20 * SK_Scalar1,
+                            20 * SK_Scalar1,
+                            titlePaint);
+
+        SkRandom rand;
+        SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
+        canvas->save();
+        canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
+        canvas->save();
+        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+            if (0 < cap) {
+                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
+            }
+            canvas->save();
+            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+                if (0 < fill) {
+                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
+                }
+                canvas->save();
+                for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+                    if (0 < style) {
+                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
                     }
-                    canvas->restore();
+        
+                    SkColor color = 0xff007000;
+                    this->drawPath(path.fPath, canvas, color, rect,
+                                    gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
+                                    gFills[fill].fFill, SK_Scalar1*10);
+        
+                    SkPaint rectPaint;
+                    rectPaint.setColor(SK_ColorBLACK);
+                    rectPaint.setStyle(SkPaint::kStroke_Style);
+                    rectPaint.setStrokeWidth(-1);
+                    rectPaint.setAntiAlias(true);
+                    canvas->drawRect(rect, rectPaint);
+        
+                    SkPaint labelPaint;
+                    labelPaint.setColor(color);
+                    labelPaint.setAntiAlias(true);
+                    labelPaint.setLCDRenderText(true);
+                    labelPaint.setTextSize(10 * SK_Scalar1);
+                    canvas->drawText(gStyles[style].fName,
+                                        strlen(gStyles[style].fName),
+                                        0, rect.height() + 12 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gFills[fill].fName,
+                                        strlen(gFills[fill].fName),
+                                        0, rect.height() + 24 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gCaps[cap].fName,
+                                        strlen(gCaps[cap].fName),
+                                        0, rect.height() + 36 * SK_Scalar1,
+                                        labelPaint);
+                }
+                canvas->restore();
+            }
+            canvas->restore();
+        }
+        canvas->restore();
+        canvas->restore();
+    }
+    
+private:
+    typedef GM INHERITED;
+};
+
+class CubicPathGM : public GM {
+public:
+    CubicPathGM() {}
+
+protected:
+    SkString onShortName() {
+        return SkString("cubicpath");
+    }
+        
+    SkISize onISize() { return make_isize(1240, 390); }
+    
+    void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
+                  const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
+                  SkPaint::Style style, SkPath::FillType fill,
+                  SkScalar strokeWidth) {
+        path.setFillType(fill);
+        SkPaint paint;
+        paint.setStrokeCap(cap);
+        paint.setStrokeWidth(strokeWidth);
+        paint.setStrokeJoin(join);
+        paint.setColor(color);
+        paint.setStyle(style);
+        canvas->save();
+        canvas->clipRect(clip);
+        canvas->drawPath(path, paint);
+        canvas->restore();
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        struct FillAndName {
+            SkPath::FillType fFill;
+            const char*      fName;
+        };
+        static const FillAndName gFills[] = {
+            {SkPath::kWinding_FillType, "Winding"},
+            {SkPath::kEvenOdd_FillType, "Even / Odd"},
+            {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+            {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+        };
+        struct StyleAndName {
+            SkPaint::Style fStyle;
+            const char*    fName;
+        };
+        static const StyleAndName gStyles[] = {
+            {SkPaint::kFill_Style, "Fill"},
+            {SkPaint::kStroke_Style, "Stroke"},
+            {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+        };
+        struct CapAndName {
+            SkPaint::Cap  fCap;
+            SkPaint::Join fJoin;
+            const char*   fName;
+        };
+        static const CapAndName gCaps[] = {
+            {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
+            {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
+            {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
+        };
+        struct PathAndName {
+            SkPath      fPath;
+            const char* fName;
+        };
+        PathAndName path;
+        path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
+        path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1,
+                           60*SK_Scalar1, 20*SK_Scalar1,
+                           75*SK_Scalar1, 10*SK_Scalar1);
+        path.fName = "moveTo-cubic";
+
+        SkPaint titlePaint;
+        titlePaint.setColor(SK_ColorBLACK);
+        titlePaint.setAntiAlias(true);
+        titlePaint.setLCDRenderText(true);
+        titlePaint.setTextSize(15 * SK_Scalar1);
+        const char title[] = "Cubic Drawn Into Rectangle Clips With "
+                             "Indicated Style, Fill and Linecaps, with stroke width 10";
+        canvas->drawText(title, strlen(title),
+                            20 * SK_Scalar1,
+                            20 * SK_Scalar1,
+                            titlePaint);
+
+        SkRandom rand;
+        SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
+        canvas->save();
+        canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
+        canvas->save();
+        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+            if (0 < cap) {
+                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
+            }
+            canvas->save();
+            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+                if (0 < fill) {
+                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
+                }
+                canvas->save();
+                for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+                    if (0 < style) {
+                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
+                    }
+        
+                    SkColor color = 0xff007000;
+                    this->drawPath(path.fPath, canvas, color, rect,
+                                    gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
+                                    gFills[fill].fFill, SK_Scalar1*10);
+        
+                    SkPaint rectPaint;
+                    rectPaint.setColor(SK_ColorBLACK);
+                    rectPaint.setStyle(SkPaint::kStroke_Style);
+                    rectPaint.setStrokeWidth(-1);
+                    rectPaint.setAntiAlias(true);
+                    canvas->drawRect(rect, rectPaint);
+        
+                    SkPaint labelPaint;
+                    labelPaint.setColor(color);
+                    labelPaint.setAntiAlias(true);
+                    labelPaint.setLCDRenderText(true);
+                    labelPaint.setTextSize(10 * SK_Scalar1);
+                    canvas->drawText(gStyles[style].fName,
+                                        strlen(gStyles[style].fName),
+                                        0, rect.height() + 12 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gFills[fill].fName,
+                                        strlen(gFills[fill].fName),
+                                        0, rect.height() + 24 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gCaps[cap].fName,
+                                        strlen(gCaps[cap].fName),
+                                        0, rect.height() + 36 * SK_Scalar1,
+                                        labelPaint);
+                }
+                canvas->restore();
+            }
+            canvas->restore();
+        }
+        canvas->restore();
+        canvas->restore();
+    }
+    
+private:
+    typedef GM INHERITED;
+};
+
+class CubicClosePathGM : public GM {
+public:
+    CubicClosePathGM() {}
+
+protected:
+    SkString onShortName() {
+        return SkString("cubicclosepath");
+    }
+        
+    SkISize onISize() { return make_isize(1240, 390); }
+    
+    void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
+                  const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
+                  SkPaint::Style style, SkPath::FillType fill,
+                  SkScalar strokeWidth) {
+        path.setFillType(fill);
+        SkPaint paint;
+        paint.setStrokeCap(cap);
+        paint.setStrokeWidth(strokeWidth);
+        paint.setStrokeJoin(join);
+        paint.setColor(color);
+        paint.setStyle(style);
+        canvas->save();
+        canvas->clipRect(clip);
+        canvas->drawPath(path, paint);
+        canvas->restore();
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        struct FillAndName {
+            SkPath::FillType fFill;
+            const char*      fName;
+        };
+        static const FillAndName gFills[] = {
+            {SkPath::kWinding_FillType, "Winding"},
+            {SkPath::kEvenOdd_FillType, "Even / Odd"},
+            {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+            {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+        };
+        struct StyleAndName {
+            SkPaint::Style fStyle;
+            const char*    fName;
+        };
+        static const StyleAndName gStyles[] = {
+            {SkPaint::kFill_Style, "Fill"},
+            {SkPaint::kStroke_Style, "Stroke"},
+            {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+        };
+        struct CapAndName {
+            SkPaint::Cap  fCap;
+            SkPaint::Join fJoin;
+            const char*   fName;
+        };
+        static const CapAndName gCaps[] = {
+            {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
+            {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
+            {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
+        };
+        struct PathAndName {
+            SkPath      fPath;
+            const char* fName;
+        };
+        PathAndName path;
+        path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
+        path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1,
+                           60*SK_Scalar1, 20*SK_Scalar1,
+                           75*SK_Scalar1, 10*SK_Scalar1);
+        path.fPath.close();
+        path.fName = "moveTo-cubic-close";
+
+        SkPaint titlePaint;
+        titlePaint.setColor(SK_ColorBLACK);
+        titlePaint.setAntiAlias(true);
+        titlePaint.setLCDRenderText(true);
+        titlePaint.setTextSize(15 * SK_Scalar1);
+        const char title[] = "Cubic Closed Drawn Into Rectangle Clips With "
+                             "Indicated Style, Fill and Linecaps, with stroke width 10";
+        canvas->drawText(title, strlen(title),
+                            20 * SK_Scalar1,
+                            20 * SK_Scalar1,
+                            titlePaint);
+
+        SkRandom rand;
+        SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
+        canvas->save();
+        canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
+        canvas->save();
+        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+            if (0 < cap) {
+                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
+            }
+            canvas->save();
+            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+                if (0 < fill) {
+                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
+                }
+                canvas->save();
+                for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+                    if (0 < style) {
+                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
+                    }
+        
+                    SkColor color = 0xff007000;
+                    this->drawPath(path.fPath, canvas, color, rect,
+                                    gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
+                                    gFills[fill].fFill, SK_Scalar1*10);
+        
+                    SkPaint rectPaint;
+                    rectPaint.setColor(SK_ColorBLACK);
+                    rectPaint.setStyle(SkPaint::kStroke_Style);
+                    rectPaint.setStrokeWidth(-1);
+                    rectPaint.setAntiAlias(true);
+                    canvas->drawRect(rect, rectPaint);
+        
+                    SkPaint labelPaint;
+                    labelPaint.setColor(color);
+                    labelPaint.setAntiAlias(true);
+                    labelPaint.setLCDRenderText(true);
+                    labelPaint.setTextSize(10 * SK_Scalar1);
+                    canvas->drawText(gStyles[style].fName,
+                                        strlen(gStyles[style].fName),
+                                        0, rect.height() + 12 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gFills[fill].fName,
+                                        strlen(gFills[fill].fName),
+                                        0, rect.height() + 24 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gCaps[cap].fName,
+                                        strlen(gCaps[cap].fName),
+                                        0, rect.height() + 36 * SK_Scalar1,
+                                        labelPaint);
                 }
                 canvas->restore();
             }
@@ -183,7 +586,16 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
-static GM* MyFactory(void*) { return new CubicPathsGM; }
-static GMRegistry reg(MyFactory);
+static GM* ZeroCubicPathFactory(void*) { return new ZeroCubicPathGM; }
+static GMRegistry regZeroCubicPath(ZeroCubicPathFactory);
+
+static GM* ZeroCubicClosePathFactory(void*) { return new ZeroCubicClosePathGM; }
+static GMRegistry regZeroCubicClosePath(ZeroCubicClosePathFactory);
+
+static GM* CubicPathFactory(void*) { return new CubicPathGM; }
+static GMRegistry regCubicPath(CubicPathFactory);
+
+static GM* CubicClosePathFactory(void*) { return new CubicClosePathGM; }
+static GMRegistry regCubicClosePath(CubicClosePathFactory);
 
 }
diff --git a/gm/degeneratesegments.cpp b/gm/degeneratesegments.cpp
index 7288d95..99dd4ad 100644
--- a/gm/degeneratesegments.cpp
+++ b/gm/degeneratesegments.cpp
@@ -26,7 +26,7 @@
         return SkString("degeneratesegments");
     }
         
-    SkISize onISize() { return make_isize(1368, 1230); }
+    SkISize onISize() { return make_isize(896, 930); }
 
     typedef SkPoint (*AddSegmentFunc)(SkPath&, SkPoint&);
     
@@ -190,13 +190,14 @@
     }
 
     void drawPath(SkPath& path, SkCanvas* canvas, SkColor color,
-                  const SkRect& clip, SkPaint::Cap cap,
+                  const SkRect& clip, SkPaint::Cap cap, SkPaint::Join join,
                   SkPaint::Style style, SkPath::FillType fill,
                   SkScalar strokeWidth) {
         path.setFillType(fill);
         SkPaint paint;
         paint.setStrokeCap(cap);
         paint.setStrokeWidth(strokeWidth);
+        paint.setStrokeJoin(join);
         paint.setColor(color);
         paint.setStyle(style);
         canvas->save();
@@ -273,13 +274,14 @@
             {SkPaint::kStrokeAndFill_Style, "Stroke 10 And Fill"}
         };
         struct CapAndName {
-            SkPaint::Cap fCap;
-            const char*  fName;
+            SkPaint::Cap  fCap;
+            SkPaint::Join fJoin;
+            const char*   fName;
         };
         static const CapAndName gCaps[] = {
-            {SkPaint::kButt_Cap, "Butt"},
-            {SkPaint::kRound_Cap, "Round"},
-            {SkPaint::kSquare_Cap, "Square"}
+            {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
+            {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
+            {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
         };
 
         SkPaint titlePaint;
@@ -304,12 +306,12 @@
         unsigned numCaps = SK_ARRAY_COUNT(gCaps);
         unsigned numStyles = SK_ARRAY_COUNT(gStyles);
         unsigned numFills = SK_ARRAY_COUNT(gFills);
-        for (size_t row = 0; row < 8; ++row) {
+        for (size_t row = 0; row < 6; ++row) {
             if (0 < row) {
                 canvas->translate(0, rect.height() + 100*SK_Scalar1);
             }
             canvas->save();
-            for (size_t column = 0; column < 6; ++column) {
+            for (size_t column = 0; column < 4; ++column) {
                 if (0 < column) {
                     canvas->translate(rect.width() + 4*SK_Scalar1, 0);
                 }
@@ -332,7 +334,7 @@
                 pt = gSegmentFunctions[s5](path, pt);
 
                 this->drawPath(path, canvas, color, rect,
-                               cap.fCap, style.fStyle,
+                               cap.fCap, cap.fJoin, style.fStyle,
                                fill.fFill, SK_Scalar1*6);
 
                 SkPaint rectPaint;
diff --git a/gm/linepaths.cpp b/gm/linepaths.cpp
index 2a33920..99c9c49 100644
--- a/gm/linepaths.cpp
+++ b/gm/linepaths.cpp
@@ -11,25 +11,167 @@
 
 namespace skiagm {
 
-class LinePathsGM : public GM {
+class ZeroLinePathGM : public GM {
 public:
-    LinePathsGM() {}
+    ZeroLinePathGM() {}
 
 protected:
     SkString onShortName() {
-        return SkString("linepaths");
+        return SkString("zerolinepath");
     }
         
-    SkISize onISize() { return make_isize(1800, 1110); }
+    SkISize onISize() { return make_isize(1240, 390); }
     
     void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
-                  const SkRect& clip,SkPaint::Cap cap,
+                  const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
                   SkPaint::Style style, SkPath::FillType fill,
                   SkScalar strokeWidth) {
         path.setFillType(fill);
         SkPaint paint;
         paint.setStrokeCap(cap);
         paint.setStrokeWidth(strokeWidth);
+        paint.setStrokeJoin(join);
+        paint.setColor(color);
+        paint.setStyle(style);
+        canvas->save();
+        canvas->clipRect(clip);
+        canvas->drawPath(path, paint);
+        canvas->restore();
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        struct FillAndName {
+            SkPath::FillType fFill;
+            const char*      fName;
+        };
+        static const FillAndName gFills[] = {
+            {SkPath::kWinding_FillType, "Winding"},
+            {SkPath::kEvenOdd_FillType, "Even / Odd"},
+            {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+            {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+        };
+        struct StyleAndName {
+            SkPaint::Style fStyle;
+            const char*    fName;
+        };
+        static const StyleAndName gStyles[] = {
+            {SkPaint::kFill_Style, "Fill"},
+            {SkPaint::kStroke_Style, "Stroke"},
+            {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+        };
+        struct CapAndName {
+            SkPaint::Cap  fCap;
+            SkPaint::Join fJoin;
+            const char*   fName;
+        };
+        static const CapAndName gCaps[] = {
+            {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
+            {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
+            {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
+        };
+        struct PathAndName {
+            SkPath      fPath;
+            const char* fName;
+        };
+        PathAndName path;
+        path.fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
+        path.fPath.lineTo(50*SK_Scalar1, 15*SK_Scalar1);
+        path.fName = "moveTo-zeroline";
+
+        SkPaint titlePaint;
+        titlePaint.setColor(SK_ColorBLACK);
+        titlePaint.setAntiAlias(true);
+        titlePaint.setLCDRenderText(true);
+        titlePaint.setTextSize(15 * SK_Scalar1);
+        const char title[] = "Zero-Length Line Drawn Into Rectangle Clips With "
+                             "Indicated Style, Fill and Linecaps, with stroke width 10";
+        canvas->drawText(title, strlen(title),
+                            20 * SK_Scalar1,
+                            20 * SK_Scalar1,
+                            titlePaint);
+
+        SkRandom rand;
+        SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
+        canvas->save();
+        canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
+        canvas->save();
+        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+            if (0 < cap) {
+                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
+            }
+            canvas->save();
+            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+                if (0 < fill) {
+                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
+                }
+                canvas->save();
+                for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+                    if (0 < style) {
+                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
+                    }
+        
+                    SkColor color = 0xff007000;
+                    this->drawPath(path.fPath, canvas, color, rect,
+                                    gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
+                                    gFills[fill].fFill, SK_Scalar1*10);
+        
+                    SkPaint rectPaint;
+                    rectPaint.setColor(SK_ColorBLACK);
+                    rectPaint.setStyle(SkPaint::kStroke_Style);
+                    rectPaint.setStrokeWidth(-1);
+                    rectPaint.setAntiAlias(true);
+                    canvas->drawRect(rect, rectPaint);
+        
+                    SkPaint labelPaint;
+                    labelPaint.setColor(color);
+                    labelPaint.setAntiAlias(true);
+                    labelPaint.setLCDRenderText(true);
+                    labelPaint.setTextSize(10 * SK_Scalar1);
+                    canvas->drawText(gStyles[style].fName,
+                                        strlen(gStyles[style].fName),
+                                        0, rect.height() + 12 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gFills[fill].fName,
+                                        strlen(gFills[fill].fName),
+                                        0, rect.height() + 24 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gCaps[cap].fName,
+                                        strlen(gCaps[cap].fName),
+                                        0, rect.height() + 36 * SK_Scalar1,
+                                        labelPaint);
+                }
+                canvas->restore();
+            }
+            canvas->restore();
+        }
+        canvas->restore();
+        canvas->restore();
+    }
+    
+private:
+    typedef GM INHERITED;
+};
+
+class ZeroLineClosePathGM : public GM {
+public:
+    ZeroLineClosePathGM() {}
+
+protected:
+    SkString onShortName() {
+        return SkString("zerolineclosepath");
+    }
+        
+    SkISize onISize() { return make_isize(1240, 390); }
+    
+    void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
+                  const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
+                  SkPaint::Style style, SkPath::FillType fill,
+                  SkScalar strokeWidth) {
+        path.setFillType(fill);
+        SkPaint paint;
+        paint.setStrokeCap(cap);
+        paint.setStrokeJoin(join);
+        paint.setStrokeWidth(strokeWidth);
         paint.setColor(color);
         paint.setStyle(style);
         canvas->save();
@@ -59,42 +201,32 @@
             {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
         };
         struct CapAndName {
-            SkPaint::Cap fCap;
-            const char*  fName;
+            SkPaint::Cap  fCap;
+            SkPaint::Join fJoin;
+            const char*   fName;
         };
         static const CapAndName gCaps[] = {
-            {SkPaint::kButt_Cap, "Butt"},
-            {SkPaint::kRound_Cap, "Round"},
-            {SkPaint::kSquare_Cap, "Square"},
+            {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
+            {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
+            {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
         };
         struct PathAndName {
             SkPath      fPath;
             const char* fName;
         };
-        PathAndName gPaths[4];
-        gPaths[0].fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[0].fPath.lineTo(50*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[0].fName = "moveTo-zeroline";
-        gPaths[1].fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[1].fPath.lineTo(50*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[1].fPath.close();
-        gPaths[1].fName = "moveTo-zeroline-close";
-        gPaths[2].fPath.moveTo(30*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[2].fPath.lineTo(70*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[2].fName = "moveTo-line";
-        gPaths[3].fPath.moveTo(30*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[3].fPath.lineTo(70*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[3].fPath.close();
-        gPaths[3].fName = "moveTo-line-close";
+        PathAndName path;
+        path.fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
+        path.fPath.lineTo(50*SK_Scalar1, 15*SK_Scalar1);
+        path.fPath.close();
+        path.fName = "moveTo-zeroline-close";
 
         SkPaint titlePaint;
         titlePaint.setColor(SK_ColorBLACK);
         titlePaint.setAntiAlias(true);
         titlePaint.setLCDRenderText(true);
         titlePaint.setTextSize(15 * SK_Scalar1);
-        const char title[] = "Line Paths Drawn Into Rectangle Clips With "
-                             "Indicated Style, Fill and Linecaps, "
-                             "with random stroke widths";
+        const char title[] = "Zero-Length Line Closed Drawn Into Rectangle Clips With "
+                             "Indicated Style, Fill and Linecaps, with stroke width 10";
         canvas->drawText(title, strlen(title),
                             20 * SK_Scalar1,
                             20 * SK_Scalar1,
@@ -105,61 +237,333 @@
         canvas->save();
         canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
         canvas->save();
-        for (size_t path = 0; path < SK_ARRAY_COUNT(gPaths); ++path) {
-            if (0 < path) {
-                canvas->translate(0, (rect.height() + 60 * SK_Scalar1) * 3);
+        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+            if (0 < cap) {
+                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
             }
             canvas->save();
-            for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
-                if (0 < cap) {
-                    canvas->translate((rect.width() + 40 * SK_Scalar1) * 4, 0);
+            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+                if (0 < fill) {
+                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
                 }
                 canvas->save();
                 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
                     if (0 < style) {
-                        canvas->translate(0, rect.height() + 60 * SK_Scalar1);
+                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
                     }
-                    canvas->save();
-                    for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
-                        if (0 < fill) {
-                            canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
-                        }
         
-                        SkColor color = 0xff007000;
-                        this->drawPath(gPaths[path].fPath, canvas, color, rect,
-                                       gCaps[cap].fCap, gStyles[style].fStyle,
-                                       gFills[fill].fFill, SK_Scalar1*10);
+                    SkColor color = 0xff007000;
+                    this->drawPath(path.fPath, canvas, color, rect,
+                                    gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
+                                    gFills[fill].fFill, SK_Scalar1*10);
         
-                        SkPaint rectPaint;
-                        rectPaint.setColor(SK_ColorBLACK);
-                        rectPaint.setStyle(SkPaint::kStroke_Style);
-                        rectPaint.setStrokeWidth(-1);
-                        rectPaint.setAntiAlias(true);
-                        canvas->drawRect(rect, rectPaint);
+                    SkPaint rectPaint;
+                    rectPaint.setColor(SK_ColorBLACK);
+                    rectPaint.setStyle(SkPaint::kStroke_Style);
+                    rectPaint.setStrokeWidth(-1);
+                    rectPaint.setAntiAlias(true);
+                    canvas->drawRect(rect, rectPaint);
         
-                        SkPaint labelPaint;
-                        labelPaint.setColor(color);
-                        labelPaint.setAntiAlias(true);
-                        labelPaint.setLCDRenderText(true);
-                        labelPaint.setTextSize(10 * SK_Scalar1);
-                        canvas->drawText(gStyles[style].fName,
-                                         strlen(gStyles[style].fName),
-                                         0, rect.height() + 12 * SK_Scalar1,
-                                         labelPaint);
-                        canvas->drawText(gFills[fill].fName,
-                                         strlen(gFills[fill].fName),
-                                         0, rect.height() + 24 * SK_Scalar1,
-                                         labelPaint);
-                        canvas->drawText(gCaps[cap].fName,
-                                         strlen(gCaps[cap].fName),
-                                         0, rect.height() + 36 * SK_Scalar1,
-                                         labelPaint);
-                        canvas->drawText(gPaths[path].fName,
-                                         strlen(gPaths[path].fName),
-                                         0, rect.height() + 48 * SK_Scalar1,
-                                         labelPaint);
+                    SkPaint labelPaint;
+                    labelPaint.setColor(color);
+                    labelPaint.setAntiAlias(true);
+                    labelPaint.setLCDRenderText(true);
+                    labelPaint.setTextSize(10 * SK_Scalar1);
+                    canvas->drawText(gStyles[style].fName,
+                                        strlen(gStyles[style].fName),
+                                        0, rect.height() + 12 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gFills[fill].fName,
+                                        strlen(gFills[fill].fName),
+                                        0, rect.height() + 24 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gCaps[cap].fName,
+                                        strlen(gCaps[cap].fName),
+                                        0, rect.height() + 36 * SK_Scalar1,
+                                        labelPaint);
+                }
+                canvas->restore();
+            }
+            canvas->restore();
+        }
+        canvas->restore();
+        canvas->restore();
+    }
+    
+private:
+    typedef GM INHERITED;
+};
+
+class LinePathGM : public GM {
+public:
+    LinePathGM() {}
+
+protected:
+    SkString onShortName() {
+        return SkString("linepath");
+    }
+        
+    SkISize onISize() { return make_isize(1240, 390); }
+    
+    void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
+                  const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
+                  SkPaint::Style style, SkPath::FillType fill,
+                  SkScalar strokeWidth) {
+        path.setFillType(fill);
+        SkPaint paint;
+        paint.setStrokeCap(cap);
+        paint.setStrokeWidth(strokeWidth);
+        paint.setStrokeJoin(join);
+        paint.setColor(color);
+        paint.setStyle(style);
+        canvas->save();
+        canvas->clipRect(clip);
+        canvas->drawPath(path, paint);
+        canvas->restore();
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        struct FillAndName {
+            SkPath::FillType fFill;
+            const char*      fName;
+        };
+        static const FillAndName gFills[] = {
+            {SkPath::kWinding_FillType, "Winding"},
+            {SkPath::kEvenOdd_FillType, "Even / Odd"},
+            {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+            {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+        };
+        struct StyleAndName {
+            SkPaint::Style fStyle;
+            const char*    fName;
+        };
+        static const StyleAndName gStyles[] = {
+            {SkPaint::kFill_Style, "Fill"},
+            {SkPaint::kStroke_Style, "Stroke"},
+            {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+        };
+        struct CapAndName {
+            SkPaint::Cap  fCap;
+            SkPaint::Join fJoin;
+            const char*   fName;
+        };
+        static const CapAndName gCaps[] = {
+            {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
+            {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
+            {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
+        };
+        struct PathAndName {
+            SkPath      fPath;
+            const char* fName;
+        };
+        PathAndName path;
+        path.fPath.moveTo(25*SK_Scalar1, 15*SK_Scalar1);
+        path.fPath.lineTo(75*SK_Scalar1, 15*SK_Scalar1);
+        path.fName = "moveTo-line";
+
+        SkPaint titlePaint;
+        titlePaint.setColor(SK_ColorBLACK);
+        titlePaint.setAntiAlias(true);
+        titlePaint.setLCDRenderText(true);
+        titlePaint.setTextSize(15 * SK_Scalar1);
+        const char title[] = "Line Drawn Into Rectangle Clips With "
+                             "Indicated Style, Fill and Linecaps, with stroke width 10";
+        canvas->drawText(title, strlen(title),
+                            20 * SK_Scalar1,
+                            20 * SK_Scalar1,
+                            titlePaint);
+
+        SkRandom rand;
+        SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
+        canvas->save();
+        canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
+        canvas->save();
+        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+            if (0 < cap) {
+                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
+            }
+            canvas->save();
+            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+                if (0 < fill) {
+                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
+                }
+                canvas->save();
+                for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+                    if (0 < style) {
+                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
                     }
-                    canvas->restore();
+        
+                    SkColor color = 0xff007000;
+                    this->drawPath(path.fPath, canvas, color, rect,
+                                    gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
+                                    gFills[fill].fFill, SK_Scalar1*10);
+        
+                    SkPaint rectPaint;
+                    rectPaint.setColor(SK_ColorBLACK);
+                    rectPaint.setStyle(SkPaint::kStroke_Style);
+                    rectPaint.setStrokeWidth(-1);
+                    rectPaint.setAntiAlias(true);
+                    canvas->drawRect(rect, rectPaint);
+        
+                    SkPaint labelPaint;
+                    labelPaint.setColor(color);
+                    labelPaint.setAntiAlias(true);
+                    labelPaint.setLCDRenderText(true);
+                    labelPaint.setTextSize(10 * SK_Scalar1);
+                    canvas->drawText(gStyles[style].fName,
+                                        strlen(gStyles[style].fName),
+                                        0, rect.height() + 12 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gFills[fill].fName,
+                                        strlen(gFills[fill].fName),
+                                        0, rect.height() + 24 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gCaps[cap].fName,
+                                        strlen(gCaps[cap].fName),
+                                        0, rect.height() + 36 * SK_Scalar1,
+                                        labelPaint);
+                }
+                canvas->restore();
+            }
+            canvas->restore();
+        }
+        canvas->restore();
+        canvas->restore();
+    }
+    
+private:
+    typedef GM INHERITED;
+};
+
+class LineClosePathGM : public GM {
+public:
+    LineClosePathGM() {}
+
+protected:
+    SkString onShortName() {
+        return SkString("lineclosepath");
+    }
+        
+    SkISize onISize() { return make_isize(1240, 390); }
+    
+    void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
+                  const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
+                  SkPaint::Style style, SkPath::FillType fill,
+                  SkScalar strokeWidth) {
+        path.setFillType(fill);
+        SkPaint paint;
+        paint.setStrokeCap(cap);
+        paint.setStrokeWidth(strokeWidth);
+        paint.setStrokeJoin(join);
+        paint.setColor(color);
+        paint.setStyle(style);
+        canvas->save();
+        canvas->clipRect(clip);
+        canvas->drawPath(path, paint);
+        canvas->restore();
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        struct FillAndName {
+            SkPath::FillType fFill;
+            const char*      fName;
+        };
+        static const FillAndName gFills[] = {
+            {SkPath::kWinding_FillType, "Winding"},
+            {SkPath::kEvenOdd_FillType, "Even / Odd"},
+            {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+            {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+        };
+        struct StyleAndName {
+            SkPaint::Style fStyle;
+            const char*    fName;
+        };
+        static const StyleAndName gStyles[] = {
+            {SkPaint::kFill_Style, "Fill"},
+            {SkPaint::kStroke_Style, "Stroke"},
+            {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+        };
+        struct CapAndName {
+            SkPaint::Cap  fCap;
+            SkPaint::Join fJoin;
+            const char*   fName;
+        };
+        static const CapAndName gCaps[] = {
+            {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
+            {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
+            {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
+        };
+        struct PathAndName {
+            SkPath      fPath;
+            const char* fName;
+        };
+        PathAndName path;
+        path.fPath.moveTo(25*SK_Scalar1, 15*SK_Scalar1);
+        path.fPath.lineTo(75*SK_Scalar1, 15*SK_Scalar1);
+        path.fPath.close();
+        path.fName = "moveTo-line-close";
+
+        SkPaint titlePaint;
+        titlePaint.setColor(SK_ColorBLACK);
+        titlePaint.setAntiAlias(true);
+        titlePaint.setLCDRenderText(true);
+        titlePaint.setTextSize(15 * SK_Scalar1);
+        const char title[] = "Line Closed Drawn Into Rectangle Clips With "
+                             "Indicated Style, Fill and Linecaps, with stroke width 10";
+        canvas->drawText(title, strlen(title),
+                            20 * SK_Scalar1,
+                            20 * SK_Scalar1,
+                            titlePaint);
+
+        SkRandom rand;
+        SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
+        canvas->save();
+        canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
+        canvas->save();
+        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+            if (0 < cap) {
+                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
+            }
+            canvas->save();
+            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+                if (0 < fill) {
+                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
+                }
+                canvas->save();
+                for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+                    if (0 < style) {
+                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
+                    }
+        
+                    SkColor color = 0xff007000;
+                    this->drawPath(path.fPath, canvas, color, rect,
+                                    gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
+                                    gFills[fill].fFill, SK_Scalar1*10);
+        
+                    SkPaint rectPaint;
+                    rectPaint.setColor(SK_ColorBLACK);
+                    rectPaint.setStyle(SkPaint::kStroke_Style);
+                    rectPaint.setStrokeWidth(-1);
+                    rectPaint.setAntiAlias(true);
+                    canvas->drawRect(rect, rectPaint);
+        
+                    SkPaint labelPaint;
+                    labelPaint.setColor(color);
+                    labelPaint.setAntiAlias(true);
+                    labelPaint.setLCDRenderText(true);
+                    labelPaint.setTextSize(10 * SK_Scalar1);
+                    canvas->drawText(gStyles[style].fName,
+                                        strlen(gStyles[style].fName),
+                                        0, rect.height() + 12 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gFills[fill].fName,
+                                        strlen(gFills[fill].fName),
+                                        0, rect.height() + 24 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gCaps[cap].fName,
+                                        strlen(gCaps[cap].fName),
+                                        0, rect.height() + 36 * SK_Scalar1,
+                                        labelPaint);
                 }
                 canvas->restore();
             }
@@ -175,7 +579,16 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
-static GM* MyFactory(void*) { return new LinePathsGM; }
-static GMRegistry reg(MyFactory);
+static GM* ZeroLinePathFactory(void*) { return new ZeroLinePathGM; }
+static GMRegistry regZeroLinePath(ZeroLinePathFactory);
+
+static GM* ZeroLineClosePathFactory(void*) { return new ZeroLineClosePathGM; }
+static GMRegistry regZeroLineClosePath(ZeroLineClosePathFactory);
+
+static GM* LinePathFactory(void*) { return new LinePathGM; }
+static GMRegistry regLinePath(LinePathFactory);
+
+static GM* LineClosePathFactory(void*) { return new LineClosePathGM; }
+static GMRegistry regLineClosePath(LineClosePathFactory);
 
 }
diff --git a/gm/movepaths.cpp b/gm/movepaths.cpp
index 574058e..30a5dfd 100644
--- a/gm/movepaths.cpp
+++ b/gm/movepaths.cpp
@@ -11,16 +11,16 @@
 
 namespace skiagm {
 
-class MovePathsGM : public GM {
+class MovePathGM : public GM {
 public:
-    MovePathsGM() {}
+    MovePathGM() {}
 
 protected:
     SkString onShortName() {
-        return SkString("movepaths");
+        return SkString("movepath");
     }
         
-    SkISize onISize() { return make_isize(1800, 1110); }
+    SkISize onISize() { return make_isize(1240, 390); }
     
     void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
                   const SkRect& clip,SkPaint::Cap cap,
@@ -71,29 +71,17 @@
             SkPath      fPath;
             const char* fName;
         };
-        PathAndName gPaths[4];
-        gPaths[0].fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[0].fName = "moveTo";
-        gPaths[1].fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[1].fPath.close();
-        gPaths[1].fName = "moveTo-close";
-        gPaths[2].fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[2].fPath.moveTo(75*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[2].fName = "moveTo-moveTo";
-        gPaths[3].fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[3].fPath.close();
-        gPaths[3].fPath.moveTo(75*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[3].fPath.close();
-        gPaths[3].fName = "moveTo-close-moveTo-close";
+        PathAndName path;
+        path.fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
+        path.fName = "moveTo";
 
         SkPaint titlePaint;
         titlePaint.setColor(SK_ColorBLACK);
         titlePaint.setAntiAlias(true);
         titlePaint.setLCDRenderText(true);
         titlePaint.setTextSize(15 * SK_Scalar1);
-        const char title[] = "MoveTo Paths Drawn Into Rectangle Clips With "
-                             "Indicated Style, Fill and Linecaps, "
-                             "with random stroke widths";
+        const char title[] = "Lone Move Drawn Into Rectangle Clips With "
+                             "Indicated Style, Fill and Linecaps, with stroke width 10";
         canvas->drawText(title, strlen(title),
                             20 * SK_Scalar1,
                             20 * SK_Scalar1,
@@ -104,61 +92,469 @@
         canvas->save();
         canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
         canvas->save();
-        for (size_t path = 0; path < SK_ARRAY_COUNT(gPaths); ++path) {
-            if (0 < path) {
-                canvas->translate(0, (rect.height() + 60 * SK_Scalar1) * 3);
+        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+            if (0 < cap) {
+                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
             }
             canvas->save();
-            for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
-                if (0 < cap) {
-                    canvas->translate((rect.width() + 40 * SK_Scalar1) * 4, 0);
+            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+                if (0 < fill) {
+                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
                 }
                 canvas->save();
                 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
                     if (0 < style) {
-                        canvas->translate(0, rect.height() + 60 * SK_Scalar1);
+                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
                     }
-                    canvas->save();
-                    for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
-                        if (0 < fill) {
-                            canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
-                        }
         
-                        SkColor color = 0xff007000;
-                        this->drawPath(gPaths[path].fPath, canvas, color, rect,
-                                       gCaps[cap].fCap, gStyles[style].fStyle,
-                                       gFills[fill].fFill, SK_Scalar1*10);
+                    SkColor color = 0xff007000;
+                    this->drawPath(path.fPath, canvas, color, rect,
+                                    gCaps[cap].fCap, gStyles[style].fStyle,
+                                    gFills[fill].fFill, SK_Scalar1*10);
         
-                        SkPaint rectPaint;
-                        rectPaint.setColor(SK_ColorBLACK);
-                        rectPaint.setStyle(SkPaint::kStroke_Style);
-                        rectPaint.setStrokeWidth(-1);
-                        rectPaint.setAntiAlias(true);
-                        canvas->drawRect(rect, rectPaint);
+                    SkPaint rectPaint;
+                    rectPaint.setColor(SK_ColorBLACK);
+                    rectPaint.setStyle(SkPaint::kStroke_Style);
+                    rectPaint.setStrokeWidth(-1);
+                    rectPaint.setAntiAlias(true);
+                    canvas->drawRect(rect, rectPaint);
         
-                        SkPaint labelPaint;
-                        labelPaint.setColor(color);
-                        labelPaint.setAntiAlias(true);
-                        labelPaint.setLCDRenderText(true);
-                        labelPaint.setTextSize(10 * SK_Scalar1);
-                        canvas->drawText(gStyles[style].fName,
-                                         strlen(gStyles[style].fName),
-                                         0, rect.height() + 12 * SK_Scalar1,
-                                         labelPaint);
-                        canvas->drawText(gFills[fill].fName,
-                                         strlen(gFills[fill].fName),
-                                         0, rect.height() + 24 * SK_Scalar1,
-                                         labelPaint);
-                        canvas->drawText(gCaps[cap].fName,
-                                         strlen(gCaps[cap].fName),
-                                         0, rect.height() + 36 * SK_Scalar1,
-                                         labelPaint);
-                        canvas->drawText(gPaths[path].fName,
-                                         strlen(gPaths[path].fName),
-                                         0, rect.height() + 48 * SK_Scalar1,
-                                         labelPaint);
+                    SkPaint labelPaint;
+                    labelPaint.setColor(color);
+                    labelPaint.setAntiAlias(true);
+                    labelPaint.setLCDRenderText(true);
+                    labelPaint.setTextSize(10 * SK_Scalar1);
+                    canvas->drawText(gStyles[style].fName,
+                                        strlen(gStyles[style].fName),
+                                        0, rect.height() + 12 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gFills[fill].fName,
+                                        strlen(gFills[fill].fName),
+                                        0, rect.height() + 24 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gCaps[cap].fName,
+                                        strlen(gCaps[cap].fName),
+                                        0, rect.height() + 36 * SK_Scalar1,
+                                        labelPaint);
+                }
+                canvas->restore();
+            }
+            canvas->restore();
+        }
+        canvas->restore();
+        canvas->restore();
+    }
+    
+private:
+    typedef GM INHERITED;
+};
+
+class MoveClosePathGM : public GM {
+public:
+    MoveClosePathGM() {}
+
+protected:
+    SkString onShortName() {
+        return SkString("moveclosepath");
+    }
+        
+    SkISize onISize() { return make_isize(1240, 390); }
+    
+    void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
+                  const SkRect& clip,SkPaint::Cap cap,
+                  SkPaint::Style style, SkPath::FillType fill,
+                  SkScalar strokeWidth) {
+        path.setFillType(fill);
+        SkPaint paint;
+        paint.setStrokeCap(cap);
+        paint.setStrokeWidth(strokeWidth);
+        paint.setColor(color);
+        paint.setStyle(style);
+        canvas->save();
+        canvas->clipRect(clip);
+        canvas->drawPath(path, paint);
+        canvas->restore();
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        struct FillAndName {
+            SkPath::FillType fFill;
+            const char*      fName;
+        };
+        static const FillAndName gFills[] = {
+            {SkPath::kWinding_FillType, "Winding"},
+            {SkPath::kEvenOdd_FillType, "Even / Odd"},
+            {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+            {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+        };
+        struct StyleAndName {
+            SkPaint::Style fStyle;
+            const char*    fName;
+        };
+        static const StyleAndName gStyles[] = {
+            {SkPaint::kFill_Style, "Fill"},
+            {SkPaint::kStroke_Style, "Stroke"},
+            {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+        };
+        struct CapAndName {
+            SkPaint::Cap fCap;
+            const char*  fName;
+        };
+        static const CapAndName gCaps[] = {
+            {SkPaint::kButt_Cap, "Butt"},
+            {SkPaint::kRound_Cap, "Round"},
+            {SkPaint::kSquare_Cap, "Square"},
+        };
+        struct PathAndName {
+            SkPath      fPath;
+            const char* fName;
+        };
+        PathAndName path;
+        path.fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
+        path.fPath.close();
+        path.fName = "moveTo-close";
+
+        SkPaint titlePaint;
+        titlePaint.setColor(SK_ColorBLACK);
+        titlePaint.setAntiAlias(true);
+        titlePaint.setLCDRenderText(true);
+        titlePaint.setTextSize(15 * SK_Scalar1);
+        const char title[] = "Move Close Drawn Into Rectangle Clips With "
+                             "Indicated Style, Fill and Linecaps, with stroke width 10";
+        canvas->drawText(title, strlen(title),
+                            20 * SK_Scalar1,
+                            20 * SK_Scalar1,
+                            titlePaint);
+
+        SkRandom rand;
+        SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
+        canvas->save();
+        canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
+        canvas->save();
+        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+            if (0 < cap) {
+                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
+            }
+            canvas->save();
+            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+                if (0 < fill) {
+                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
+                }
+                canvas->save();
+                for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+                    if (0 < style) {
+                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
                     }
-                    canvas->restore();
+        
+                    SkColor color = 0xff007000;
+                    this->drawPath(path.fPath, canvas, color, rect,
+                                    gCaps[cap].fCap, gStyles[style].fStyle,
+                                    gFills[fill].fFill, SK_Scalar1*10);
+        
+                    SkPaint rectPaint;
+                    rectPaint.setColor(SK_ColorBLACK);
+                    rectPaint.setStyle(SkPaint::kStroke_Style);
+                    rectPaint.setStrokeWidth(-1);
+                    rectPaint.setAntiAlias(true);
+                    canvas->drawRect(rect, rectPaint);
+        
+                    SkPaint labelPaint;
+                    labelPaint.setColor(color);
+                    labelPaint.setAntiAlias(true);
+                    labelPaint.setLCDRenderText(true);
+                    labelPaint.setTextSize(10 * SK_Scalar1);
+                    canvas->drawText(gStyles[style].fName,
+                                        strlen(gStyles[style].fName),
+                                        0, rect.height() + 12 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gFills[fill].fName,
+                                        strlen(gFills[fill].fName),
+                                        0, rect.height() + 24 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gCaps[cap].fName,
+                                        strlen(gCaps[cap].fName),
+                                        0, rect.height() + 36 * SK_Scalar1,
+                                        labelPaint);
+                }
+                canvas->restore();
+            }
+            canvas->restore();
+        }
+        canvas->restore();
+        canvas->restore();
+    }
+    
+private:
+    typedef GM INHERITED;
+};
+
+class MoveMovePathGM : public GM {
+public:
+    MoveMovePathGM() {}
+
+protected:
+    SkString onShortName() {
+        return SkString("movemovepath");
+    }
+        
+    SkISize onISize() { return make_isize(1240, 390); }
+    
+    void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
+                  const SkRect& clip,SkPaint::Cap cap,
+                  SkPaint::Style style, SkPath::FillType fill,
+                  SkScalar strokeWidth) {
+        path.setFillType(fill);
+        SkPaint paint;
+        paint.setStrokeCap(cap);
+        paint.setStrokeWidth(strokeWidth);
+        paint.setColor(color);
+        paint.setStyle(style);
+        canvas->save();
+        canvas->clipRect(clip);
+        canvas->drawPath(path, paint);
+        canvas->restore();
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        struct FillAndName {
+            SkPath::FillType fFill;
+            const char*      fName;
+        };
+        static const FillAndName gFills[] = {
+            {SkPath::kWinding_FillType, "Winding"},
+            {SkPath::kEvenOdd_FillType, "Even / Odd"},
+            {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+            {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+        };
+        struct StyleAndName {
+            SkPaint::Style fStyle;
+            const char*    fName;
+        };
+        static const StyleAndName gStyles[] = {
+            {SkPaint::kFill_Style, "Fill"},
+            {SkPaint::kStroke_Style, "Stroke"},
+            {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+        };
+        struct CapAndName {
+            SkPaint::Cap fCap;
+            const char*  fName;
+        };
+        static const CapAndName gCaps[] = {
+            {SkPaint::kButt_Cap, "Butt"},
+            {SkPaint::kRound_Cap, "Round"},
+            {SkPaint::kSquare_Cap, "Square"},
+        };
+        struct PathAndName {
+            SkPath      fPath;
+            const char* fName;
+        };
+        PathAndName path;
+        path.fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
+        path.fPath.moveTo(75*SK_Scalar1, 15*SK_Scalar1);
+        path.fName = "moveTo-moveTo";
+
+        SkPaint titlePaint;
+        titlePaint.setColor(SK_ColorBLACK);
+        titlePaint.setAntiAlias(true);
+        titlePaint.setLCDRenderText(true);
+        titlePaint.setTextSize(15 * SK_Scalar1);
+        const char title[] = "Move Move Drawn Into Rectangle Clips With "
+                             "Indicated Style, Fill and Linecaps, with stroke width 10";
+        canvas->drawText(title, strlen(title),
+                            20 * SK_Scalar1,
+                            20 * SK_Scalar1,
+                            titlePaint);
+
+        SkRandom rand;
+        SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
+        canvas->save();
+        canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
+        canvas->save();
+        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+            if (0 < cap) {
+                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
+            }
+            canvas->save();
+            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+                if (0 < fill) {
+                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
+                }
+                canvas->save();
+                for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+                    if (0 < style) {
+                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
+                    }
+        
+                    SkColor color = 0xff007000;
+                    this->drawPath(path.fPath, canvas, color, rect,
+                                    gCaps[cap].fCap, gStyles[style].fStyle,
+                                    gFills[fill].fFill, SK_Scalar1*10);
+        
+                    SkPaint rectPaint;
+                    rectPaint.setColor(SK_ColorBLACK);
+                    rectPaint.setStyle(SkPaint::kStroke_Style);
+                    rectPaint.setStrokeWidth(-1);
+                    rectPaint.setAntiAlias(true);
+                    canvas->drawRect(rect, rectPaint);
+        
+                    SkPaint labelPaint;
+                    labelPaint.setColor(color);
+                    labelPaint.setAntiAlias(true);
+                    labelPaint.setLCDRenderText(true);
+                    labelPaint.setTextSize(10 * SK_Scalar1);
+                    canvas->drawText(gStyles[style].fName,
+                                        strlen(gStyles[style].fName),
+                                        0, rect.height() + 12 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gFills[fill].fName,
+                                        strlen(gFills[fill].fName),
+                                        0, rect.height() + 24 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gCaps[cap].fName,
+                                        strlen(gCaps[cap].fName),
+                                        0, rect.height() + 36 * SK_Scalar1,
+                                        labelPaint);
+                }
+                canvas->restore();
+            }
+            canvas->restore();
+        }
+        canvas->restore();
+        canvas->restore();
+    }
+    
+private:
+    typedef GM INHERITED;
+};
+
+class MoveCloseMoveClosePathGM : public GM {
+public:
+    MoveCloseMoveClosePathGM() {}
+
+protected:
+    SkString onShortName() {
+        return SkString("moveclosemoveclosepath");
+    }
+        
+    SkISize onISize() { return make_isize(1240, 390); }
+    
+    void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
+                  const SkRect& clip,SkPaint::Cap cap,
+                  SkPaint::Style style, SkPath::FillType fill,
+                  SkScalar strokeWidth) {
+        path.setFillType(fill);
+        SkPaint paint;
+        paint.setStrokeCap(cap);
+        paint.setStrokeWidth(strokeWidth);
+        paint.setColor(color);
+        paint.setStyle(style);
+        canvas->save();
+        canvas->clipRect(clip);
+        canvas->drawPath(path, paint);
+        canvas->restore();
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        struct FillAndName {
+            SkPath::FillType fFill;
+            const char*      fName;
+        };
+        static const FillAndName gFills[] = {
+            {SkPath::kWinding_FillType, "Winding"},
+            {SkPath::kEvenOdd_FillType, "Even / Odd"},
+            {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+            {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+        };
+        struct StyleAndName {
+            SkPaint::Style fStyle;
+            const char*    fName;
+        };
+        static const StyleAndName gStyles[] = {
+            {SkPaint::kFill_Style, "Fill"},
+            {SkPaint::kStroke_Style, "Stroke"},
+            {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+        };
+        struct CapAndName {
+            SkPaint::Cap fCap;
+            const char*  fName;
+        };
+        static const CapAndName gCaps[] = {
+            {SkPaint::kButt_Cap, "Butt"},
+            {SkPaint::kRound_Cap, "Round"},
+            {SkPaint::kSquare_Cap, "Square"},
+        };
+        struct PathAndName {
+            SkPath      fPath;
+            const char* fName;
+        };
+        PathAndName path;
+        path.fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
+        path.fPath.close();
+        path.fPath.moveTo(75*SK_Scalar1, 15*SK_Scalar1);
+        path.fPath.close();
+        path.fName = "moveTo-close-moveTo-close";
+
+        SkPaint titlePaint;
+        titlePaint.setColor(SK_ColorBLACK);
+        titlePaint.setAntiAlias(true);
+        titlePaint.setLCDRenderText(true);
+        titlePaint.setTextSize(15 * SK_Scalar1);
+        const char title[] = "Move-Close-Move-Close Drawn Into Rectangle Clips With "
+                             "Indicated Style, Fill and Linecaps, with stroke width 10";
+        canvas->drawText(title, strlen(title),
+                            20 * SK_Scalar1,
+                            20 * SK_Scalar1,
+                            titlePaint);
+
+        SkRandom rand;
+        SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
+        canvas->save();
+        canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
+        canvas->save();
+        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+            if (0 < cap) {
+                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
+            }
+            canvas->save();
+            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+                if (0 < fill) {
+                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
+                }
+                canvas->save();
+                for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+                    if (0 < style) {
+                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
+                    }
+        
+                    SkColor color = 0xff007000;
+                    this->drawPath(path.fPath, canvas, color, rect,
+                                    gCaps[cap].fCap, gStyles[style].fStyle,
+                                    gFills[fill].fFill, SK_Scalar1*10);
+        
+                    SkPaint rectPaint;
+                    rectPaint.setColor(SK_ColorBLACK);
+                    rectPaint.setStyle(SkPaint::kStroke_Style);
+                    rectPaint.setStrokeWidth(-1);
+                    rectPaint.setAntiAlias(true);
+                    canvas->drawRect(rect, rectPaint);
+        
+                    SkPaint labelPaint;
+                    labelPaint.setColor(color);
+                    labelPaint.setAntiAlias(true);
+                    labelPaint.setLCDRenderText(true);
+                    labelPaint.setTextSize(10 * SK_Scalar1);
+                    canvas->drawText(gStyles[style].fName,
+                                        strlen(gStyles[style].fName),
+                                        0, rect.height() + 12 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gFills[fill].fName,
+                                        strlen(gFills[fill].fName),
+                                        0, rect.height() + 24 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gCaps[cap].fName,
+                                        strlen(gCaps[cap].fName),
+                                        0, rect.height() + 36 * SK_Scalar1,
+                                        labelPaint);
                 }
                 canvas->restore();
             }
@@ -174,7 +570,16 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
-static GM* MyFactory(void*) { return new MovePathsGM; }
-static GMRegistry reg(MyFactory);
+static GM* MPathFactory(void*) { return new MovePathGM; }
+static GMRegistry regMPath(MPathFactory);
+
+static GM* MCPathFactory(void*) { return new MoveClosePathGM; }
+static GMRegistry regMCPath(MCPathFactory);
+
+static GM* MMPathFactory(void*) { return new MoveMovePathGM; }
+static GMRegistry regMMPath(MMPathFactory);
+
+static GM* MCMCPathFactory(void*) { return new MoveCloseMoveClosePathGM; }
+static GMRegistry regMCMCPath(MCMCPathFactory);
 
 }
diff --git a/gm/quadpaths.cpp b/gm/quadpaths.cpp
index 32de2f4..1ae9e15 100644
--- a/gm/quadpaths.cpp
+++ b/gm/quadpaths.cpp
@@ -11,25 +11,26 @@
 
 namespace skiagm {
 
-class QuadPathsGM : public GM {
+class ZeroQuadPathGM : public GM {
 public:
-    QuadPathsGM() {}
+    ZeroQuadPathGM() {}
 
 protected:
     SkString onShortName() {
-        return SkString("quadpaths");
+        return SkString("zeroquadpath");
     }
         
-    SkISize onISize() { return make_isize(1800, 1110); }
+    SkISize onISize() { return make_isize(1240, 390); }
     
     void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
-                  const SkRect& clip,SkPaint::Cap cap,
+                  const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
                   SkPaint::Style style, SkPath::FillType fill,
                   SkScalar strokeWidth) {
         path.setFillType(fill);
         SkPaint paint;
         paint.setStrokeCap(cap);
         paint.setStrokeWidth(strokeWidth);
+        paint.setStrokeJoin(join);
         paint.setColor(color);
         paint.setStyle(style);
         canvas->save();
@@ -59,46 +60,32 @@
             {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
         };
         struct CapAndName {
-            SkPaint::Cap fCap;
-            const char*  fName;
+            SkPaint::Cap  fCap;
+            SkPaint::Join fJoin;
+            const char*   fName;
         };
         static const CapAndName gCaps[] = {
-            {SkPaint::kButt_Cap, "Butt"},
-            {SkPaint::kRound_Cap, "Round"},
-            {SkPaint::kSquare_Cap, "Square"},
+            {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
+            {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
+            {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
         };
         struct PathAndName {
             SkPath      fPath;
             const char* fName;
         };
-        PathAndName gPaths[4];
-        gPaths[0].fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[0].fPath.quadTo(50*SK_Scalar1, 15*SK_Scalar1,
-                               50*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[0].fName = "moveTo-zeroquad";
-        gPaths[1].fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[1].fPath.quadTo(50*SK_Scalar1, 15*SK_Scalar1,
-                               50*SK_Scalar1, 15*SK_Scalar1);
-        gPaths[1].fPath.close();
-        gPaths[1].fName = "moveTo-zeroquad-close";
-        gPaths[2].fPath.moveTo(30*SK_Scalar1, 10*SK_Scalar1);
-        gPaths[2].fPath.quadTo(50*SK_Scalar1, 20*SK_Scalar1,
-                               70*SK_Scalar1, 10*SK_Scalar1);
-        gPaths[2].fName = "moveTo-quad";
-        gPaths[3].fPath.moveTo(30*SK_Scalar1, 10*SK_Scalar1);
-        gPaths[3].fPath.quadTo(50*SK_Scalar1, 20*SK_Scalar1,
-                               70*SK_Scalar1, 10*SK_Scalar1);
-        gPaths[3].fPath.close();
-        gPaths[3].fName = "moveTo-quad-close";
+        PathAndName path;
+        path.fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
+        path.fPath.quadTo(50*SK_Scalar1, 15*SK_Scalar1,
+                          50*SK_Scalar1, 15*SK_Scalar1);
+        path.fName = "moveTo-zeroquad";
 
         SkPaint titlePaint;
         titlePaint.setColor(SK_ColorBLACK);
         titlePaint.setAntiAlias(true);
         titlePaint.setLCDRenderText(true);
         titlePaint.setTextSize(15 * SK_Scalar1);
-        const char title[] = "Zero Paths Drawn Into Rectangle Clips With "
-                             "Indicated Style, Fill and Linecaps, "
-                             "with random stroke widths";
+        const char title[] = "Zero-Length Quad Drawn Into Rectangle Clips With "
+                             "Indicated Style, Fill and Linecaps, with stroke width 10";
         canvas->drawText(title, strlen(title),
                             20 * SK_Scalar1,
                             20 * SK_Scalar1,
@@ -109,61 +96,478 @@
         canvas->save();
         canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
         canvas->save();
-        for (size_t path = 0; path < SK_ARRAY_COUNT(gPaths); ++path) {
-            if (0 < path) {
-                canvas->translate(0, (rect.height() + 60 * SK_Scalar1) * 3);
+        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+            if (0 < cap) {
+                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
             }
             canvas->save();
-            for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
-                if (0 < cap) {
-                    canvas->translate((rect.width() + 40 * SK_Scalar1) * 4, 0);
+            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+                if (0 < fill) {
+                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
                 }
                 canvas->save();
                 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
                     if (0 < style) {
-                        canvas->translate(0, rect.height() + 60 * SK_Scalar1);
+                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
                     }
-                    canvas->save();
-                    for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
-                        if (0 < fill) {
-                            canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
-                        }
         
-                        SkColor color = 0xff007000;
-                        this->drawPath(gPaths[path].fPath, canvas, color, rect,
-                                       gCaps[cap].fCap, gStyles[style].fStyle,
-                                       gFills[fill].fFill, SK_Scalar1*10);
+                    SkColor color = 0xff007000;
+                    this->drawPath(path.fPath, canvas, color, rect,
+                                    gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
+                                    gFills[fill].fFill, SK_Scalar1*10);
         
-                        SkPaint rectPaint;
-                        rectPaint.setColor(SK_ColorBLACK);
-                        rectPaint.setStyle(SkPaint::kStroke_Style);
-                        rectPaint.setStrokeWidth(-1);
-                        rectPaint.setAntiAlias(true);
-                        canvas->drawRect(rect, rectPaint);
+                    SkPaint rectPaint;
+                    rectPaint.setColor(SK_ColorBLACK);
+                    rectPaint.setStyle(SkPaint::kStroke_Style);
+                    rectPaint.setStrokeWidth(-1);
+                    rectPaint.setAntiAlias(true);
+                    canvas->drawRect(rect, rectPaint);
         
-                        SkPaint labelPaint;
-                        labelPaint.setColor(color);
-                        labelPaint.setAntiAlias(true);
-                        labelPaint.setLCDRenderText(true);
-                        labelPaint.setTextSize(10 * SK_Scalar1);
-                        canvas->drawText(gStyles[style].fName,
-                                         strlen(gStyles[style].fName),
-                                         0, rect.height() + 12 * SK_Scalar1,
-                                         labelPaint);
-                        canvas->drawText(gFills[fill].fName,
-                                         strlen(gFills[fill].fName),
-                                         0, rect.height() + 24 * SK_Scalar1,
-                                         labelPaint);
-                        canvas->drawText(gCaps[cap].fName,
-                                         strlen(gCaps[cap].fName),
-                                         0, rect.height() + 36 * SK_Scalar1,
-                                         labelPaint);
-                        canvas->drawText(gPaths[path].fName,
-                                         strlen(gPaths[path].fName),
-                                         0, rect.height() + 48 * SK_Scalar1,
-                                         labelPaint);
+                    SkPaint labelPaint;
+                    labelPaint.setColor(color);
+                    labelPaint.setAntiAlias(true);
+                    labelPaint.setLCDRenderText(true);
+                    labelPaint.setTextSize(10 * SK_Scalar1);
+                    canvas->drawText(gStyles[style].fName,
+                                        strlen(gStyles[style].fName),
+                                        0, rect.height() + 12 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gFills[fill].fName,
+                                        strlen(gFills[fill].fName),
+                                        0, rect.height() + 24 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gCaps[cap].fName,
+                                        strlen(gCaps[cap].fName),
+                                        0, rect.height() + 36 * SK_Scalar1,
+                                        labelPaint);
+                }
+                canvas->restore();
+            }
+            canvas->restore();
+        }
+        canvas->restore();
+        canvas->restore();
+    }
+    
+private:
+    typedef GM INHERITED;
+};
+
+class ZeroQuadClosePathGM : public GM {
+public:
+    ZeroQuadClosePathGM() {}
+
+protected:
+    SkString onShortName() {
+        return SkString("zeroquadclosepath");
+    }
+        
+    SkISize onISize() { return make_isize(1240, 390); }
+    
+    void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
+                  const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
+                  SkPaint::Style style, SkPath::FillType fill,
+                  SkScalar strokeWidth) {
+        path.setFillType(fill);
+        SkPaint paint;
+        paint.setStrokeCap(cap);
+        paint.setStrokeWidth(strokeWidth);
+        paint.setStrokeJoin(join);
+        paint.setColor(color);
+        paint.setStyle(style);
+        canvas->save();
+        canvas->clipRect(clip);
+        canvas->drawPath(path, paint);
+        canvas->restore();
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        struct FillAndName {
+            SkPath::FillType fFill;
+            const char*      fName;
+        };
+        static const FillAndName gFills[] = {
+            {SkPath::kWinding_FillType, "Winding"},
+            {SkPath::kEvenOdd_FillType, "Even / Odd"},
+            {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+            {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+        };
+        struct StyleAndName {
+            SkPaint::Style fStyle;
+            const char*    fName;
+        };
+        static const StyleAndName gStyles[] = {
+            {SkPaint::kFill_Style, "Fill"},
+            {SkPaint::kStroke_Style, "Stroke"},
+            {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+        };
+        struct CapAndName {
+            SkPaint::Cap  fCap;
+            SkPaint::Join fJoin;
+            const char*   fName;
+        };
+        static const CapAndName gCaps[] = {
+            {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
+            {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
+            {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
+        };
+        struct PathAndName {
+            SkPath      fPath;
+            const char* fName;
+        };
+        PathAndName path;
+        path.fPath.moveTo(50*SK_Scalar1, 15*SK_Scalar1);
+        path.fPath.quadTo(50*SK_Scalar1, 15*SK_Scalar1,
+                          50*SK_Scalar1, 15*SK_Scalar1);
+        path.fPath.close();
+        path.fName = "moveTo-zeroquad-close";
+
+        SkPaint titlePaint;
+        titlePaint.setColor(SK_ColorBLACK);
+        titlePaint.setAntiAlias(true);
+        titlePaint.setLCDRenderText(true);
+        titlePaint.setTextSize(15 * SK_Scalar1);
+        const char title[] = "Zero-Length Quad Closed Drawn Into Rectangle Clips With "
+                             "Indicated Style, Fill and Linecaps, with stroke width 10";
+        canvas->drawText(title, strlen(title),
+                            20 * SK_Scalar1,
+                            20 * SK_Scalar1,
+                            titlePaint);
+
+        SkRandom rand;
+        SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
+        canvas->save();
+        canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
+        canvas->save();
+        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+            if (0 < cap) {
+                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
+            }
+            canvas->save();
+            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+                if (0 < fill) {
+                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
+                }
+                canvas->save();
+                for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+                    if (0 < style) {
+                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
                     }
-                    canvas->restore();
+        
+                    SkColor color = 0xff007000;
+                    this->drawPath(path.fPath, canvas, color, rect,
+                                    gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
+                                    gFills[fill].fFill, SK_Scalar1*10);
+        
+                    SkPaint rectPaint;
+                    rectPaint.setColor(SK_ColorBLACK);
+                    rectPaint.setStyle(SkPaint::kStroke_Style);
+                    rectPaint.setStrokeWidth(-1);
+                    rectPaint.setAntiAlias(true);
+                    canvas->drawRect(rect, rectPaint);
+        
+                    SkPaint labelPaint;
+                    labelPaint.setColor(color);
+                    labelPaint.setAntiAlias(true);
+                    labelPaint.setLCDRenderText(true);
+                    labelPaint.setTextSize(10 * SK_Scalar1);
+                    canvas->drawText(gStyles[style].fName,
+                                        strlen(gStyles[style].fName),
+                                        0, rect.height() + 12 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gFills[fill].fName,
+                                        strlen(gFills[fill].fName),
+                                        0, rect.height() + 24 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gCaps[cap].fName,
+                                        strlen(gCaps[cap].fName),
+                                        0, rect.height() + 36 * SK_Scalar1,
+                                        labelPaint);
+                }
+                canvas->restore();
+            }
+            canvas->restore();
+        }
+        canvas->restore();
+        canvas->restore();
+    }
+    
+private:
+    typedef GM INHERITED;
+};
+
+class QuadPathGM : public GM {
+public:
+    QuadPathGM() {}
+
+protected:
+    SkString onShortName() {
+        return SkString("quadpath");
+    }
+        
+    SkISize onISize() { return make_isize(1240, 390); }
+    
+    void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
+                  const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
+                  SkPaint::Style style, SkPath::FillType fill,
+                  SkScalar strokeWidth) {
+        path.setFillType(fill);
+        SkPaint paint;
+        paint.setStrokeCap(cap);
+        paint.setStrokeWidth(strokeWidth);
+        paint.setStrokeJoin(join);
+        paint.setColor(color);
+        paint.setStyle(style);
+        canvas->save();
+        canvas->clipRect(clip);
+        canvas->drawPath(path, paint);
+        canvas->restore();
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        struct FillAndName {
+            SkPath::FillType fFill;
+            const char*      fName;
+        };
+        static const FillAndName gFills[] = {
+            {SkPath::kWinding_FillType, "Winding"},
+            {SkPath::kEvenOdd_FillType, "Even / Odd"},
+            {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+            {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+        };
+        struct StyleAndName {
+            SkPaint::Style fStyle;
+            const char*    fName;
+        };
+        static const StyleAndName gStyles[] = {
+            {SkPaint::kFill_Style, "Fill"},
+            {SkPaint::kStroke_Style, "Stroke"},
+            {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+        };
+        struct CapAndName {
+            SkPaint::Cap  fCap;
+            SkPaint::Join fJoin;
+            const char*   fName;
+        };
+        static const CapAndName gCaps[] = {
+            {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
+            {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
+            {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
+        };
+        struct PathAndName {
+            SkPath      fPath;
+            const char* fName;
+        };
+        PathAndName path;
+        path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
+        path.fPath.quadTo(50*SK_Scalar1, 20*SK_Scalar1,
+                          75*SK_Scalar1, 10*SK_Scalar1);
+        path.fName = "moveTo-quad";
+
+        SkPaint titlePaint;
+        titlePaint.setColor(SK_ColorBLACK);
+        titlePaint.setAntiAlias(true);
+        titlePaint.setLCDRenderText(true);
+        titlePaint.setTextSize(15 * SK_Scalar1);
+        const char title[] = "Quad Drawn Into Rectangle Clips With "
+                             "Indicated Style, Fill and Linecaps, with stroke width 10";
+        canvas->drawText(title, strlen(title),
+                            20 * SK_Scalar1,
+                            20 * SK_Scalar1,
+                            titlePaint);
+
+        SkRandom rand;
+        SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
+        canvas->save();
+        canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
+        canvas->save();
+        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+            if (0 < cap) {
+                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
+            }
+            canvas->save();
+            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+                if (0 < fill) {
+                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
+                }
+                canvas->save();
+                for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+                    if (0 < style) {
+                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
+                    }
+        
+                    SkColor color = 0xff007000;
+                    this->drawPath(path.fPath, canvas, color, rect,
+                                    gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
+                                    gFills[fill].fFill, SK_Scalar1*10);
+        
+                    SkPaint rectPaint;
+                    rectPaint.setColor(SK_ColorBLACK);
+                    rectPaint.setStyle(SkPaint::kStroke_Style);
+                    rectPaint.setStrokeWidth(-1);
+                    rectPaint.setAntiAlias(true);
+                    canvas->drawRect(rect, rectPaint);
+        
+                    SkPaint labelPaint;
+                    labelPaint.setColor(color);
+                    labelPaint.setAntiAlias(true);
+                    labelPaint.setLCDRenderText(true);
+                    labelPaint.setTextSize(10 * SK_Scalar1);
+                    canvas->drawText(gStyles[style].fName,
+                                        strlen(gStyles[style].fName),
+                                        0, rect.height() + 12 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gFills[fill].fName,
+                                        strlen(gFills[fill].fName),
+                                        0, rect.height() + 24 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gCaps[cap].fName,
+                                        strlen(gCaps[cap].fName),
+                                        0, rect.height() + 36 * SK_Scalar1,
+                                        labelPaint);
+                }
+                canvas->restore();
+            }
+            canvas->restore();
+        }
+        canvas->restore();
+        canvas->restore();
+    }
+    
+private:
+    typedef GM INHERITED;
+};
+
+class QuadClosePathGM : public GM {
+public:
+    QuadClosePathGM() {}
+
+protected:
+    SkString onShortName() {
+        return SkString("quadclosepath");
+    }
+        
+    SkISize onISize() { return make_isize(1240, 390); }
+    
+    void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
+                  const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
+                  SkPaint::Style style, SkPath::FillType fill,
+                  SkScalar strokeWidth) {
+        path.setFillType(fill);
+        SkPaint paint;
+        paint.setStrokeCap(cap);
+        paint.setStrokeWidth(strokeWidth);
+        paint.setStrokeJoin(join);
+        paint.setColor(color);
+        paint.setStyle(style);
+        canvas->save();
+        canvas->clipRect(clip);
+        canvas->drawPath(path, paint);
+        canvas->restore();
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        struct FillAndName {
+            SkPath::FillType fFill;
+            const char*      fName;
+        };
+        static const FillAndName gFills[] = {
+            {SkPath::kWinding_FillType, "Winding"},
+            {SkPath::kEvenOdd_FillType, "Even / Odd"},
+            {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+            {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+        };
+        struct StyleAndName {
+            SkPaint::Style fStyle;
+            const char*    fName;
+        };
+        static const StyleAndName gStyles[] = {
+            {SkPaint::kFill_Style, "Fill"},
+            {SkPaint::kStroke_Style, "Stroke"},
+            {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+        };
+        struct CapAndName {
+            SkPaint::Cap  fCap;
+            SkPaint::Join fJoin;
+            const char*   fName;
+        };
+        static const CapAndName gCaps[] = {
+            {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
+            {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
+            {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
+        };
+        struct PathAndName {
+            SkPath      fPath;
+            const char* fName;
+        };
+        PathAndName path;
+        path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
+        path.fPath.quadTo(50*SK_Scalar1, 20*SK_Scalar1,
+                          75*SK_Scalar1, 10*SK_Scalar1);
+        path.fPath.close();
+        path.fName = "moveTo-quad-close";
+
+        SkPaint titlePaint;
+        titlePaint.setColor(SK_ColorBLACK);
+        titlePaint.setAntiAlias(true);
+        titlePaint.setLCDRenderText(true);
+        titlePaint.setTextSize(15 * SK_Scalar1);
+        const char title[] = "Quad Closed Drawn Into Rectangle Clips With "
+                             "Indicated Style, Fill and Linecaps, with stroke width 10";
+        canvas->drawText(title, strlen(title),
+                            20 * SK_Scalar1,
+                            20 * SK_Scalar1,
+                            titlePaint);
+
+        SkRandom rand;
+        SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
+        canvas->save();
+        canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
+        canvas->save();
+        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+            if (0 < cap) {
+                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
+            }
+            canvas->save();
+            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+                if (0 < fill) {
+                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
+                }
+                canvas->save();
+                for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+                    if (0 < style) {
+                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
+                    }
+        
+                    SkColor color = 0xff007000;
+                    this->drawPath(path.fPath, canvas, color, rect,
+                                    gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
+                                    gFills[fill].fFill, SK_Scalar1*10);
+        
+                    SkPaint rectPaint;
+                    rectPaint.setColor(SK_ColorBLACK);
+                    rectPaint.setStyle(SkPaint::kStroke_Style);
+                    rectPaint.setStrokeWidth(-1);
+                    rectPaint.setAntiAlias(true);
+                    canvas->drawRect(rect, rectPaint);
+        
+                    SkPaint labelPaint;
+                    labelPaint.setColor(color);
+                    labelPaint.setAntiAlias(true);
+                    labelPaint.setLCDRenderText(true);
+                    labelPaint.setTextSize(10 * SK_Scalar1);
+                    canvas->drawText(gStyles[style].fName,
+                                        strlen(gStyles[style].fName),
+                                        0, rect.height() + 12 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gFills[fill].fName,
+                                        strlen(gFills[fill].fName),
+                                        0, rect.height() + 24 * SK_Scalar1,
+                                        labelPaint);
+                    canvas->drawText(gCaps[cap].fName,
+                                        strlen(gCaps[cap].fName),
+                                        0, rect.height() + 36 * SK_Scalar1,
+                                        labelPaint);
                 }
                 canvas->restore();
             }
@@ -179,7 +583,16 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
-static GM* MyFactory(void*) { return new QuadPathsGM; }
-static GMRegistry reg(MyFactory);
+static GM* ZeroQuadPathFactory(void*) { return new ZeroQuadPathGM; }
+static GMRegistry regZeroQuadPath(ZeroQuadPathFactory);
 
-}
+static GM* ZeroQuadClosePathFactory(void*) { return new ZeroQuadClosePathGM; }
+static GMRegistry regZeroQuadClosePath(ZeroQuadClosePathFactory);
+
+static GM* QuadPathFactory(void*) { return new QuadPathGM; }
+static GMRegistry regQuadPath(QuadPathFactory);
+
+static GM* QuadClosePathFactory(void*) { return new QuadClosePathGM; }
+static GMRegistry regQuadClosePath(QuadClosePathFactory);
+
+}
\ No newline at end of file