pdfviewer: when q start, and an operator is called, it should not be able to see...
authoredisonn@google.com <edisonn@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 22 Aug 2013 15:37:21 +0000 (15:37 +0000)
committeredisonn@google.com <edisonn@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 22 Aug 2013 15:37:21 +0000 (15:37 +0000)
Review URL: https://codereview.chromium.org/23033022

git-svn-id: http://skia.googlecode.com/svn/trunk@10873 2bbb7eff-a529-9590-31e7-b0007b416f81

experimental/PdfViewer/SkPdfFont.h
experimental/PdfViewer/SkPdfGraphicsState.h
experimental/PdfViewer/SkPdfRenderer.cpp
experimental/PdfViewer/pdfparser/native/SkPdfNativeDoc.cpp
experimental/PdfViewer/pdfparser/native/SkPdfNativeDoc.h

index 09e01ac..51e0329 100644 (file)
@@ -211,7 +211,7 @@ public:
     };
 
     inline unsigned int ToUnicode(unsigned int ch) const {
-        if (fToUnicode) {
+        if (fToUnicode && fToUnicode->fCMapEncoding) {
             return fToUnicode->fCMapEncoding[ch];
         } else {
             return ch;
index 0928f44..abda00f 100644 (file)
@@ -24,14 +24,18 @@ class SkPdfSoftMaskDictionary;
 class SkPdfNativeDoc;
 class SkPdfAllocator;
 
-// TODO(edisonn): move this class in iclude/core?
+// TODO(edisonn): move this class in include/core?
 // Ref objects can't be dealt unless we use a specific class initialization
 // The difference between SkTDStackNew and SkTDStack is that SkTDStackNew uses new/delete
 // to be a manage c++ stuff (like initializations)
+
+// Adobe limits it to 28, so 256 should be more than enough
+#define MAX_NESTING 256
+
 #include "SkTypes.h"
 template <typename T> class SkTDStackNew : SkNoncopyable {
 public:
-    SkTDStackNew() : fCount(0), fTotalCount(0) {
+    SkTDStackNew() : fCount(0), fTotalCount(0), fLocalCount(0) {
         fInitialRec.fNext = NULL;
         fRec = &fInitialRec;
 
@@ -47,9 +51,36 @@ public:
         }
     }
 
-    int count() const { return fTotalCount; }
-    int depth() const { return fTotalCount; }
-    bool empty() const { return fTotalCount == 0; }
+    int count() const { return fLocalCount; }
+    int depth() const { return fLocalCount; }
+    bool empty() const { return fLocalCount == 0; }
+
+    bool nests() {
+        return fNestingLevel;
+    }
+
+    void nest() {
+        // We are are past max nesting levels, we will still continue to work, but we might fail
+        // to properly ignore errors. Ideally it should only mean poor rendering in exceptional
+        // cases
+        if (fNestingLevel >= 0 && fNestingLevel < MAX_NESTING) {
+            fNestings[fNestingLevel] = fLocalCount;
+            fLocalCount = 0;
+        }
+        fNestingLevel++;
+    }
+
+    void unnest() {
+        SkASSERT(fNestingLevel > 0);
+        fNestingLevel--;
+        if (fNestingLevel >= 0 && fNestingLevel < MAX_NESTING) {
+            // TODO(edisonn): warn if fLocal > 0
+            while (fLocalCount > 0) {
+                pop();
+            }
+            fLocalCount = fNestings[fNestingLevel];
+        }
+    }
 
     T* push() {
         SkASSERT(fCount <= kSlotCount);
@@ -60,6 +91,7 @@ public:
             fCount = 0;
         }
         ++fTotalCount;
+        ++fLocalCount;
         return &fRec->fSlots[fCount++];
     }
 
@@ -94,6 +126,7 @@ public:
 
     void pop() {
         SkASSERT(fCount > 0 && fRec);
+        --fLocalCount;
         --fTotalCount;
         if (--fCount == 0) {
             if (fRec != &fInitialRec) {
@@ -121,7 +154,9 @@ private:
     };
     Rec     fInitialRec;
     Rec*    fRec;
-    int     fCount, fTotalCount;
+    int     fCount, fTotalCount, fLocalCount;
+    int     fNestings[MAX_NESTING];
+    int     fNestingLevel;
 };
 
 // TODO(edisonn): better class design.
index e7be1d8..21e4287 100644 (file)
@@ -1085,13 +1085,25 @@ SkPdfResult PdfOp_q(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper**
     // it is not possible to see under the previous q?
     pdfContext->fStateStack.push(pdfContext->fGraphicsState);
     canvas->save();
+    pdfContext->fObjectStack.nest();
     return kOK_SkPdfResult;
 }
 
 SkPdfResult PdfOp_Q(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) {
-    pdfContext->fGraphicsState = pdfContext->fStateStack.top();
-    pdfContext->fStateStack.pop();
-    canvas->restore();
+    if (pdfContext->fStateStack.count() > 0) {
+        pdfContext->fGraphicsState = pdfContext->fStateStack.top();
+        pdfContext->fStateStack.pop();
+        canvas->restore();
+
+        if (pdfContext->fObjectStack.nests() <= 0) {
+            return kIgnoreError_SkPdfResult;
+        } else {
+            pdfContext->fObjectStack.unnest();
+        }
+    } else {
+        return kIgnoreError_SkPdfResult;
+    }
+
     return kOK_SkPdfResult;
 }
 
@@ -2775,6 +2787,10 @@ bool SkPdfRenderer::renderPage(int page, SkCanvas* canvas, const SkRect& dst) co
     SkScalar w = dst.width();
     SkScalar h = dst.height();
 
+    if (SkScalarTruncToInt(w) <= 0 || SkScalarTruncToInt(h) <= 0) {
+        return true;
+    }
+
     SkScalar wp = fPdfDoc->MediaBox(page).width();
     SkScalar hp = fPdfDoc->MediaBox(page).height();
 
index c32d5ff..ebc27ad 100644 (file)
@@ -358,6 +358,7 @@ void SkPdfNativeDoc::addCrossSectionInfo(int id, int generation, int offset, boo
     fObjects[id].fOffset = offset;
     fObjects[id].fObj = NULL;
     fObjects[id].fResolvedReference = NULL;
+    fObjects[id].fIsReferenceResolved = false;
 }
 
 SkPdfNativeObject* SkPdfNativeDoc::readObject(int id/*, int expectedGeneration*/) {
@@ -546,15 +547,22 @@ SkPdfNativeObject* SkPdfNativeDoc::resolveReference(SkPdfNativeObject* ref) {
             return NULL;
         }
 
-        if (fObjects[id].fResolvedReference != NULL) {
+        if (fObjects[id].fIsReferenceResolved) {
 
 #ifdef PDF_TRACE
             printf("\nresolve(%s) = %s\n", ref->toString(0).c_str(), fObjects[id].fResolvedReference->toString(0, ref->toString().size() + 13).c_str());
 #endif
 
+            // TODO(edisonn): for known good documents, assert here THAT THE REFERENCE IS NOT null
             return fObjects[id].fResolvedReference;
         }
 
+        // TODO(edisonn): there are pdfs in the crashing suite that cause a stack overflow here unless we check for resolved reference on next line
+        // determine if the pdf is corrupted, or we have a bug here
+
+        // avoids recursive calls
+        fObjects[id].fIsReferenceResolved = true;
+
         if (fObjects[id].fObj == NULL) {
             fObjects[id].fObj = readObject(id);
         }
index ae89e8f..411343b 100644 (file)
@@ -36,6 +36,7 @@ private:
         SkPdfNativeObject* fObj;
         // TODO(edisonn): perf ... probably it does not make sense to cache the ref. test it!
         SkPdfNativeObject* fResolvedReference;
+        bool fIsReferenceResolved;
     };
 
 public:
@@ -91,6 +92,7 @@ private:
         obj->fObj = NULL;
         obj->fResolvedReference = NULL;
         obj->fOffset = -1;
+        obj->fIsReferenceResolved = false;
     }
 
     SkPdfNativeObject* readObject(int id/*, int generation*/);