Add additional source types to xfer mode test.

Review URL: http://codereview.appspot.com/4589051

git-svn-id: http://skia.googlecode.com/svn/trunk@1705 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/xfermodes.cpp b/gm/xfermodes.cpp
index b8565a3..e36f54e 100644
--- a/gm/xfermodes.cpp
+++ b/gm/xfermodes.cpp
@@ -37,14 +37,70 @@
     SkBitmap    fBG;
     SkBitmap    fSrcB, fDstB;
 
-    void draw_mode(SkCanvas* canvas, SkXfermode* mode, int alpha,
+    /* The sourceType argument indicates what to draw for the source part. Skia
+     * uses the implied shape of the drawing command and these modes
+     * demonstrate that.
+     *
+     * 0x01: A WxH image with a rectangle in the lower right.
+     * 0x02: Same as 0x01, but with an alpha of 34.5%.
+     * 0x04: Same as 0x02, but scaled down by half.
+     * 0x08: The same rectangle as 0x01, but drawn directly instead in an image.
+     * 0x10: Two rectangles, first on the right half, second on the bottom half.
+     * 0x20: Same as 0x10, but on a layer.
+     */
+    void draw_mode(SkCanvas* canvas, SkXfermode* mode, int sourceType,
                    SkScalar x, SkScalar y) {
         SkPaint p;
+        SkMatrix m;
+        bool restoreNeeded = false;
+        m.setTranslate(x, y);
 
-        canvas->drawBitmap(fSrcB, x, y, &p);
-        p.setAlpha(alpha);
+        canvas->drawBitmapMatrix(fSrcB, m, &p);
         p.setXfermode(mode);
-        canvas->drawBitmap(fDstB, x, y, &p);
+        switch (sourceType) {
+            case 0x20: {
+                SkRect bounds = SkRect::MakeXYWH(x, y, W, H);
+                canvas->saveLayer(&bounds, &p);
+                restoreNeeded = true;
+                p.setXfermodeMode(SkXfermode::kSrcOver_Mode);
+                // Fall through.
+            }
+            case 0x10: {
+                SkScalar halfW = SkIntToScalar(W) / 2;
+                SkScalar halfH = SkIntToScalar(H) / 2;
+                p.setColor(0xFF66AAFF);
+                SkRect r = SkRect::MakeXYWH(x + halfW, y, halfW, H);
+                canvas->drawRect(r, p);
+                p.setColor(0xFFAA66FF);
+                r = SkRect::MakeXYWH(x, y + halfH, W, halfH);
+                canvas->drawRect(r, p);
+                break;
+            }
+            case 0x8: {
+                SkScalar w = SkIntToScalar(W);
+                SkScalar h = SkIntToScalar(H);
+                SkRect r = SkRect::MakeXYWH(x + w / 3, y + h / 3,
+                                            w * 37 / 60, h * 37 / 60);
+                p.setColor(0xFF66AAFF);
+                canvas->drawRect(r, p);
+                break;
+            }
+            case 0x4:
+                m.postScale(SK_ScalarHalf, SK_ScalarHalf, x, y);
+                // Fall through.
+            case 0x2:
+                p.setAlpha(0x88);
+                // Fall through.
+            case 0x1:
+                canvas->drawBitmapMatrix(fDstB, m, &p);
+                break;
+            default:
+                break;
+        }
+
+        if (restoreNeeded) {
+            canvas->restore();
+        }
     }
 
 public:
@@ -68,7 +124,7 @@
     }
 
     virtual SkISize onISize() {
-        return make_isize(790, 640);
+        return make_isize(1590, 640);
     }
 
     void drawBG(SkCanvas* canvas) {
@@ -80,35 +136,42 @@
 
         this->drawBG(canvas);
 
+        const int kMaxSourceType = 0x20;
         const struct {
             SkXfermode::Mode  fMode;
-            const char*         fLabel;
+            const char*       fLabel;
+            int               fSourceTypeMask;  // The source types to use this
+                                                // mode with. See draw_mode for
+                                                // an explanation of each type.
+                                                // PDF has to play some tricks
+                                                // to support the base modes,
+                                                // test those more extensively.
         } gModes[] = {
-            { SkXfermode::kClear_Mode,    "Clear"     },
-            { SkXfermode::kSrc_Mode,      "Src"       },
-            { SkXfermode::kDst_Mode,      "Dst"       },
-            { SkXfermode::kSrcOver_Mode,  "SrcOver"   },
-            { SkXfermode::kDstOver_Mode,  "DstOver"   },
-            { SkXfermode::kSrcIn_Mode,    "SrcIn"     },
-            { SkXfermode::kDstIn_Mode,    "DstIn"     },
-            { SkXfermode::kSrcOut_Mode,   "SrcOut"    },
-            { SkXfermode::kDstOut_Mode,   "DstOut"    },
-            { SkXfermode::kSrcATop_Mode,  "SrcATop"   },
-            { SkXfermode::kDstATop_Mode,  "DstATop"   },
-            { SkXfermode::kXor_Mode,      "Xor"       },
+            { SkXfermode::kClear_Mode,       "Clear",        0x3F  },
+            { SkXfermode::kSrc_Mode,         "Src",          0x3F  },
+            { SkXfermode::kDst_Mode,         "Dst",          0x3F  },
+            { SkXfermode::kSrcOver_Mode,     "SrcOver",      0x3F  },
+            { SkXfermode::kDstOver_Mode,     "DstOver",      0x3F  },
+            { SkXfermode::kSrcIn_Mode,       "SrcIn",        0x3F  },
+            { SkXfermode::kDstIn_Mode,       "DstIn",        0x3F  },
+            { SkXfermode::kSrcOut_Mode,      "SrcOut",       0x3F  },
+            { SkXfermode::kDstOut_Mode,      "DstOut",       0x3F  },
+            { SkXfermode::kSrcATop_Mode,     "SrcATop",      0x3F  },
+            { SkXfermode::kDstATop_Mode,     "DstATop",      0x3F  },
 
-            { SkXfermode::kPlus_Mode,         "Plus"          },
-            { SkXfermode::kMultiply_Mode,     "Multiply"      },
-            { SkXfermode::kScreen_Mode,       "Screen"        },
-            { SkXfermode::kOverlay_Mode,      "Overlay"       },
-            { SkXfermode::kDarken_Mode,       "Darken"        },
-            { SkXfermode::kLighten_Mode,      "Lighten"       },
-            { SkXfermode::kColorDodge_Mode,   "ColorDodge"    },
-            { SkXfermode::kColorBurn_Mode,    "ColorBurn"     },
-            { SkXfermode::kHardLight_Mode,    "HardLight"     },
-            { SkXfermode::kSoftLight_Mode,    "SoftLight"     },
-            { SkXfermode::kDifference_Mode,   "Difference"    },
-            { SkXfermode::kExclusion_Mode,    "Exclusion"     },
+            { SkXfermode::kXor_Mode,          "Xor",         0x03  },
+            { SkXfermode::kPlus_Mode,         "Plus",        0x03  },
+            { SkXfermode::kMultiply_Mode,     "Multiply",    0x3F  },
+            { SkXfermode::kScreen_Mode,       "Screen",      0x03  },
+            { SkXfermode::kOverlay_Mode,      "Overlay",     0x03  },
+            { SkXfermode::kDarken_Mode,       "Darken",      0x03  },
+            { SkXfermode::kLighten_Mode,      "Lighten",     0x03  },
+            { SkXfermode::kColorDodge_Mode,   "ColorDodge",  0x03  },
+            { SkXfermode::kColorBurn_Mode,    "ColorBurn",   0x03  },
+            { SkXfermode::kHardLight_Mode,    "HardLight",   0x03  },
+            { SkXfermode::kSoftLight_Mode,    "SoftLight",   0x03  },
+            { SkXfermode::kDifference_Mode,   "Difference",  0x03  },
+            { SkXfermode::kExclusion_Mode,    "Exclusion",   0x03  },
         };
 
         const SkScalar w = SkIntToScalar(W);
@@ -127,9 +190,13 @@
         const int W = 5;
 
         SkScalar x0 = 0;
-        for (int twice = 0; twice < 2; twice++) {
-            SkScalar x = x0, y = 0;
+        SkScalar y0 = 0;
+        for (int sourceType = 1; sourceType <= kMaxSourceType; sourceType *=2) {
+            SkScalar x = x0, y = y0;
             for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) {
+                if ((gModes[i].fSourceTypeMask & sourceType) == 0) {
+                    continue;
+                }
                 SkXfermode* mode = SkXfermode::Create(gModes[i].fMode);
                 SkAutoUnref aur(mode);
                 SkRect r;
@@ -141,7 +208,7 @@
                 canvas->drawRect(r, p);
 
                 canvas->saveLayer(&r, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
-                draw_mode(canvas, mode, twice ? 0x88 : 0xFF, r.fLeft, r.fTop);
+                draw_mode(canvas, mode, sourceType, r.fLeft, r.fTop);
                 canvas->restore();
 
                 r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
@@ -159,7 +226,15 @@
                     y += h + SkIntToScalar(30);
                 }
             }
-            x0 += SkIntToScalar(400);
+            if (y < 320) {
+                if (x > x0) {
+                    y += h + SkIntToScalar(30);
+                }
+                y0 = y;
+            } else {
+                x0 += SkIntToScalar(400);
+                y0 = 0;
+            }
         }
         s->unref();
     }