[PDF] Add support for xfermodes / blend modes.

- Change SkGraphicState to track and set the blend mode (xfermode) for modes built in to PDF (non porter duff modes + src over).
- Add SkXfermode::asMode() to retrieve xfermode as an enum for non porter duff modes.
- Move SkXfermode.cpp around a bit to support asMode() -- Generally move utility functions toward the top of the file.
- Make SkPDFFormXObject an isolated transparency group, as it used for saveLayer, which draws on transparent, not the device background.
- Set the graphic state in drawDevice and drawBitmap in order to get the right xfermode and alpha.

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

git-svn-id: http://skia.googlecode.com/svn/trunk@774 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/pdf/SkPDFGraphicState.cpp b/src/pdf/SkPDFGraphicState.cpp
index ff55941..44419ec 100644
--- a/src/pdf/SkPDFGraphicState.cpp
+++ b/src/pdf/SkPDFGraphicState.cpp
@@ -16,6 +16,44 @@
 
 #include "SkPDFGraphicState.h"
 #include "SkStream.h"
+#include "SkTypes.h"
+
+namespace {
+
+const char* blendModeFromXfermode(SkXfermode::Mode mode) {
+    switch (mode) {
+        case SkXfermode::kSrcOver_Mode:    return "Normal";
+        case SkXfermode::kMultiply_Mode:   return "Multiply";
+        case SkXfermode::kScreen_Mode:     return "Screen";
+        case SkXfermode::kOverlay_Mode:    return "Overlay";
+        case SkXfermode::kDarken_Mode:     return "Darken";
+        case SkXfermode::kLighten_Mode:    return "Lighten";
+        case SkXfermode::kColorDodge_Mode: return "ColorDodge";
+        case SkXfermode::kColorBurn_Mode:  return "ColorBurn";
+        case SkXfermode::kHardLight_Mode:  return "HardLight";
+        case SkXfermode::kSoftLight_Mode:  return "SoftLight";
+        case SkXfermode::kDifference_Mode: return "Difference";
+        case SkXfermode::kExclusion_Mode:  return "Exclusion";
+
+        // TODO(vandebo) Figure out if we can support more of these modes.
+        case SkXfermode::kClear_Mode:
+        case SkXfermode::kSrc_Mode:
+        case SkXfermode::kDst_Mode:
+        case SkXfermode::kDstOver_Mode:
+        case SkXfermode::kSrcIn_Mode:
+        case SkXfermode::kDstIn_Mode:
+        case SkXfermode::kSrcOut_Mode:
+        case SkXfermode::kDstOut_Mode:
+        case SkXfermode::kSrcATop_Mode:
+        case SkXfermode::kDstATop_Mode:
+        case SkXfermode::kXor_Mode:
+        case SkXfermode::kPlus_Mode:
+            return NULL;
+    }
+    return NULL;
+}
+
+}
 
 SkPDFGraphicState::~SkPDFGraphicState() {
     SkAutoMutexAcquire lock(canonicalPaintsMutex());
@@ -30,6 +68,7 @@
     SkPDFDict::emitObject(stream, catalog, indirect);
 }
 
+// static
 size_t SkPDFGraphicState::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
     populateDict();
     return SkPDFDict::getOutputSize(catalog, indirect);
@@ -104,6 +143,18 @@
         insert("LW", new SkPDFScalar(fPaint.getStrokeWidth()))->unref();
         insert("ML", new SkPDFScalar(fPaint.getStrokeMiter()))->unref();
         insert("SA", new SkPDFBool(true))->unref();  // Auto stroke adjustment.
+
+        SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode;
+        // If asMode fails return false, default to kSrcOver_Mode.
+        if (fPaint.getXfermode())
+            fPaint.getXfermode()->asMode(&xfermode);
+        // If we don't support the mode, just use kSrcOver_Mode.
+        if (xfermode < 0 || xfermode > SkXfermode::kLastMode ||
+                blendModeFromXfermode(xfermode) == NULL) {
+            fprintf(stderr, "NOT_IMPLEMENTED: xfermode = %d\n", xfermode);
+            xfermode = SkXfermode::kSrcOver_Mode;
+        }
+        insert("BM", new SkPDFName(blendModeFromXfermode(xfermode)))->unref();
     }
 }
 
@@ -115,9 +166,29 @@
     const SkPaint* b = gs.fPaint;
     SkASSERT(a != NULL);
     SkASSERT(b != NULL);
-    return SkColorGetA(a->getColor()) == SkColorGetA(b->getColor()) &&
-           a->getStrokeCap() == b->getStrokeCap() &&
-           a->getStrokeJoin() == b->getStrokeJoin() &&
-           a->getStrokeWidth() == b->getStrokeWidth() &&
-           a->getStrokeMiter() == b->getStrokeMiter();
+
+    if (SkColorGetA(a->getColor()) != SkColorGetA(b->getColor()) ||
+           a->getStrokeCap() != b->getStrokeCap() ||
+           a->getStrokeJoin() != b->getStrokeJoin() ||
+           a->getStrokeWidth() != b->getStrokeWidth() ||
+           a->getStrokeMiter() != b->getStrokeMiter()) {
+        return false;
+    }
+
+    SkXfermode* aXfermode = a->getXfermode();
+    SkXfermode::Mode aXfermodeName = SkXfermode::kSrcOver_Mode;
+    bool aXfermodeKnown = true;
+    if (aXfermode)
+        aXfermodeKnown = aXfermode->asMode(&aXfermodeName);
+    SkXfermode* bXfermode = b->getXfermode();
+    SkXfermode::Mode bXfermodeName = SkXfermode::kSrcOver_Mode;
+    bool bXfermodeKnown = true;
+    if (bXfermode)
+        bXfermodeKnown = bXfermode->asMode(&bXfermodeName);
+
+    if (aXfermodeKnown != bXfermodeKnown)
+        return false;
+    if (!aXfermodeKnown)
+       return aXfermode == bXfermode;
+    return aXfermodeName == bXfermodeName;
 }