[PDF] Fixes the cases where SkPDFDevice::finishContentEntry is called with empty content.

There are some cases (like drawing a completely transparent image) where the code tries to finish a content entry with no content and an xfermode other than clear.  This makes those cases work correctly.

This is likely what was happening in chromium:316546, but it wasn't clear what the core problem was. desk_techcrunch.skp tripped a debug only assert that exposed the core issue.

BUG=skia:1868,chromium:316546
R=reed@google.com, bungeman@google.com

Author: vandebo@chromium.org

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

git-svn-id: http://skia.googlecode.com/svn/trunk@12473 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index bdabc53..cdfec33 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -1875,11 +1875,12 @@
     return entry;
 }
 
-void SkPDFDevice::finishContentEntry(const SkXfermode::Mode xfermode,
+void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode,
                                      SkPDFFormXObject* dst,
                                      SkPath* shape) {
     if (xfermode != SkXfermode::kClear_Mode       &&
             xfermode != SkXfermode::kSrc_Mode     &&
+            xfermode != SkXfermode::kDstOver_Mode &&
             xfermode != SkXfermode::kSrcIn_Mode   &&
             xfermode != SkXfermode::kDstIn_Mode   &&
             xfermode != SkXfermode::kSrcOut_Mode  &&
@@ -1890,6 +1891,18 @@
         SkASSERT(!dst);
         return;
     }
+    if (xfermode == SkXfermode::kDstOver_Mode) {
+        SkASSERT(!dst);
+        ContentEntry* firstContentEntry = getContentEntries()->get();
+        if (firstContentEntry->fContent.getOffset() == 0) {
+            // For DstOver, an empty content entry was inserted before the rest
+            // of the content entries. If nothing was drawn, it needs to be
+            // removed.
+            SkAutoTDelete<ContentEntry>* contentEntries = getContentEntries();
+            contentEntries->reset(firstContentEntry->fNext.detach());
+        }
+        return;
+    }
     if (!dst) {
         SkASSERT(xfermode == SkXfermode::kSrc_Mode ||
                  xfermode == SkXfermode::kSrcOut_Mode);
@@ -1904,17 +1917,32 @@
     SkClipStack clipStack = contentEntries->fState.fClipStack;
     SkRegion clipRegion = contentEntries->fState.fClipRegion;
 
+    SkMatrix identity;
+    identity.reset();
+    SkPaint stockPaint;
+
     SkAutoTUnref<SkPDFFormXObject> srcFormXObject;
     if (isContentEmpty()) {
-        SkASSERT(xfermode == SkXfermode::kClear_Mode);
+        // If nothing was drawn and there's no shape, then the draw was a
+        // no-op, but dst needs to be restored for that to be true.
+        // If there is shape, then an empty source with Src, SrcIn, SrcOut,
+        // DstIn, DstAtop or Modulate reduces to Clear and DstOut or SrcAtop
+        // reduces to Dst.
+        if (shape == NULL || xfermode == SkXfermode::kDstOut_Mode ||
+                xfermode == SkXfermode::kSrcATop_Mode) {
+            ScopedContentEntry content(this, &clipStack, clipRegion, identity,
+                                       stockPaint);
+            SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst),
+                                        &content.entry()->fContent);
+            return;
+        } else {
+            xfermode = SkXfermode::kClear_Mode;
+        }
     } else {
         SkASSERT(!fContentEntries->fNext.get());
         srcFormXObject.reset(createFormXObjectFromDevice());
     }
 
-    SkMatrix identity;
-    identity.reset();
-
     // TODO(vandebo) srcFormXObject may contain alpha, but here we want it
     // without alpha.
     if (xfermode == SkXfermode::kSrcATop_Mode) {
@@ -1946,16 +1974,7 @@
                                 clipRegion, SkXfermode::kSrcOver_Mode, true);
     }
 
-    SkPaint stockPaint;
-
-    if (xfermode == SkXfermode::kSrcATop_Mode) {
-        ScopedContentEntry content(this, &clipStack, clipRegion, identity,
-                                   stockPaint);
-        if (content.entry()) {
-            SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst),
-                                        &content.entry()->fContent);
-        }
-    } else if (xfermode == SkXfermode::kClear_Mode || !srcFormXObject.get()) {
+    if (xfermode == SkXfermode::kClear_Mode) {
         return;
     } else if (xfermode == SkXfermode::kSrc_Mode ||
             xfermode == SkXfermode::kDstATop_Mode) {
@@ -1969,6 +1988,13 @@
         if (xfermode == SkXfermode::kSrc_Mode) {
             return;
         }
+    } else if (xfermode == SkXfermode::kSrcATop_Mode) {
+        ScopedContentEntry content(this, &clipStack, clipRegion, identity,
+                                   stockPaint);
+        if (content.entry()) {
+            SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst),
+                                        &content.entry()->fContent);
+        }
     }
 
     SkASSERT(xfermode == SkXfermode::kSrcIn_Mode   ||