diff options
author | edisonn@google.com <edisonn@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-09-13 19:33:42 +0000 |
---|---|---|
committer | edisonn@google.com <edisonn@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-09-13 19:33:42 +0000 |
commit | af54a513a5b7723b53f61730afe0ad6256881749 (patch) | |
tree | 1da9eecfbdbbf951076e219629cc61f3160e1e3d /experimental/PdfViewer | |
parent | 1fb04e25405d5ec75aea4a099819d6feca348ff6 (diff) |
pdfviewer: do not submit, uploaded for backup, and will be done actually after I refactor the params for functions, to put the char* params in a structure: report errors and warnings in pdf, infrastructure
Review URL: https://codereview.chromium.org/23902018
git-svn-id: http://skia.googlecode.com/svn/trunk@11262 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'experimental/PdfViewer')
-rw-r--r-- | experimental/PdfViewer/SkPdfConfig.h | 33 | ||||
-rw-r--r-- | experimental/PdfViewer/SkPdfRenderer.cpp | 372 | ||||
-rw-r--r-- | experimental/PdfViewer/SkPdfRenderer.h | 6 | ||||
-rw-r--r-- | experimental/PdfViewer/pdfparser/native/SkPdfNativeDoc.cpp | 45 | ||||
-rw-r--r-- | experimental/PdfViewer/pdfparser/native/SkPdfNativeObject.cpp | 15 | ||||
-rw-r--r-- | experimental/PdfViewer/pdfparser/native/SkPdfNativeObject.h | 36 | ||||
-rw-r--r-- | experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp | 8 |
7 files changed, 352 insertions, 163 deletions
diff --git a/experimental/PdfViewer/SkPdfConfig.h b/experimental/PdfViewer/SkPdfConfig.h index 905041bab6..11e0319ae4 100644 --- a/experimental/PdfViewer/SkPdfConfig.h +++ b/experimental/PdfViewer/SkPdfConfig.h @@ -8,8 +8,12 @@ #ifndef SkPdfConfig_DEFINED #define SkPdfConfig_DEFINED +#include "stddef.h" +class SkPdfNativeObject; + //#define PDF_TRACK_OBJECT_USAGE //#define PDF_TRACK_STREAM_OFFSETS +//#define PDF_REPORT //#define PDF_TRACE //#define PDF_TRACE_READ_TOKEN //#define PDF_TRACE_DRAWTEXT @@ -73,5 +77,34 @@ #define STORE_TRACK_PARAMETER_OFFSET_END(obj,offsetEnd) #endif //PDF_TRACK_STREAM_OFFSETS +// TODO(edisonn): move it somewhere else? +struct SkPdfInputStream { +#ifdef PDF_TRACK_STREAM_OFFSETS + // no parent object -> original file to be rendered + // no parent file -> stream object + // both -> external stream object + int fParentFileID; + const SkPdfNativeObject* fParentObject; + + size_t fDelta; // delta in parent stream + const unsigned char* fStart; +#endif // PDF_TRACK_STREAM_OFFSETS + + const unsigned char* fEnd; +}; + +struct SkPdfInputStreamLocation { + SkPdfInputStream fInputStream; + const unsigned char* fNow; +}; + +#ifdef PDF_TRACK_STREAM_OFFSETS +struct SkPdfInputStreamRange { + SkPdfInputStream fInputStream; + const unsigned char* fRangeStart; + const unsigned char* fRangeEnd; +}; +#endif // PDF_TRACK_STREAM_OFFSETS + #endif // SkPdfConfig_DEFINED diff --git a/experimental/PdfViewer/SkPdfRenderer.cpp b/experimental/PdfViewer/SkPdfRenderer.cpp index e18c339925..04d9d28fde 100644 --- a/experimental/PdfViewer/SkPdfRenderer.cpp +++ b/experimental/PdfViewer/SkPdfRenderer.cpp @@ -5,6 +5,8 @@ * found in the LICENSE file. */ +#include "SkPdfRenderer.h" + #include "SkBitmapDevice.h" #include "SkCanvas.h" #include "SkDevice.h" @@ -21,11 +23,13 @@ #include "SkPdfGraphicsState.h" #include "SkPdfNativeTokenizer.h" +#include "SkPdfReporter.h" extern "C" SkPdfContext* gPdfContext; extern "C" SkBitmap* gDumpBitmap; extern "C" SkCanvas* gDumpCanvas; + __SK_FORCE_IMAGE_DECODER_LINKING; // TODO(edisonn): tool, show what objects were read at least, show the ones not even read @@ -72,8 +76,11 @@ __SK_FORCE_IMAGE_DECODER_LINKING; * - deal with specific type in spec directly, add all dictionary types to known types */ -#define EXPECT_OPERANDS(pdfContext,n) \ +#define EXPECT_OPERANDS(name,pdfContext,n) \ bool __failed = pdfContext->fObjectStack.count() < n; \ + SkPdfREPORTCODE(const char* __operator_name = name); \ + SkPdfREPORTCODE((void)__operator_name); \ + SkPdfReportIf(pdfContext->fObjectStack.count() < n, kIgnoreError_SkPdfIssueSeverity, kStackOverflow_SkPdfIssue, "Not enought parameters.", NULL, pdfContext); \ SkDEBUGCODE(int __cnt = n); #define POP_OBJ(pdfContext,name) \ @@ -86,18 +93,21 @@ __SK_FORCE_IMAGE_DECODER_LINKING; pdfContext->fObjectStack.pop(); \ } +// TODO(edisonn): make all pop function to use name##_obj #define POP_NUMBER(pdfContext,name) \ SkDEBUGCODE(__cnt--); \ SkASSERT(__cnt >= 0); \ double name = 0; \ + SkPdfNativeObject* name##_obj = NULL; \ __failed = __failed || pdfContext->fObjectStack.count() == 0; \ if (pdfContext->fObjectStack.count() > 0) { \ - SkPdfNativeObject* tmp = pdfContext->fObjectStack.top(); \ + name##_obj = pdfContext->fObjectStack.top(); \ pdfContext->fObjectStack.pop(); \ - if (!tmp || !tmp->isNumber()) { \ + if (!name##_obj || !name##_obj->isNumber()) { \ + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, __operator_name, name##_obj, SkPdfNativeObject::_kNumber_PdfObjectType, NULL);\ __failed = true;\ } else { \ - name = tmp->numberValue(); \ + name = name##_obj->numberValue(); \ } \ } @@ -106,13 +116,15 @@ __SK_FORCE_IMAGE_DECODER_LINKING; SkASSERT(__cnt >= 0); \ int64_t name = 0; \ __failed = __failed || pdfContext->fObjectStack.count() == 0; \ + SkPdfNativeObject* name##_obj = NULL; \ if (pdfContext->fObjectStack.count() > 0) { \ - SkPdfNativeObject* tmp = pdfContext->fObjectStack.top(); \ + name##_obj = pdfContext->fObjectStack.top(); \ pdfContext->fObjectStack.pop(); \ - if (!tmp || !tmp->isInteger()) { \ + if (!name##_obj || !name##_obj->isInteger()) { \ + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, __operator_name, name##_obj, SkPdfNativeObject::kInteger_PdfObjectType, NULL);\ __failed = true;\ } else { \ - name = tmp->intValue(); \ + name = name##_obj->intValue(); \ } \ } @@ -124,6 +136,7 @@ __SK_FORCE_IMAGE_DECODER_LINKING; SkPdfNativeObject* tmp = pdfContext->fObjectStack.top(); \ pdfContext->fObjectStack.pop(); \ if (!tmp || !tmp->isNumber()) { \ + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, __operator_name, tmp, SkPdfNativeObject::kInteger_PdfObjectType | SkPdfNativeObject::kReal_PdfObjectType, NULL);\ __failed = true;\ } else { \ var = tmp->numberValue(); \ @@ -140,6 +153,7 @@ __SK_FORCE_IMAGE_DECODER_LINKING; SkPdfNativeObject* tmp = pdfContext->fObjectStack.top(); \ pdfContext->fObjectStack.pop(); \ if (!tmp || !tmp->isName()) { \ + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, __operator_name, tmp, SkPdfNativeObject::kName_PdfObjectType, NULL);\ __failed = true;\ } else { \ name = tmp; \ @@ -155,6 +169,7 @@ __SK_FORCE_IMAGE_DECODER_LINKING; SkPdfNativeObject* tmp = pdfContext->fObjectStack.top(); \ pdfContext->fObjectStack.pop(); \ if (!tmp || !tmp->isAnyString()) { \ + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, __operator_name, tmp, SkPdfNativeObject::kString_PdfObjectType | SkPdfNativeObject::kHexString_PdfObjectType, NULL);\ __failed = true;\ } else { \ name = tmp; \ @@ -170,6 +185,7 @@ __SK_FORCE_IMAGE_DECODER_LINKING; SkPdfNativeObject* tmp = pdfContext->fObjectStack.top(); \ pdfContext->fObjectStack.pop(); \ if (!tmp || !tmp->isArray()) { \ + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, __operator_name, tmp, SkPdfNativeObject::kArray_PdfObjectType, NULL);\ __failed = true;\ } else { \ name = (SkPdfArray*)tmp; \ @@ -300,10 +316,21 @@ SkMatrix SkMatrixFromPdfArray(SkPdfArray* pdfArray) { double array[6]; // TODO(edisonn): security issue, ret if size() != 6 + if (pdfArray == NULL) { + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kNullObject_SkPdfIssue, "null array passed to build matrix", NULL, NULL); + return SkMatrix::I(); + } + + if (pdfArray->size() != 6) { + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kUnexpectedArraySize_SkPdfIssue, "null array passed to build matrix", pdfArray, NULL); + return SkMatrix::I(); + } + for (int i = 0; i < 6; i++) { const SkPdfNativeObject* elem = pdfArray->operator [](i); if (elem == NULL || !elem->isNumber()) { - return SkMatrix::I(); // TODO(edisonn): report issue + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, elem, SkPdfNativeObject::_kNumber_PdfObjectType, NULL); + return SkMatrix::I(); } array[i] = elem->numberValue(); } @@ -462,9 +489,8 @@ static SkPdfResult DrawText(SkPdfContext* pdfContext, skfont = SkPdfFont::Default(); } - if (_str == NULL || !_str->isAnyString()) { - // TODO(edisonn): report warning + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "DrawText", _str, SkPdfNativeObject::_kAnyString_PdfObjectType, pdfContext); return kIgnoreError_SkPdfResult; } const SkPdfString* str = (const SkPdfString*)_str; @@ -474,7 +500,7 @@ static SkPdfResult DrawText(SkPdfContext* pdfContext, SkDecodedText decoded; if (skfont->encoding() == NULL) { - // TODO(edisonn): report warning + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kMissingEncoding_SkPdfIssue, "draw text", _str, pdfContext); return kNYI_SkPdfResult; } @@ -518,10 +544,11 @@ static SkColorTable* getGrayColortable() { return grayColortable; } -static SkBitmap* transferImageStreamToBitmap(const unsigned char* uncompressedStream, size_t uncompressedStreamLength, - int width, int height, int bytesPerLine, - int bpc, const SkString& colorSpace, - bool transparencyMask) { +static SkBitmap* transferImageStreamToBitmap(const unsigned char* uncompressedStream, + size_t uncompressedStreamLength, + int width, int height, int bytesPerLine, + int bpc, const SkString& colorSpace, + bool transparencyMask) { SkBitmap* bitmap = new SkBitmap(); //int components = GetColorSpaceComponents(colorSpace); @@ -566,7 +593,8 @@ static SkBitmap* transferImageStreamToBitmap(const unsigned char* uncompressedSt bitmap->setPixels(uncompressedStreamA8, transparencyMask ? NULL : getGrayColortable()); } - // TODO(edisonn): Report Warning, NYI, or error + // TODO(edisonn): pass color space and context here? + SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "Color space NYI", NULL, NULL); return bitmap; } @@ -581,7 +609,7 @@ static SkBitmap* transferImageStreamToBitmap(const unsigned char* uncompressedSt static SkBitmap* getImageFromObjectCore(SkPdfContext* pdfContext, SkPdfImageDictionary* image, bool transparencyMask) { if (image == NULL || !image->hasStream()) { - // TODO(edisonn): report warning to be used in testing. + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "Missing stream", image, SkPdfNativeObject::_kStream_PdfObjectType, pdfContext); return NULL; } @@ -594,7 +622,6 @@ static SkBitmap* getImageFromObjectCore(SkPdfContext* pdfContext, SkPdfImageDict SkPMColor colors[256]; int cnt = 0; - // TODO(edisonn): color space can be an array too! if (image->isColorSpaceAName(pdfContext->fPdfDoc)) { colorSpace = image->getColorSpaceAsName(pdfContext->fPdfDoc); } else if (image->isColorSpaceAArray(pdfContext->fPdfDoc)) { @@ -604,17 +631,17 @@ static SkBitmap* getImageFromObjectCore(SkPdfContext* pdfContext, SkPdfImageDict array->objAtAIndex(2)->isInteger() && array->objAtAIndex(3)->isHexString() ) { - // TODO(edisonn): suport only DeviceRGB for now. + SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "Color space NYI", image, pdfContext); indexed = true; cnt = (int)array->objAtAIndex(2)->intValue() + 1; if (cnt > 256) { - // TODO(edionn): report NYIs + SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "Color space feature NYI, cnt > 256", image, pdfContext); return NULL; } SkColorTable colorTable(cnt); NotOwnedString data = array->objAtAIndex(3)->strRef(); if (data.fBytes != (unsigned int)cnt * 3) { - // TODO(edionn): report error/warning + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kIncostistentSizes_SkPdfIssue, "Image color table mismatch color space specs", array, pdfContext); return NULL; } for (int i = 0 ; i < cnt; i++) { @@ -642,7 +669,7 @@ static SkBitmap* getImageFromObjectCore(SkPdfContext* pdfContext, SkPdfImageDict if (!stream || !stream->GetFilteredStreamRef(&uncompressedStream, &uncompressedStreamLength) || uncompressedStream == NULL || uncompressedStreamLength == 0) { - // TODO(edisonn): report warning to be used in testing. + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "Missing stream", stream, SkPdfNativeObject::_kStream_PdfObjectType, pdfContext); return NULL; } @@ -718,6 +745,8 @@ static SkBitmap* getSmaskFromObject(SkPdfContext* pdfContext, SkPdfImageDictiona } // TODO(edisonn): implement GS SMask. Default to empty right now. + SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "implement GS SMask. Default to empty right now.", obj, pdfContext); + return pdfContext->fGraphicsState.fSMask; } @@ -756,6 +785,8 @@ static SkPdfResult doXObject_Image(SkPdfContext* pdfContext, SkCanvas* canvas, S SkRect dst = SkRect::MakeXYWH(SkDoubleToScalar(0.0), SkDoubleToScalar(0.0), SkDoubleToScalar(1.0), SkDoubleToScalar(1.0)); // TODO(edisonn): soft mask type? alpha/luminosity. + SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "implement soft mask type", skpdfimage, pdfContext); + SkPaint paint; pdfContext->fGraphicsState.applyGraphicsState(&paint, false); @@ -818,10 +849,12 @@ static void doGroup_before(SkPdfContext* pdfContext, SkCanvas* canvas, SkRect bb static SkPdfResult doXObject_Form(SkPdfContext* pdfContext, SkCanvas* canvas, SkPdfType1FormDictionary* skobj) { if (!skobj || !skobj->hasStream()) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "Missing stream", skobj, SkPdfNativeObject::_kStream_PdfObjectType, pdfContext); return kIgnoreError_SkPdfResult; } if (!skobj->has_BBox()) { + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kMissingRequiredKey_SkPdfIssue, "BBox", skobj, pdfContext); return kIgnoreError_SkPdfResult; } @@ -885,10 +918,12 @@ static SkPdfResult doXObject_Form(SkPdfContext* pdfContext, SkCanvas* canvas, Sk // TODO(edisonn): Extract a class like ObjWithStream static SkPdfResult doXObject_Pattern(SkPdfContext* pdfContext, SkCanvas* canvas, SkPdfType1PatternDictionary* skobj) { if (!skobj || !skobj->hasStream()) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "Missing stream", skobj, SkPdfNativeObject::_kStream_PdfObjectType, pdfContext); return kIgnoreError_SkPdfResult; } if (!skobj->has_BBox()) { + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kMissingRequiredKey_SkPdfIssue, "BBox", skobj, pdfContext); return kIgnoreError_SkPdfResult; } @@ -940,6 +975,7 @@ static SkPdfResult doXObject_Pattern(SkPdfContext* pdfContext, SkCanvas* canvas, SkPdfResult doType3Char(SkPdfContext* pdfContext, SkCanvas* canvas, const SkPdfNativeObject* skobj, SkRect bBox, SkMatrix matrix, double textSize) { if (!skobj || !skobj->hasStream()) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "Missing stream", skobj, SkPdfNativeObject::_kStream_PdfObjectType, pdfContext); return kIgnoreError_SkPdfResult; } @@ -1003,7 +1039,7 @@ public: static SkPdfResult doXObject(SkPdfContext* pdfContext, SkCanvas* canvas, SkPdfNativeObject* obj) { if (CheckRecursiveRendering::IsInRendering(obj)) { - // Oops, corrupt PDF! + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kRecursiveReferencing_SkPdfIssue, "Recursive reverencing is invalid in draw objects", obj, pdfContext); return kIgnoreError_SkPdfResult; } @@ -1022,23 +1058,22 @@ static SkPdfResult doXObject(SkPdfContext* pdfContext, SkCanvas* canvas, SkPdfNa SkPdfType1PatternDictionary* pattern = (SkPdfType1PatternDictionary*)obj; return doXObject_Pattern(pdfContext, canvas, pattern); } + SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "doXObject", obj, pdfContext); } } return kIgnoreError_SkPdfResult; } static SkPdfResult doPage(SkPdfContext* pdfContext, SkCanvas* canvas, SkPdfPageObjectDictionary* skobj) { - if (!skobj) { - return kIgnoreError_SkPdfResult; - } - - if (!skobj->isContentsAStream(pdfContext->fPdfDoc)) { + if (!skobj || !skobj->isContentsAStream(pdfContext->fPdfDoc)) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "Missing stream", skobj, SkPdfNativeObject::_kStream_PdfObjectType, pdfContext); return kNYI_SkPdfResult; } SkPdfStream* stream = skobj->getContentsAsStream(pdfContext->fPdfDoc); if (!stream) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "Missing stream", skobj, SkPdfNativeObject::_kStream_PdfObjectType, pdfContext); return kIgnoreError_SkPdfResult; } @@ -1049,7 +1084,7 @@ static SkPdfResult doPage(SkPdfContext* pdfContext, SkCanvas* canvas, SkPdfPageO } if (CheckRecursiveRendering::IsInRendering(skobj)) { - // Oops, corrupt PDF! + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kRecursiveReferencing_SkPdfIssue, "Recursive reverencing is invalid in draw objects", skobj, pdfContext); return kIgnoreError_SkPdfResult; } CheckRecursiveRendering checkRecursion(skobj); @@ -1058,6 +1093,8 @@ static SkPdfResult doPage(SkPdfContext* pdfContext, SkCanvas* canvas, SkPdfPageO PdfOp_q(pdfContext, canvas, NULL); // TODO(edisonn): MediaBox can be inherited!!!! + SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "MediaBox inheritance NYI", NULL, pdfContext); + SkRect bbox = skobj->MediaBox(pdfContext->fPdfDoc); if (skobj->has_Group()) { SkPdfTransparencyGroupDictionary* tgroup = skobj->Group(pdfContext->fPdfDoc); @@ -1097,12 +1134,14 @@ SkPdfResult PdfOp_Q(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** pdfContext->fStateStack.pop(); canvas->restore(); - if (pdfContext->fObjectStack.nests() <= 0) { + if (pdfContext->fObjectStack.nests() == 0) { + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kStackNestingOverflow_SkPdfIssue, "stack nesting overflow (q/Q)", NULL, pdfContext); return kIgnoreError_SkPdfResult; } else { pdfContext->fObjectStack.unnest(); } } else { + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kStackOverflow_SkPdfIssue, "stack overflow (q/Q)", NULL, pdfContext); return kIgnoreError_SkPdfResult; } @@ -1110,7 +1149,7 @@ SkPdfResult PdfOp_Q(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** } static SkPdfResult PdfOp_cm(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 6); + EXPECT_OPERANDS("cm", pdfContext, 6); POP_NUMBER(pdfContext, f); POP_NUMBER(pdfContext, e); POP_NUMBER(pdfContext, d); @@ -1151,7 +1190,7 @@ static SkPdfResult PdfOp_cm(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken //, to leading, which is a number expressed in unscaled text //space units. Text leading is used only by the T*, ', and " operators. Initial value: 0. static SkPdfResult PdfOp_TL(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 1) + EXPECT_OPERANDS("TL", pdfContext, 1); POP_NUMBER(pdfContext, ty); CHECK_PARAMETERS(); @@ -1161,7 +1200,7 @@ static SkPdfResult PdfOp_TL(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken } static SkPdfResult PdfOp_Td(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 2); + EXPECT_OPERANDS("Td", pdfContext, 2); POP_NUMBER(pdfContext, ty); POP_NUMBER(pdfContext, tx); CHECK_PARAMETERS(); @@ -1176,7 +1215,7 @@ static SkPdfResult PdfOp_Td(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken } static SkPdfResult PdfOp_TD(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 2) + EXPECT_OPERANDS("TD", pdfContext, 2) POP_NUMBER(pdfContext, ty); POP_NUMBER(pdfContext, tx); CHECK_PARAMETERS(); @@ -1202,7 +1241,7 @@ static SkPdfResult PdfOp_TD(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken } static SkPdfResult PdfOp_Tm(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 6); + EXPECT_OPERANDS("Tm", pdfContext, 6); POP_NUMBER(pdfContext, f); POP_NUMBER(pdfContext, e); POP_NUMBER(pdfContext, d); @@ -1224,6 +1263,8 @@ static SkPdfResult PdfOp_Tm(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken matrix.preScale(SkDoubleToScalar(1), SkDoubleToScalar(-1)); // TODO(edisonn): Text positioning. + SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "Text positioning not implemented for 2+ chars", NULL, pdfContext); + pdfContext->fGraphicsState.fMatrixTm = matrix; pdfContext->fGraphicsState.fMatrixTlm = matrix;; @@ -1251,7 +1292,7 @@ static SkPdfResult PdfOp_m(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenL pdfContext->fGraphicsState.fPathClosed = false; } - EXPECT_OPERANDS(pdfContext, 2); + EXPECT_OPERANDS("m", pdfContext, 2); POP_NUMBER(pdfContext, y); POP_NUMBER(pdfContext, x); CHECK_PARAMETERS(); @@ -1271,7 +1312,7 @@ static SkPdfResult PdfOp_l(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenL pdfContext->fGraphicsState.fPathClosed = false; } - EXPECT_OPERANDS(pdfContext, 2); + EXPECT_OPERANDS("l", pdfContext, 2); POP_NUMBER(pdfContext, y); POP_NUMBER(pdfContext, x); CHECK_PARAMETERS(); @@ -1291,7 +1332,7 @@ static SkPdfResult PdfOp_c(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenL pdfContext->fGraphicsState.fPathClosed = false; } - EXPECT_OPERANDS(pdfContext, 6); + EXPECT_OPERANDS("c", pdfContext, 6); POP_NUMBER(pdfContext, y3); POP_NUMBER(pdfContext, x3); POP_NUMBER(pdfContext, y2); @@ -1316,7 +1357,7 @@ static SkPdfResult PdfOp_v(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenL pdfContext->fGraphicsState.fPathClosed = false; } - EXPECT_OPERANDS(pdfContext, 4); + EXPECT_OPERANDS("v", pdfContext, 4); POP_NUMBER(pdfContext, y3); POP_NUMBER(pdfContext, x3); POP_NUMBER(pdfContext, y2); @@ -1342,7 +1383,7 @@ static SkPdfResult PdfOp_y(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenL pdfContext->fGraphicsState.fPathClosed = false; } - EXPECT_OPERANDS(pdfContext, 4); + EXPECT_OPERANDS("y", pdfContext, 4); POP_NUMBER(pdfContext, y3); POP_NUMBER(pdfContext, x3); POP_NUMBER(pdfContext, y1); @@ -1368,7 +1409,7 @@ static SkPdfResult PdfOp_re(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken pdfContext->fGraphicsState.fPathClosed = false; } - EXPECT_OPERANDS(pdfContext, 4); + EXPECT_OPERANDS("re", pdfContext, 4); POP_NUMBER(pdfContext, height); POP_NUMBER(pdfContext, width); POP_NUMBER(pdfContext, y); @@ -1435,6 +1476,8 @@ static SkPdfResult PdfOp_fillAndStroke(SkPdfContext* pdfContext, SkCanvas* canva int xStep = abs((int)pattern->XStep(pdfContext->fPdfDoc)); int yStep = abs((int)pattern->YStep(pdfContext->fPdfDoc)); + SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "paterns x/y step is forced to positive number", pattern, pdfContext); + SkRect bounds = path.getBounds(); // TODO(edisonn): xstep and ystep can be negative, and we need to iterate in reverse @@ -1564,7 +1607,6 @@ static SkPdfResult PdfOp_n(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenL #endif } - //pdfContext->fGraphicsState.fClipPath.reset(); pdfContext->fGraphicsState.fHasClipPathToApply = false; pdfContext->fGraphicsState.fPathClosed = true; @@ -1584,6 +1626,8 @@ static SkPdfResult PdfOp_BT(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken static SkPdfResult PdfOp_ET(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { if (!pdfContext->fGraphicsState.fTextBlock) { + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kMissingBT_SkPdfIssue, "ET without BT", NULL, pdfContext); + return kIgnoreError_SkPdfResult; } // TODO(edisonn): anything else to be done once we are done with draw text? Like restore stack? @@ -1597,6 +1641,7 @@ static SkPdfResult skpdfGraphicsStateApplyFontCore(SkPdfContext* pdfContext, con if (!pdfContext->fGraphicsState.fResources->Font(pdfContext->fPdfDoc)) { // TODO(edisonn): try to recover and draw it any way? + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kMissingFont_SkPdfIssue, "No font", fontName, pdfContext); return kIgnoreError_SkPdfResult; } @@ -1604,6 +1649,7 @@ static SkPdfResult skpdfGraphicsStateApplyFontCore(SkPdfContext* pdfContext, con objFont = pdfContext->fPdfDoc->resolveReference(objFont); if (kNone_SkPdfNativeObjectType == pdfContext->fPdfDoc->mapper()->mapFontDictionary(objFont)) { // TODO(edisonn): try to recover and draw it any way? + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kInvalidFont_SkPdfIssue, "Invalid font", objFont, pdfContext); return kIgnoreError_SkPdfResult; } @@ -1624,7 +1670,7 @@ static SkPdfResult skpdfGraphicsStateApplyFontCore(SkPdfContext* pdfContext, con //a number representing a scale factor. There is no initial value for either font or //size; they must be specified explicitly using Tf before any text is shown. static SkPdfResult PdfOp_Tf(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 2); + EXPECT_OPERANDS("Tf", pdfContext, 2); POP_NUMBER(pdfContext, fontSize); POP_NAME(pdfContext, fontName); CHECK_PARAMETERS(); @@ -1633,12 +1679,13 @@ static SkPdfResult PdfOp_Tf(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken } static SkPdfResult PdfOp_Tj(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 1); + EXPECT_OPERANDS("Tj", pdfContext, 1); POP_STRING(pdfContext, str); CHECK_PARAMETERS(); if (!pdfContext->fGraphicsState.fTextBlock) { // TODO(edisonn): try to recover and draw it any way? + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kMissingBT_SkPdfIssue, "Tj without BT", NULL, pdfContext); return kIgnoreError_SkPdfResult; } @@ -1650,6 +1697,7 @@ static SkPdfResult PdfOp_Tj(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken static SkPdfResult PdfOp_quote(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { if (!pdfContext->fGraphicsState.fTextBlock) { // TODO(edisonn): try to recover and draw it any way? + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kMissingBT_SkPdfIssue, "' without BT", NULL, pdfContext); return kIgnoreError_SkPdfResult; } @@ -1661,10 +1709,11 @@ static SkPdfResult PdfOp_quote(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTo static SkPdfResult PdfOp_doublequote(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { if (!pdfContext->fGraphicsState.fTextBlock) { // TODO(edisonn): try to recover and draw it any way? + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kMissingBT_SkPdfIssue, "\" without BT", NULL, pdfContext); return kIgnoreError_SkPdfResult; } - EXPECT_OPERANDS(pdfContext, 3); + EXPECT_OPERANDS("\"", pdfContext, 3); POP_OBJ(pdfContext, str); POP_OBJ(pdfContext, ac); POP_OBJ(pdfContext, aw); @@ -1683,22 +1732,26 @@ static SkPdfResult PdfOp_doublequote(SkPdfContext* pdfContext, SkCanvas* canvas, } static SkPdfResult PdfOp_TJ(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 1); + EXPECT_OPERANDS("Tf", pdfContext, 1); POP_ARRAY(pdfContext, array); CHECK_PARAMETERS(); if (!pdfContext->fGraphicsState.fTextBlock) { // TODO(edisonn): try to recover and draw it any way? + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kMissingBT_SkPdfIssue, "TJ without BT", NULL, pdfContext); return kIgnoreError_SkPdfResult; } if (!array->isArray()) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, array, SkPdfNativeObject::kArray_PdfObjectType, pdfContext); return kIgnoreError_SkPdfResult; } for( int i=0; i<static_cast<int>(array->size()); i++ ) { - if( (*array)[i]->isAnyString()) { + if (!(*array)[i]) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "element [i] is null, no element should be null", array, SkPdfNativeObject::_kAnyString_PdfObjectType || SkPdfNativeObject::_kNumber_PdfObjectType, pdfContext); + } else if( (*array)[i]->isAnyString()) { SkPdfNativeObject* obj = (*array)[i]; DrawText(pdfContext, obj, canvas); } else if ((*array)[i]->isNumber()) { @@ -1716,13 +1769,15 @@ static SkPdfResult PdfOp_TJ(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken SkDoubleToScalar(1)); pdfContext->fGraphicsState.fMatrixTm.preConcat(matrix); + } else { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "wrong type", (*array)[i], SkPdfNativeObject::kArray_PdfObjectType || SkPdfNativeObject::_kNumber_PdfObjectType, pdfContext); } } return kPartial_SkPdfResult; // TODO(edisonn): Implement fully DrawText before returing OK. } static SkPdfResult PdfOp_CS_cs(SkPdfContext* pdfContext, SkCanvas* canvas, SkPdfColorOperator* colorOperator) { - EXPECT_OPERANDS(pdfContext, 1); + EXPECT_OPERANDS("CS/cs", pdfContext, 1); POP_NAME(pdfContext, name); CHECK_PARAMETERS(); @@ -1742,6 +1797,7 @@ static SkPdfResult PdfOp_CS_cs(SkPdfContext* pdfContext, SkCanvas* canvas, SkPdf } else if (colorSpace->isArray()) { int cnt = colorSpace->size(); if (cnt == 0) { + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kIncostistentSizes_SkPdfIssue, "color space has length 0", colorSpace, pdfContext); return kIgnoreError_SkPdfResult; } SkPdfNativeObject* type = colorSpace->objAtAIndex(0); @@ -1749,6 +1805,7 @@ static SkPdfResult PdfOp_CS_cs(SkPdfContext* pdfContext, SkCanvas* canvas, SkPdf if (type->isName("ICCBased")) { if (cnt != 2) { + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kIncostistentSizes_SkPdfIssue, "ICCBased color space must have an array with 2 elements", colorSpace, pdfContext); return kIgnoreError_SkPdfResult; } SkPdfNativeObject* prop = colorSpace->objAtAIndex(1); @@ -1792,7 +1849,7 @@ static SkPdfResult PdfOp_SC_sc(SkPdfContext* pdfContext, SkCanvas* canvas, SkPdf printf("color space = %s, N = %i\n", colorOperator->fColorSpace.fBuffer, n); #endif - EXPECT_OPERANDS(pdfContext, n); + EXPECT_OPERANDS("SC/sc", pdfContext, n); for (int i = n - 1; i >= 0 ; i--) { if (doubles) { @@ -1852,7 +1909,7 @@ static SkPdfResult PdfOp_scn(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToke } static SkPdfResult PdfOp_G_g(SkPdfContext* pdfContext, SkCanvas* canvas, SkPdfColorOperator* colorOperator) { - EXPECT_OPERANDS(pdfContext, 1); + EXPECT_OPERANDS("G/g", pdfContext, 1); POP_NUMBER(pdfContext, gray); CHECK_PARAMETERS(); @@ -1871,7 +1928,7 @@ static SkPdfResult PdfOp_g(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenL } static SkPdfResult PdfOp_RG_rg(SkPdfContext* pdfContext, SkCanvas* canvas, SkPdfColorOperator* colorOperator) { - EXPECT_OPERANDS(pdfContext, 3); + EXPECT_OPERANDS("RG/rg", pdfContext, 3); POP_NUMBER(pdfContext, b); POP_NUMBER(pdfContext, g); POP_NUMBER(pdfContext, r); @@ -1892,7 +1949,7 @@ static SkPdfResult PdfOp_rg(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken static SkPdfResult PdfOp_K_k(SkPdfContext* pdfContext, SkCanvas* canvas, SkPdfColorOperator* colorOperator) { // TODO(edisonn): spec has some rules about overprint, implement them. - EXPECT_OPERANDS(pdfContext, 4); + EXPECT_OPERANDS("K/k", pdfContext, 4); POP_NUMBER(pdfContext, k); POP_NUMBER(pdfContext, y); POP_NUMBER(pdfContext, m); @@ -1939,10 +1996,8 @@ static SkPdfResult PdfOp_BX(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken } static SkPdfResult PdfOp_EX(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { -#ifdef ASSERT_BAD_PDF_OPS - SkASSERT(false); // EX must be consumed by PdfCompatibilitySectionLooper, but let's - // have the assert when testing good pdfs. -#endif + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kNullObject_SkPdfIssue, "EX operator should not be called, it is habdled in a looper, unless the file is corrupted, we should assert", NULL, pdfContext); + return kIgnoreError_SkPdfResult; } @@ -1952,22 +2007,15 @@ static SkPdfResult PdfOp_BI(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken } static SkPdfResult PdfOp_ID(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { -#ifdef ASSERT_BAD_PDF_OPS - SkASSERT(false); // must be processed in inline image looper, but let's - // have the assert when testing good pdfs. -#endif + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kNullObject_SkPdfIssue, "ID operator should not be called, it is habdled in a looper, unless the file is corrupted, we should assert", NULL, pdfContext); return kIgnoreError_SkPdfResult; } static SkPdfResult PdfOp_EI(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { -#ifdef ASSERT_BAD_PDF_OPS - SkASSERT(false); // must be processed in inline image looper, but let's - // have the assert when testing good pdfs. -#endif + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kNullObject_SkPdfIssue, "EI operator should not be called, it is habdled in a looper, unless the file is corrupted, we should assert", NULL, pdfContext); return kIgnoreError_SkPdfResult; } - // TODO(edisonn): security review here, make sure all parameters are valid, and safe. static SkPdfResult skpdfGraphicsStateApply_ca(SkPdfContext* pdfContext, double ca) { pdfContext->fGraphicsState.fNonStroking.fOpacity = ca; @@ -2010,15 +2058,25 @@ static SkPdfResult skpdfGraphicsStateApplyML(SkPdfContext* pdfContext, double mi */ static SkPdfResult skpdfGraphicsStateApplyD(SkPdfContext* pdfContext, SkPdfArray* intervals, SkPdfNativeObject* phase) { + if (intervals == NULL) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, intervals, SkPdfNativeObject::_kNumber_PdfObjectType, pdfContext); + return kIgnoreError_SkPdfResult; + } + + if (phase == NULL) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, phase, SkPdfNativeObject::_kNumber_PdfObjectType, pdfContext); + return kIgnoreError_SkPdfResult; + } + int cnt = intervals->size(); if (cnt >= 256) { - // TODO(edisonn): report error/warning, unsuported; // TODO(edisonn): alloc memory + SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "dash array size unssuported, cnt > 256", intervals, pdfContext); return kIgnoreError_SkPdfResult; } for (int i = 0; i < cnt; i++) { - if (!intervals->objAtAIndex(i)->isNumber()) { - // TODO(edisonn): report error/warning + if (!intervals->objAtAIndex(i) || !intervals->objAtAIndex(i)->isNumber()) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, intervals->objAtAIndex(i), SkPdfNativeObject::_kNumber_PdfObjectType, NULL); return kIgnoreError_SkPdfResult; } } @@ -2048,26 +2106,58 @@ static SkPdfResult skpdfGraphicsStateApplyD(SkPdfContext* pdfContext, SkPdfArray } static SkPdfResult skpdfGraphicsStateApplyD(SkPdfContext* pdfContext, SkPdfArray* dash) { - // TODO(edisonn): verify input - if (!dash || dash->isArray() || dash->size() != 2 || !dash->objAtAIndex(0)->isArray() || !dash->objAtAIndex(1)->isNumber()) { - // TODO(edisonn): report error/warning + if (!dash || dash->isArray()) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, dash, SkPdfNativeObject::kArray_PdfObjectType, pdfContext); + return kIgnoreError_SkPdfResult; + } + + if (dash->size() != 2) { + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kIncostistentSizes_SkPdfIssue, "hash array must have 2 elements", dash, pdfContext); return kIgnoreError_SkPdfResult; } + + if (!dash->objAtAIndex(0) || !dash->objAtAIndex(0)->isArray()) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, dash->objAtAIndex(0), SkPdfNativeObject::kArray_PdfObjectType, pdfContext); + return kIgnoreError_SkPdfResult; + } + + if (!dash->objAtAIndex(1) || !dash->objAtAIndex(1)->isNumber()) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, dash->objAtAIndex(1), SkPdfNativeObject::_kNumber_PdfObjectType, pdfContext); + return kIgnoreError_SkPdfResult; + } + return skpdfGraphicsStateApplyD(pdfContext, (SkPdfArray*)dash->objAtAIndex(0), dash->objAtAIndex(1)); } static void skpdfGraphicsStateApplyFont(SkPdfContext* pdfContext, SkPdfArray* fontAndSize) { - if (!fontAndSize || fontAndSize->isArray() || fontAndSize->size() != 2 || !fontAndSize->objAtAIndex(0)->isName() || !fontAndSize->objAtAIndex(1)->isNumber()) { - // TODO(edisonn): report error/warning + if (!fontAndSize || !fontAndSize->isArray()) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, fontAndSize, SkPdfNativeObject::kArray_PdfObjectType, pdfContext); return; } + + if (fontAndSize->size() != 2) { + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kIncostistentSizes_SkPdfIssue, "font array must have 2 elements", fontAndSize, pdfContext); + return; + } + + if (!fontAndSize->objAtAIndex(0) || !fontAndSize->objAtAIndex(0)->isName()) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, fontAndSize->objAtAIndex(0), SkPdfNativeObject::kName_PdfObjectType, pdfContext); + return; + } + + + if (!fontAndSize->objAtAIndex(1) || !fontAndSize->objAtAIndex(1)->isNumber()) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, fontAndSize->objAtAIndex(0), SkPdfNativeObject::_kNumber_PdfObjectType, pdfContext); + return; + } + skpdfGraphicsStateApplyFontCore(pdfContext, fontAndSize->objAtAIndex(0), fontAndSize->objAtAIndex(1)->numberValue()); } //lineWidth w Set the line width in the graphics state (see “Line Width” on page 152). static SkPdfResult PdfOp_w(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 1); + EXPECT_OPERANDS("w", pdfContext, 1); POP_NUMBER(pdfContext, lw); CHECK_PARAMETERS(); @@ -2077,7 +2167,7 @@ static SkPdfResult PdfOp_w(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenL //lineCap J Set the line cap style in the graphics state (see “Line Cap Style” on page 153). static SkPdfResult PdfOp_J(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { // TODO(edisonn): round/ceil to int? - EXPECT_OPERANDS(pdfContext, 1); + EXPECT_OPERANDS("J", pdfContext, 1); POP_NUMBER(pdfContext, lc); CHECK_PARAMETERS(); @@ -2087,7 +2177,7 @@ static SkPdfResult PdfOp_J(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenL //lineJoin j Set the line join style in the graphics state (see “Line Join Style” on page 153). static SkPdfResult PdfOp_j(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { // TODO(edisonn): round/ceil to int? - EXPECT_OPERANDS(pdfContext, 1); + EXPECT_OPERANDS("j", pdfContext, 1); POP_NUMBER(pdfContext, lj); CHECK_PARAMETERS(); @@ -2096,7 +2186,7 @@ static SkPdfResult PdfOp_j(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenL //miterLimit M Set the miter limit in the graphics state (see “Miter Limit” on page 153). static SkPdfResult PdfOp_M(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 1); + EXPECT_OPERANDS("M", pdfContext, 1); POP_NUMBER(pdfContext, ml); CHECK_PARAMETERS(); return skpdfGraphicsStateApplyML(pdfContext, ml); @@ -2105,7 +2195,7 @@ static SkPdfResult PdfOp_M(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenL //dashArray dashPhase d Set the line dash pattern in the graphics state (see “Line Dash Pattern” on //page 155). static SkPdfResult PdfOp_d(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 2); + EXPECT_OPERANDS("d", pdfContext, 2); POP_OBJ(pdfContext, phase); POP_ARRAY(pdfContext, array); CHECK_PARAMETERS(); @@ -2117,6 +2207,8 @@ static SkPdfResult PdfOp_d(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenL static SkPdfResult PdfOp_ri(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { pdfContext->fObjectStack.pop(); + SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "render intent NYI", NULL, pdfContext); + return kNYI_SkPdfResult; } @@ -2124,12 +2216,13 @@ static SkPdfResult PdfOp_ri(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken //Tolerance”). flatness is a number in the range 0 to 100; a value of 0 speci- //fies the output device’s default flatness tolerance. static SkPdfResult PdfOp_i(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 1); + EXPECT_OPERANDS("i", pdfContext, 1); POP_NUMBER(pdfContext, flatness); CHECK_PARAMETERS(); if (flatness < 0 || flatness > 100) { - return kError_SkPdfResult; + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kOutOfRange_SkPdfIssue, "flatness must be a real in [0, 100] range", flatness_obj, pdfContext); + return kIgnoreError_SkPdfResult; } return kNYI_SkPdfResult; @@ -2180,26 +2273,32 @@ static void skpdfGraphicsStateApplyBM_name(SkPdfContext* pdfContext, const SkStr pdfContext->fGraphicsState.fBlendModesLength = 1; pdfContext->fGraphicsState.fBlendModes[0] = mode; } else { - // TODO(edisonn): report unknown blend mode + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kUnknownBlendMode_SkPdfIssue, blendMode.c_str(), NULL, pdfContext); } } static void skpdfGraphicsStateApplyBM_array(SkPdfContext* pdfContext, SkPdfArray* blendModes) { - if (!blendModes || blendModes->isArray() || blendModes->size() == 0 || blendModes->size() > 256) { - // TODO(edisonn): report error/warning + if (!blendModes || !blendModes->isArray()) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, blendModes, SkPdfNativeObject::kArray_PdfObjectType, pdfContext); + return; + } + + if (blendModes->size() == 0 || blendModes->size() > 256) { + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kIncostistentSizes_SkPdfIssue, "length of blendmodes, 0, is an erro, 256+, is NYI", blendModes, pdfContext); return; } + SkXfermode::Mode modes[256]; int cnt = blendModes->size(); for (int i = 0; i < cnt; i++) { SkPdfNativeObject* name = blendModes->objAtAIndex(i); - if (!name->isName()) { - // TODO(edisonn): report error/warning + if (!name || !name->isName()) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, name, SkPdfNativeObject::kName_PdfObjectType, pdfContext); return; } SkXfermode::Mode mode = xferModeFromBlendMode(name->c_str(), name->lenstr()); if (mode > SkXfermode::kLastMode) { - // TODO(edisonn): report error/warning + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kUnknownBlendMode_SkPdfIssue, NULL, name, pdfContext); return; } } @@ -2211,14 +2310,19 @@ static void skpdfGraphicsStateApplyBM_array(SkPdfContext* pdfContext, SkPdfArray } static void skpdfGraphicsStateApplySMask_dict(SkPdfContext* pdfContext, SkPdfDictionary* sMask) { - // TODO(edisonn): verify input + if (!sMask || !sMask->isName()) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, sMask, SkPdfNativeObject::kArray_PdfObjectType, pdfContext); + return; + } + if (pdfContext->fPdfDoc->mapper()->mapSoftMaskDictionary(sMask)) { pdfContext->fGraphicsState.fSoftMaskDictionary = (SkPdfSoftMaskDictionary*)sMask; } else if (pdfContext->fPdfDoc->mapper()->mapSoftMaskImageDictionary(sMask)) { SkPdfSoftMaskImageDictionary* smid = (SkPdfSoftMaskImageDictionary*)sMask; pdfContext->fGraphicsState.fSMask = getImageFromObject(pdfContext, smid, true); } else { - // TODO (edisonn): report error/warning + // TODO(edisonn): make the dictionary types an enum? + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "Dictionary must be SoftMask, or SoftMaskImage", sMask, SkPdfNativeObject::kDictionary_PdfObjectType, pdfContext); } } @@ -2233,16 +2337,13 @@ static void skpdfGraphicsStateApplySMask_name(SkPdfContext* pdfContext, const Sk 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 + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kMissingExtGState_SkPdfIssue, NULL, pdfContext->fGraphicsState.fResources, pdfContext); return; } SkPdfNativeObject* obj = pdfContext->fPdfDoc->resolveReference(extGStateDictionary->get(sMask.c_str())); if (!obj || !obj->isDictionary()) { - // TODO (edisonn): report error/warning + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, obj, SkPdfNativeObject::kDictionary_PdfObjectType, pdfContext); return; } @@ -2260,7 +2361,7 @@ static void skpdfGraphicsStateApplyAIS(SkPdfContext* pdfContext, bool alphaSourc //dictName gs (PDF 1.2) Set the specified parameters in the graphics state. dictName is //the name of a graphics state parameter dictionary in the ExtGState subdictionary of the current resource dictionary (see the next section). static SkPdfResult PdfOp_gs(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 1); + EXPECT_OPERANDS("gs", pdfContext, 1); POP_NAME(pdfContext, name); CHECK_PARAMETERS(); @@ -2272,9 +2373,7 @@ static SkPdfResult PdfOp_gs(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken SkPdfDictionary* extGStateDictionary = pdfContext->fGraphicsState.fResources->ExtGState(pdfContext->fPdfDoc); if (extGStateDictionary == NULL) { -#ifdef PDF_TRACE - printf("ExtGState is NULL!\n"); -#endif + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kMissingExtGState_SkPdfIssue, NULL, pdfContext->fGraphicsState.fResources, pdfContext); return kIgnoreError_SkPdfResult; } @@ -2287,6 +2386,7 @@ static SkPdfResult PdfOp_gs(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken // TODO(edisonn): now load all those properties in graphic state. if (gs == NULL) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, gs, SkPdfNativeObject::kDictionary_PdfObjectType, pdfContext); return kIgnoreError_SkPdfResult; } @@ -2320,7 +2420,7 @@ static SkPdfResult PdfOp_gs(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken } else if (gs->isBMAArray(pdfContext->fPdfDoc)) { skpdfGraphicsStateApplyBM_array(pdfContext, gs->getBMAsArray(pdfContext->fPdfDoc)); } else { - // TODO(edisonn): report/warn + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "wrong type", gs->get("BM"), SkPdfNativeObject::kArray_PdfObjectType || SkPdfNativeObject::kName_PdfObjectType, pdfContext); } } @@ -2330,7 +2430,7 @@ static SkPdfResult PdfOp_gs(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken } else if (gs->isSMaskADictionary(pdfContext->fPdfDoc)) { skpdfGraphicsStateApplySMask_dict(pdfContext, gs->getSMaskAsDictionary(pdfContext->fPdfDoc)); } else { - // TODO(edisonn): report/warn + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "wrong type", gs->get("BM"), SkPdfNativeObject::kDictionary_PdfObjectType || SkPdfNativeObject::kName_PdfObjectType, pdfContext); } } @@ -2353,7 +2453,7 @@ static SkPdfResult PdfOp_gs(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken //, to charSpace, which is a number expressed in unscaled text space units. Character spacing is used by the Tj, TJ, and ' operators. //Initial value: 0. SkPdfResult PdfOp_Tc(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 1); + EXPECT_OPERANDS("Tc", pdfContext, 1); POP_NUMBER(pdfContext, charSpace); CHECK_PARAMETERS(); @@ -2368,7 +2468,7 @@ SkPdfResult PdfOp_Tc(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper* //text space units. Word spacing is used by the Tj, TJ, and ' operators. Initial //value: 0. SkPdfResult PdfOp_Tw(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 1); + EXPECT_OPERANDS("Tw", pdfContext, 1); POP_NUMBER(pdfContext, wordSpace); CHECK_PARAMETERS(); @@ -2381,11 +2481,12 @@ SkPdfResult PdfOp_Tw(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper* //, to (scale ˜ 100). scale is a number specifying the //percentage of the normal width. Initial value: 100 (normal width). static SkPdfResult PdfOp_Tz(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 1); + EXPECT_OPERANDS("Tz", pdfContext, 1); POP_NUMBER(pdfContext, scale); CHECK_PARAMETERS(); if (scale < 0) { + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kOutOfRange_SkPdfIssue, "scale must a positive real number", scale_obj, pdfContext); return kError_SkPdfResult; } @@ -2395,11 +2496,12 @@ static SkPdfResult PdfOp_Tz(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken //render Tr Set the text rendering mode, T //mode, to render, which is an integer. Initial value: 0. static SkPdfResult PdfOp_Tr(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 1); + EXPECT_OPERANDS("Tr", pdfContext, 1); POP_INTEGER(pdfContext, mode); CHECK_PARAMETERS(); if (mode < 0) { // TODO(edisonn): function/enums with supported modes + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kOutOfRange_SkPdfIssue, "mode must a positive integer or 0", mode_obj, pdfContext); return kError_SkPdfResult; } @@ -2408,11 +2510,12 @@ static SkPdfResult PdfOp_Tr(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken //rise Ts Set the text rise, Trise, to rise, which is a number expressed in unscaled text space //units. Initial value: 0. static SkPdfResult PdfOp_Ts(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 1); + EXPECT_OPERANDS("Ts", pdfContext, 1); POP_NUMBER(pdfContext, rise); CHECK_PARAMETERS(); if (rise < 0) { + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kOutOfRange_SkPdfIssue, "rise must a positive real number", rise_obj, pdfContext); return kNYI_SkPdfResult; } @@ -2421,12 +2524,18 @@ static SkPdfResult PdfOp_Ts(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken //wx wy d0 static SkPdfResult PdfOp_d0(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 2); + EXPECT_OPERANDS("d0", pdfContext, 2); POP_NUMBER(pdfContext, wy); POP_NUMBER(pdfContext, wx); CHECK_PARAMETERS(); - if (wx < 0 || wy < 0) { + if (wx < 0) { + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kOutOfRange_SkPdfIssue, "wx must a positive real number", wx_obj, pdfContext); + return kError_SkPdfResult; + } + + if (wy < 0) { + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kOutOfRange_SkPdfIssue, "wy must a positive real number", wy_obj, pdfContext); return kError_SkPdfResult; } @@ -2435,7 +2544,7 @@ static SkPdfResult PdfOp_d0(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken //wx wy llx lly urx ury d1 static SkPdfResult PdfOp_d1(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 6); + EXPECT_OPERANDS("d1", pdfContext, 6); POP_NUMBER(pdfContext, ury); POP_NUMBER(pdfContext, urx); POP_NUMBER(pdfContext, lly); @@ -2444,6 +2553,7 @@ static SkPdfResult PdfOp_d1(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken POP_NUMBER(pdfContext, wx); CHECK_PARAMETERS(); + // TODO(edisonn): silly way to remove warning if (wx + wy + llx + lly + urx + ury) { return kNYI_SkPdfResult; } @@ -2453,11 +2563,12 @@ static SkPdfResult PdfOp_d1(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken //name sh static SkPdfResult PdfOp_sh(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 1); + EXPECT_OPERANDS("sh", pdfContext, 1); POP_NAME(pdfContext, name); CHECK_PARAMETERS(); if (name == NULL) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, name, SkPdfNativeObject::kName_PdfObjectType, pdfContext); return kError_SkPdfResult; } @@ -2466,41 +2577,36 @@ static SkPdfResult PdfOp_sh(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken //name Do static SkPdfResult PdfOp_Do(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 1); + EXPECT_OPERANDS("Do", pdfContext, 1); POP_NAME(pdfContext, name); CHECK_PARAMETERS(); SkPdfDictionary* xObject = pdfContext->fGraphicsState.fResources->XObject(pdfContext->fPdfDoc); if (xObject == NULL) { -#ifdef PDF_TRACE - printf("XObject is NULL!\n"); -#endif + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kMissingXObject_SkPdfIssue, NULL, pdfContext->fGraphicsState.fResources, pdfContext); return kIgnoreError_SkPdfResult; } SkPdfNativeObject* value = xObject->get(name); value = pdfContext->fPdfDoc->resolveReference(value); -#ifdef PDF_TRACE -// value->ToString(str); -// printf("Do object value: %s\n", str); -#endif - return doXObject(pdfContext, canvas, value); } //tag MP Designate a marked-content point. tag is a name object indicating the role or //significance of the point. static SkPdfResult PdfOp_MP(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 1); + EXPECT_OPERANDS("MP", pdfContext, 1); POP_OBJ(pdfContext, tag); CHECK_PARAMETERS(); if (tag == NULL) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, tag, SkPdfNativeObject::_kObject_PdfObjectType, pdfContext); return kNYI_SkPdfResult; } + SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "MP NYI", NULL, NULL); return kNYI_SkPdfResult; } @@ -2510,29 +2616,38 @@ static SkPdfResult PdfOp_MP(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToken //associated with it in the Properties subdictionary of the current resource //dictionary (see Section 9.5.1, “Property Lists”). static SkPdfResult PdfOp_DP(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 2); + EXPECT_OPERANDS("DP", pdfContext, 2); POP_OBJ(pdfContext, properties); POP_OBJ(pdfContext, tag); CHECK_PARAMETERS(); - if (tag == NULL || properties == NULL) { + if (tag == NULL) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, tag, SkPdfNativeObject::_kObject_PdfObjectType, pdfContext); + return kNYI_SkPdfResult; + } + + if (properties == NULL) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, properties, SkPdfNativeObject::_kObject_PdfObjectType, pdfContext); return kNYI_SkPdfResult; } + SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "DP NYI", NULL, NULL); return kNYI_SkPdfResult; } //tag BMC Begin a marked-content sequence terminated by a balancing EMC operator. //tag is a name object indicating the role or significance of the sequence. static SkPdfResult PdfOp_BMC(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 1); + EXPECT_OPERANDS("BMC", pdfContext, 1); POP_OBJ(pdfContext, tag); CHECK_PARAMETERS(); if (tag == NULL) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, tag, SkPdfNativeObject::_kObject_PdfObjectType, pdfContext); return kNYI_SkPdfResult; } + SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "BMC NYI", NULL, NULL); return kNYI_SkPdfResult; } @@ -2540,20 +2655,28 @@ static SkPdfResult PdfOp_BMC(SkPdfContext* pdfContext, SkCanvas* canvas, PdfToke //by a balancing EMCoperator. tag is a name object indicating the role or significance of the sequence; propertiesis either an inline dictionary containing the //property list or a name object associated with it in the Properties subdictionary of the current resource dictionary (see Section 9.5.1, “Property Lists”). static SkPdfResult PdfOp_BDC(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { - EXPECT_OPERANDS(pdfContext, 2); + EXPECT_OPERANDS("BDC", pdfContext, 2); POP_OBJ(pdfContext, properties); POP_OBJ(pdfContext, tag); CHECK_PARAMETERS(); - if (tag == NULL || properties == NULL) { + if (tag == NULL) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, tag, SkPdfNativeObject::_kObject_PdfObjectType, pdfContext); + return kNYI_SkPdfResult; + } + + if (properties == NULL) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, NULL, properties, SkPdfNativeObject::_kObject_PdfObjectType, pdfContext); return kNYI_SkPdfResult; } + SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "BDC NYI", NULL, NULL); return kNYI_SkPdfResult; } //— EMC End a marked-content sequence begun by a BMC or BDC operator. static SkPdfResult PdfOp_EMC(SkPdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) { + SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "EMC NYI", NULL, NULL); return kNYI_SkPdfResult; } @@ -2705,7 +2828,8 @@ SkPdfResult PdfMainLooper::consumeToken(PdfToken& token) { fPdfContext->fObjectStack.push( token.fObject ); } else { - // TODO(edisonn): deine or use assert not reached + // TODO(edisonn): store the keyword as a object, so we can track the location in file, and report it + SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, token.fKeyword, NULL, fPdfContext); return kIgnoreError_SkPdfResult; } return kOK_SkPdfResult; diff --git a/experimental/PdfViewer/SkPdfRenderer.h b/experimental/PdfViewer/SkPdfRenderer.h index df8f56c005..0a37c6024f 100644 --- a/experimental/PdfViewer/SkPdfRenderer.h +++ b/experimental/PdfViewer/SkPdfRenderer.h @@ -9,11 +9,17 @@ #ifndef SkPdfRenderer_DEFINED #define SkPdfRenderer_DEFINED +// TODO(edisonn): how to remove this dependency? Should I remove the ref counting? +#include "SkRefCnt.h" +// TODO(edisonn): remove this dependency +#include "SkString.h" + class SkBitmap; class SkCanvas; class SkPdfNativeDoc; struct SkRect; class SkStream; +class SkString; enum SkPdfContent { kNoForms_SkPdfContent, diff --git a/experimental/PdfViewer/pdfparser/native/SkPdfNativeDoc.cpp b/experimental/PdfViewer/pdfparser/native/SkPdfNativeDoc.cpp index f278ea1a2e..ef5276bf30 100644 --- a/experimental/PdfViewer/pdfparser/native/SkPdfNativeDoc.cpp +++ b/experimental/PdfViewer/pdfparser/native/SkPdfNativeDoc.cpp @@ -8,6 +8,7 @@ #include "SkPdfNativeDoc.h" #include "SkPdfNativeTokenizer.h" #include "SkPdfNativeObject.h" +#include "SkPdfReporter.h" #include <stdio.h> #include <string.h> @@ -107,7 +108,7 @@ SkPdfNativeDoc::SkPdfNativeDoc(const char* path) fclose(file); if (!ok) { sk_free(content); - // TODO(edisonn): report read error + SkPdfReport(kFatalError_SkPdfIssueSeverity, kReadStreamError_SkPdfIssue, "could not read file", NULL, NULL); // TODO(edisonn): not nice to return like this from constructor, create a static // function that can report NULL for failures. return; // Doc will have 0 pages @@ -125,7 +126,7 @@ void SkPdfNativeDoc::init(const void* bytes, size_t length) { const unsigned char* xrefstartKeywordLine = previousLineHome(fFileContent, xrefByteOffsetLine); if (strcmp((char*)xrefstartKeywordLine, "startxref") != 0) { - // TODO(edisonn): report/issue + SkPdfReport(kWarning_SkPdfIssueSeverity, kMissingToken_SkPdfIssue, "Could not find startxref", NULL, NULL); } long xrefByteOffset = atol((const char*)xrefByteOffsetLine); @@ -189,6 +190,7 @@ void SkPdfNativeDoc::loadWithoutXRef() { current = nextObject(0, current, end, &token, NULL, NULL PUT_TRACK_STREAM_ARGS_EXPL2(0, fFileContent)); // TODO(edisonn): must be obj, return error if not? ignore ? if (!token.isKeyword("obj")) { + SkPdfReport(kWarning_SkPdfIssueSeverity, kMissingToken_SkPdfIssue, "Could not find obj", NULL, NULL); continue; } @@ -203,6 +205,8 @@ void SkPdfNativeDoc::loadWithoutXRef() { fObjects[id].fResolvedReference = obj; fObjects[id].fObj = obj; + fObjects[id].fIsReferenceResolved = true; + // set objects } else if (token.isKeyword("trailer")) { @@ -227,7 +231,6 @@ void SkPdfNativeDoc::loadWithoutXRef() { } } - if (fRootCatalogRef) { fRootCatalog = (SkPdfCatalogDictionary*)resolveReference(fRootCatalogRef); if (fRootCatalog->isDictionary() && fRootCatalog->valid()) { @@ -252,6 +255,7 @@ const unsigned char* SkPdfNativeDoc::readCrossReferenceSection(const unsigned ch const unsigned char* current = nextObject(0, xrefStart, trailerEnd, &xref, NULL, NULL PUT_TRACK_STREAM_ARGS_EXPL2(0, fFileContent)); if (!xref.isKeyword("xref")) { + SkPdfReport(kWarning_SkPdfIssueSeverity, kMissingToken_SkPdfIssue, "Could not find sref", NULL, NULL); return trailerEnd; } @@ -261,6 +265,7 @@ const unsigned char* SkPdfNativeDoc::readCrossReferenceSection(const unsigned ch const unsigned char* previous = current; current = nextObject(0, current, trailerEnd, &token, NULL, NULL PUT_TRACK_STREAM_ARGS_EXPL2(0, fFileContent)); if (!token.isInteger()) { + SkPdfReport(kInfo_SkPdfIssueSeverity, kNoIssue_SkPdfIssue, "Done readCrossReferenceSection", NULL, NULL); return previous; } @@ -269,7 +274,7 @@ const unsigned char* SkPdfNativeDoc::readCrossReferenceSection(const unsigned ch current = nextObject(0, current, trailerEnd, &token, NULL, NULL PUT_TRACK_STREAM_ARGS_EXPL2(0, fFileContent)); if (!token.isInteger()) { - // TODO(edisonn): report/warning + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "readCrossReferenceSection", &token, SkPdfNativeObject::kInteger_PdfObjectType, NULL); return current; } @@ -279,7 +284,7 @@ const unsigned char* SkPdfNativeDoc::readCrossReferenceSection(const unsigned ch token.reset(); current = nextObject(0, current, trailerEnd, &token, NULL, NULL PUT_TRACK_STREAM_ARGS_EXPL2(0, fFileContent)); if (!token.isInteger()) { - // TODO(edisonn): report/warning + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "readCrossReferenceSection", &token, SkPdfNativeObject::kInteger_PdfObjectType, NULL); return current; } int offset = (int)token.intValue(); @@ -287,7 +292,7 @@ const unsigned char* SkPdfNativeDoc::readCrossReferenceSection(const unsigned ch token.reset(); current = nextObject(0, current, trailerEnd, &token, NULL, NULL PUT_TRACK_STREAM_ARGS_EXPL2(0, fFileContent)); if (!token.isInteger()) { - // TODO(edisonn): report/warning + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "readCrossReferenceSection", &token, SkPdfNativeObject::kInteger_PdfObjectType, NULL); return current; } int generation = (int)token.intValue(); @@ -295,14 +300,14 @@ const unsigned char* SkPdfNativeDoc::readCrossReferenceSection(const unsigned ch token.reset(); current = nextObject(0, current, trailerEnd, &token, NULL, NULL PUT_TRACK_STREAM_ARGS_EXPL2(0, fFileContent)); if (!token.isKeyword() || token.lenstr() != 1 || (*token.c_str() != 'f' && *token.c_str() != 'n')) { - // TODO(edisonn): report/warning + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "readCrossReferenceSection: f or n expected", &token, SkPdfNativeObject::kKeyword_PdfObjectType, NULL); return current; } addCrossSectionInfo(startId + i, generation, offset, *token.c_str() == 'f'); } } - // TODO(edisonn): it should never get here? there is no trailer? + SkPdfReport(kInfo_SkPdfIssueSeverity, kNoIssue_SkPdfIssue, "Unexpected end of readCrossReferenceSection", NULL, NULL); return current; } @@ -319,6 +324,7 @@ const unsigned char* SkPdfNativeDoc::readTrailer(const unsigned char* trailerSta if (!trailerKeyword.isKeyword() || strlen("trailer") != trailerKeyword.lenstr() || strncmp(trailerKeyword.c_str(), "trailer", strlen("trailer")) != 0) { // TODO(edisonn): report warning, rebuild trailer from objects. + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "readTrailer: trailer keyword expected", &trailerKeyword, SkPdfNativeObject::kKeyword_PdfObjectType, NULL); return current; } } @@ -336,7 +342,7 @@ const unsigned char* SkPdfNativeDoc::readTrailer(const unsigned char* trailerSta if (storeCatalog) { SkPdfNativeObject* ref = trailer->Root(NULL); if (ref == NULL || !ref->isReference()) { - // TODO(edisonn): oops, we have to fix the corrup pdf file + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "readTrailer: unexpected root reference", ref, SkPdfNativeObject::kReference_PdfObjectType, NULL); return current; } fRootCatalogRef = ref; @@ -381,28 +387,33 @@ SkPdfNativeObject* SkPdfNativeDoc::readObject(int id/*, int expectedGeneration*/ current = nextObject(0, current, end, &idObj, NULL, NULL PUT_TRACK_STREAM_ARGS_EXPL2(0, fFileContent)); if (current >= end) { - // TODO(edisonn): report warning/error + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kReadStreamError_SkPdfIssue, "reading id", NULL, NULL); return NULL; } current = nextObject(0, current, end, &generationObj, NULL, NULL PUT_TRACK_STREAM_ARGS_EXPL2(0, fFileContent)); if (current >= end) { - // TODO(edisonn): report warning/error + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kReadStreamError_SkPdfIssue, "reading generation", NULL, NULL); return NULL; } current = nextObject(0, current, end, &objKeyword, NULL, NULL PUT_TRACK_STREAM_ARGS_EXPL2(0, fFileContent)); if (current >= end) { - // TODO(edisonn): report warning/error + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kReadStreamError_SkPdfIssue, "reading keyword obj", NULL, NULL); return NULL; } - if (!idObj.isInteger() || !generationObj.isInteger() || id != idObj.intValue()/* || generation != generationObj.intValue()*/) { - // TODO(edisonn): report warning/error + if (!idObj.isInteger() || id != idObj.intValue()) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "readObject: unexpected id", &idObj, SkPdfNativeObject::kInteger_PdfObjectType, NULL); + } + + // TODO(edisonn): verify that the generation is the right one + if (!generationObj.isInteger() /* || generation != generationObj.intValue()*/) { + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "readObject: unexpected generation", &generationObj, SkPdfNativeObject::kInteger_PdfObjectType, NULL); } if (!objKeyword.isKeyword() || strcmp(objKeyword.c_str(), "obj") != 0) { - // TODO(edisonn): report warning/error + SkPdfReportUnexpectedType(kIgnoreError_SkPdfIssueSeverity, "readObject: unexpected obj keyword", &objKeyword, SkPdfNativeObject::kKeyword_PdfObjectType, NULL); } current = nextObject(1, current, end, dict, fAllocator, this PUT_TRACK_STREAM_ARGS_EXPL2(0, fFileContent)); @@ -543,7 +554,7 @@ SkPdfNativeObject* SkPdfNativeDoc::resolveReference(SkPdfNativeObject* ref) { // TODO(edisonn): verify id and gen expected if (id < 0 || id >= fObjects.count()) { - // TODO(edisonn): report error/warning + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kReadStreamError_SkPdfIssue, "resolve reference id out of bounds", NULL, NULL); return NULL; } @@ -553,7 +564,7 @@ SkPdfNativeObject* SkPdfNativeDoc::resolveReference(SkPdfNativeObject* ref) { 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 + SkPdfReportIf(!fObjects[id].fResolvedReference, kIgnoreError_SkPdfIssueSeverity, kBadReference_SkPdfIssue, "ref is NULL", NULL, NULL); return fObjects[id].fResolvedReference; } diff --git a/experimental/PdfViewer/pdfparser/native/SkPdfNativeObject.cpp b/experimental/PdfViewer/pdfparser/native/SkPdfNativeObject.cpp index 54daf17275..73f765d3c7 100644 --- a/experimental/PdfViewer/pdfparser/native/SkPdfNativeObject.cpp +++ b/experimental/PdfViewer/pdfparser/native/SkPdfNativeObject.cpp @@ -18,11 +18,13 @@ #include "SkBitmap.h" #include "SkPdfFont.h" +#include "SkPdfReporter.h" + SkPdfNativeObject SkPdfNativeObject::kNull = SkPdfNativeObject::makeNull(PUT_TRACK_PARAMETERS_SRC0); bool SkPdfNativeObject::applyFlateDecodeFilter() { if (!SkFlate::HaveFlate()) { - // TODO(edisonn): warn, make callers handle it + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kNoFlateLibrary_SkPdfIssue, "forgot to link with flate library?", NULL, NULL); return false; } @@ -43,7 +45,7 @@ bool SkPdfNativeObject::applyFlateDecodeFilter() { return true; } else { - // TODO(edisonn): warn, make callers handle it + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kBadStream_SkPdfIssue, "inflate failed", this, NULL); return false; } } @@ -61,7 +63,7 @@ bool SkPdfNativeObject::applyFilter(const char* name) { } else if (strcmp(name, "DCTDecode") == 0) { return applyDCTDecodeFilter(); } - // TODO(edisonn): allert, not supported, but should be implemented asap + SkPdfReport(kCodeWarning_SkPdfIssueSeverity, kNYI_SkPdfIssue, "filter not supported", this, NULL); return false; } @@ -69,6 +71,7 @@ bool SkPdfNativeObject::filterStream() { SkPdfMarkObjectUsed(); if (!hasStream()) { + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kBadStream_SkPdfIssue, "No Stream", this, NULL); return false; } @@ -93,7 +96,7 @@ bool SkPdfNativeObject::filterStream() { break; } } else { - // TODO(edisonn): report warning + SkPdfReport(kIgnoreError_SkPdfIssueSeverity, kIncositentSyntax_SkPdfIssue, "filter name should be a Name", this, NULL); } } } @@ -102,7 +105,9 @@ bool SkPdfNativeObject::filterStream() { } void SkPdfNativeObject::releaseData() { - // TODO(edisonn): report here unused objects +#ifdef PDF_TRACK_OBJECT_USAGE + SkPdfReportIf(!fUsed, kInfo_SkPdfIssueSeverity, NULL, this, "Unused object in rendering"); +#endif // PDF_TRACK_OBJECT_USAGE SkPdfMarkObjectUnused(); diff --git a/experimental/PdfViewer/pdfparser/native/SkPdfNativeObject.h b/experimental/PdfViewer/pdfparser/native/SkPdfNativeObject.h index 344d6c668d..94c0547c22 100644 --- a/experimental/PdfViewer/pdfparser/native/SkPdfNativeObject.h +++ b/experimental/PdfViewer/pdfparser/native/SkPdfNativeObject.h @@ -38,25 +38,31 @@ SkMatrix SkMatrixFromPdfMatrix(double array[6]); class SkPdfNativeObject { public: enum ObjectType { - kInvalid_PdfObjectType, - - kBoolean_PdfObjectType, - kInteger_PdfObjectType, - kReal_PdfObjectType, - kString_PdfObjectType, - kHexString_PdfObjectType, - kName_PdfObjectType, - kKeyword_PdfObjectType, - //kStream_PdfObjectType, // attached to a Dictionary - kArray_PdfObjectType, - kDictionary_PdfObjectType, - kNull_PdfObjectType, + // The type will have only one of these values, but for error reporting, we make it an enum + // so it can easily report that something was expected to be one of a few types + kInvalid_PdfObjectType = 1 << 1, + + kBoolean_PdfObjectType = 1 << 2, + kInteger_PdfObjectType = 1 << 3, + kReal_PdfObjectType = 1 << 4, + _kNumber_PdfObjectType = kInteger_PdfObjectType | kReal_PdfObjectType, + kString_PdfObjectType = 1 << 5, + kHexString_PdfObjectType = 1 << 6, + _kAnyString_PdfObjectType = kString_PdfObjectType | kHexString_PdfObjectType, + kName_PdfObjectType = 1 << 7, + kKeyword_PdfObjectType = 1 << 8, + _kStream_PdfObjectType = 1 << 9, // attached to a Dictionary, do not use + kArray_PdfObjectType = 1 << 10, + kDictionary_PdfObjectType = 1 << 11, + kNull_PdfObjectType = 1 << 12, // TODO(edisonn): after the pdf has been loaded completely, resolve all references // try the same thing with delayed loaded ... - kReference_PdfObjectType, + kReference_PdfObjectType = 1 << 13, - kUndefined_PdfObjectType, // per 1.4 spec, if the same key appear twice in the dictionary, the value is undefined + kUndefined_PdfObjectType = 1 << 14, // per 1.4 spec, if the same key appear twice in the dictionary, the value is undefined + + _kObject_PdfObjectType = -1, }; enum DataType { diff --git a/experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp b/experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp index 4e0e4c404a..64388552a5 100644 --- a/experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp +++ b/experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp @@ -811,11 +811,15 @@ const unsigned char* nextObject(int level, const unsigned char* start, const uns // skip white spaces start = skipPdfWhiteSpaces(level, start, end); + if (start >= end) { + return end; + } + current = endOfPdfToken(level, start, end); // no token, len would be 0 - if (current == start) { - return NULL; + if (current == start || current == end) { + return end; } int tokenLen = current - start; |