pdfviewer: more plumming for soft masks, blend modes and transparency groups

Review URL: https://codereview.chromium.org/21125002

git-svn-id: http://skia.googlecode.com/svn/trunk@10419 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/experimental/PdfViewer/SkPdfRenderer.cpp b/experimental/PdfViewer/SkPdfRenderer.cpp
index e7bfdb6..e2805c7 100644
--- a/experimental/PdfViewer/SkPdfRenderer.cpp
+++ b/experimental/PdfViewer/SkPdfRenderer.cpp
@@ -668,6 +668,11 @@
     // TODO(edisonn): iterate smart on the stream even if it is compressed, tokenize it as we go.
     // For this PdfContentsTokenizer needs to be extended.
 
+    // This is a group?
+    if (skobj->has_Group()) {
+        //TransparencyGroupDictionary* ...
+    }
+
     SkPdfStream* stream = (SkPdfStream*)skobj;
 
     SkPdfNativeTokenizer* tokenizer =
@@ -1582,20 +1587,112 @@
     skpdfGraphicsStateApplyFontCore(pdfContext, fontAndSize->objAtAIndex(0), fontAndSize->objAtAIndex(1)->numberValue());
 }
 
+SkTDict<SkXfermode::Mode> gPdfBlendModes(20);
+
+class InitBlendModes {
+public:
+    InitBlendModes() {
+        // TODO(edisonn): use the python code generator?
+        // TABLE 7.2 Standard separable blend modes
+        gPdfBlendModes.set("Normal", SkXfermode::kSrc_Mode);
+        gPdfBlendModes.set("Multiply", SkXfermode::kMultiply_Mode);
+        gPdfBlendModes.set("Screen", SkXfermode::kScreen_Mode);
+        gPdfBlendModes.set("Overlay", SkXfermode::kOverlay_Mode);
+        gPdfBlendModes.set("Darken", SkXfermode::kDarken_Mode);
+        gPdfBlendModes.set("Lighten", SkXfermode::kLighten_Mode);
+        gPdfBlendModes.set("ColorDodge", SkXfermode::kColorDodge_Mode);
+        gPdfBlendModes.set("ColorBurn", SkXfermode::kColorBurn_Mode);
+        gPdfBlendModes.set("HardLight", SkXfermode::kHardLight_Mode);
+        gPdfBlendModes.set("SoftLight", SkXfermode::kSoftLight_Mode);
+        gPdfBlendModes.set("Difference", SkXfermode::kDifference_Mode);
+        gPdfBlendModes.set("Exclusion", SkXfermode::kExclusion_Mode);
+
+        // TABLE 7.3 Standard nonseparable blend modes
+        gPdfBlendModes.set("Hue", SkXfermode::kHue_Mode);
+        gPdfBlendModes.set("Saturation", SkXfermode::kSaturation_Mode);
+        gPdfBlendModes.set("Color", SkXfermode::kColor_Mode);
+        gPdfBlendModes.set("Luminosity", SkXfermode::kLuminosity_Mode);
+    }
+};
+
+InitBlendModes _gDummyInniter;
+
+SkXfermode::Mode xferModeFromBlendMode(const char* blendMode, size_t len) {
+    SkXfermode::Mode mode = (SkXfermode::Mode)(SkXfermode::kLastMode + 1);
+    if (gPdfBlendModes.find(blendMode, len, &mode)) {
+        return mode;
+    }
+
+    return (SkXfermode::Mode)(SkXfermode::kLastMode + 1);
+}
+
 void skpdfGraphicsStateApplyBM_name(PdfContext* pdfContext, const std::string& blendMode) {
-    // TODO(edisonn): verify input
+    SkXfermode::Mode mode = xferModeFromBlendMode(blendMode.c_str(), blendMode.length());
+    if (mode <= SkXfermode::kLastMode) {
+        pdfContext->fGraphicsState.fBlendModesLength = 1;
+        pdfContext->fGraphicsState.fBlendModes[0] = mode;
+    } else {
+        // TODO(edisonn): report unknown blend mode
+    }
 }
 
 void skpdfGraphicsStateApplyBM_array(PdfContext* pdfContext, SkPdfArray* blendModes) {
-    // TODO(edisonn): verify input
-}
+    if (!blendModes || blendModes->isArray() || blendModes->size() == 0 || blendModes->size() > 256) {
+        // TODO(edisonn): report error/warning
+        return;
+    }
+    SkXfermode::Mode modes[256];
+    int cnt = blendModes->size();
+    for (int i = 0; i < cnt; i++) {
+        SkPdfObject* name = blendModes->objAtAIndex(i);
+        if (!name->isName()) {
+            // TODO(edisonn): report error/warning
+            return;
+        }
+        SkXfermode::Mode mode = xferModeFromBlendMode(name->c_str(), name->lenstr());
+        if (mode > SkXfermode::kLastMode) {
+            // TODO(edisonn): report error/warning
+            return;
+        }
+    }
 
-void skpdfGraphicsStateApplySMask_name(PdfContext* pdfContext, const std::string& sMask) {
-    // TODO(edisonn): verify input
+    pdfContext->fGraphicsState.fBlendModesLength = cnt;
+    for (int i = 0; i < cnt; i++) {
+        pdfContext->fGraphicsState.fBlendModes[i] = modes[i];
+    }
 }
 
 void skpdfGraphicsStateApplySMask_dict(PdfContext* pdfContext, SkPdfDictionary* sMask) {
     // TODO(edisonn): verify input
+    if (pdfContext->fPdfDoc->mapper()->mapSoftMaskDictionary(sMask)) {
+        //SkPdfSoftMaskDictionary* smd = (SkPdfSoftMaskDictionary*)sMask;
+        // TODO(edisonn): load soft mask
+    } else if (pdfContext->fPdfDoc->mapper()->mapSoftMaskImageDictionary(sMask)) {
+        SkPdfSoftMaskImageDictionary* smid = (SkPdfSoftMaskImageDictionary*)sMask;
+        pdfContext->fGraphicsState.fSMask = getImageFromObject(pdfContext, smid, true);
+    } else {
+        // TODO (edisonn): report error/warning
+    }
+}
+
+void skpdfGraphicsStateApplySMask_name(PdfContext* pdfContext, const std::string& sMask) {
+    //Next, get the ExtGState Dictionary from the Resource Dictionary:
+    SkPdfDictionary* extGStateDictionary = pdfContext->fGraphicsState.fResources->ExtGState(pdfContext->fPdfDoc);
+
+    if (extGStateDictionary == NULL) {
+#ifdef PDF_TRACE
+        printf("ExtGState is NULL!\n");
+#endif
+        // TODO (edisonn): report error/warning
+        return;
+    }
+
+    SkPdfObject* obj = pdfContext->fPdfDoc->resolveReference(extGStateDictionary->get(sMask.c_str()));
+    if (!obj || !obj->isDictionary()) {
+        // TODO (edisonn): report error/warning
+        return;
+    }
+    skpdfGraphicsStateApplySMask_dict(pdfContext, obj->asDictionary());
 }
 
 void skpdfGraphicsStateApplyAIS(PdfContext* pdfContext, bool alphaSource) {