};
inline unsigned int ToUnicode(unsigned int ch) const {
- if (fToUnicode) {
+ if (fToUnicode && fToUnicode->fCMapEncoding) {
return fToUnicode->fCMapEncoding[ch];
} else {
return ch;
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;
}
}
- 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);
fCount = 0;
}
++fTotalCount;
+ ++fLocalCount;
return &fRec->fSlots[fCount++];
}
void pop() {
SkASSERT(fCount > 0 && fRec);
+ --fLocalCount;
--fTotalCount;
if (--fCount == 0) {
if (fRec != &fInitialRec) {
};
Rec fInitialRec;
Rec* fRec;
- int fCount, fTotalCount;
+ int fCount, fTotalCount, fLocalCount;
+ int fNestings[MAX_NESTING];
+ int fNestingLevel;
};
// TODO(edisonn): better class design.
// 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;
}
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();
fObjects[id].fOffset = offset;
fObjects[id].fObj = NULL;
fObjects[id].fResolvedReference = NULL;
+ fObjects[id].fIsReferenceResolved = false;
}
SkPdfNativeObject* SkPdfNativeDoc::readObject(int id/*, int expectedGeneration*/) {
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);
}
SkPdfNativeObject* fObj;
// TODO(edisonn): perf ... probably it does not make sense to cache the ref. test it!
SkPdfNativeObject* fResolvedReference;
+ bool fIsReferenceResolved;
};
public:
obj->fObj = NULL;
obj->fResolvedReference = NULL;
obj->fOffset = -1;
+ obj->fIsReferenceResolved = false;
}
SkPdfNativeObject* readObject(int id/*, int generation*/);