diff options
Diffstat (limited to 'experimental/PdfViewer')
-rw-r--r-- | experimental/PdfViewer/SkPdfBasics.cpp | 7 | ||||
-rw-r--r-- | experimental/PdfViewer/SkPdfRenderer.cpp | 97 | ||||
-rw-r--r-- | experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp | 2 | ||||
-rw-r--r-- | experimental/PdfViewer/pdfparser/native/SkPdfObject.h | 3 | ||||
-rw-r--r-- | experimental/PdfViewer/spec2def.py | 2 |
5 files changed, 97 insertions, 14 deletions
diff --git a/experimental/PdfViewer/SkPdfBasics.cpp b/experimental/PdfViewer/SkPdfBasics.cpp index dc320a581c..497966792e 100644 --- a/experimental/PdfViewer/SkPdfBasics.cpp +++ b/experimental/PdfViewer/SkPdfBasics.cpp @@ -28,8 +28,13 @@ void SkPdfGraphicsState::applyGraphicsState(SkPaint* paint, bool stroking) { paint->setStrokeWidth(SkDoubleToScalar(fLineWidth)); // TODO(edisonn): perf, two sets of allocs, create SkDashPathEffect constr that takes ownership // of the intervals - if (fDashArrayLength > 0 && fDashPhase > 0) { + if (fDashArrayLength > 0) { paint->setPathEffect(new SkDashPathEffect(fDashArray, fDashArrayLength, fDashPhase))->unref(); } } + + // TODO(edisonn): NYI multiple blend modes + if (fBlendModesLength == 1 && fBlendModes[0] != SkXfermode::kSrc_Mode) { + paint->setXfermodeMode(fBlendModes[0]); + } } diff --git a/experimental/PdfViewer/SkPdfRenderer.cpp b/experimental/PdfViewer/SkPdfRenderer.cpp index 2f0f85b584..f9ced8807d 100644 --- a/experimental/PdfViewer/SkPdfRenderer.cpp +++ b/experimental/PdfViewer/SkPdfRenderer.cpp @@ -634,11 +634,73 @@ static PdfResult doXObject_Image(PdfContext* pdfContext, SkCanvas* canvas, SkPdf return kPartial_PdfResult; } +//TODO(edisonn): options for implementing isolation and knockout +// 1) emulate them (current solution) +// PRO: simple +// CON: will need to use readPixels, which means serious perf issues +// 2) Compile a plan for an array of matrixes, compose the result at the end +// PRO: might be faster then 1, no need to readPixels +// CON: multiple drawings (but on smaller areas), pay a price at loading pdf to compute a pdf draw plan +// on average, a load with empty draw is 100ms on all the skps we have, for complete sites +// 3) support them natively in SkCanvas +// PRO: simple +// CON: we would still need to use a form of readPixels anyway, so perf might be the same as 1) +// 4) compile a plan using pathops, and render once without any fancy rules with backdrop +// PRO: simple, fast +// CON: pathops must be bug free first + time to compute new paths +// pay a price at loading pdf to compute a pdf draw plan +// on average, a load with empty draw is 100ms on all the skps we have, for complete sites + + +// TODO(edisonn): draw plan from point! - list of draw ops of a point, like a tree! +// TODO(edisonn): Minimal PDF to draw some points - remove everything that it is not needed, save pdf uncompressed + + + +static void doGroup_before(PdfContext* pdfContext, SkCanvas* canvas, SkRect bbox, SkPdfTransparencyGroupDictionary* tgroup, bool page) { + SkRect bboxOrig = bbox; + SkBitmap backdrop; + bool isolatedGroup = tgroup->I(pdfContext->fPdfDoc); +// bool knockoutGroup = tgroup->K(pdfContext->fPdfDoc); + bool hasPixels = false; + if (!isolatedGroup) { + // TODO(edisonn): if the rect is not mapable, the operation could be expensive, e.g. + // a diagonal long but small rect would require to save all the page + SkMatrix inverse; + if (pdfContext->fGraphicsState.fCTM.mapRect(&bbox) && + canvas->getTotalMatrix().invert(&inverse) && + inverse.mapRect(&bbox)) { + SkIRect area = SkIRect::MakeLTRB(SkScalarTruncToInt(bbox.left()), + SkScalarTruncToInt(bbox.top()), + SkScalarTruncToInt(bbox.right()) + 2, + SkScalarTruncToInt(bbox.bottom()) + 2); + SkBitmap dummy; + if (canvas->readPixels(area, &dummy)) { + hasPixels = true; + } + } + } + SkPaint paint; + pdfContext->fGraphicsState.applyGraphicsState(&paint, false); + canvas->saveLayer(&bboxOrig, isolatedGroup ? &paint : NULL); + + if (hasPixels) { + canvas->drawBitmapRect(backdrop, bboxOrig, NULL); + } +} + +//static void doGroup_after(PdfContext* pdfContext, SkCanvas* canvas, SkRect bbox, SkPdfTransparencyGroupDictionary* tgroup) { +//} + static PdfResult doXObject_Form(PdfContext* pdfContext, SkCanvas* canvas, SkPdfType1FormDictionary* skobj) { if (!skobj || !skobj->hasStream()) { return kIgnoreError_PdfResult; } + if (!skobj->has_BBox()) { + return kIgnoreError_PdfResult; + } + PdfOp_q(pdfContext, canvas, NULL); @@ -663,16 +725,16 @@ static PdfResult doXObject_Form(PdfContext* pdfContext, SkCanvas* canvas, SkPdfT canvas->setMatrix(pdfContext->fGraphicsState.fCTM); - if (skobj->has_BBox()) { - canvas->clipRect(skobj->BBox(pdfContext->fPdfDoc), SkRegion::kIntersect_Op, true); // TODO(edisonn): AA from settings. - } + SkRect bbox = skobj->BBox(pdfContext->fPdfDoc); + canvas->clipRect(bbox, SkRegion::kIntersect_Op, true); // TODO(edisonn): AA from settings. // 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* ... + SkPdfTransparencyGroupDictionary* tgroup = skobj->Group(pdfContext->fPdfDoc); + doGroup_before(pdfContext, canvas, bbox, tgroup, false); } SkPdfStream* stream = (SkPdfStream*)skobj; @@ -687,6 +749,11 @@ static PdfResult doXObject_Form(PdfContext* pdfContext, SkCanvas* canvas, SkPdfT // TODO(edisonn): should we restore the variable stack at the same state? // There could be operands left, that could be consumed by a parent tokenizer when we pop. + + if (skobj->has_Group()) { + canvas->restore(); + } + canvas->restore(); PdfOp_Q(pdfContext, canvas, NULL); return kPartial_PdfResult; @@ -808,18 +875,21 @@ static PdfResult doPage(PdfContext* pdfContext, SkCanvas* canvas, SkPdfPageObjec PdfOp_q(pdfContext, canvas, NULL); - canvas->save(); if (skobj->Resources(pdfContext->fPdfDoc)) { pdfContext->fGraphicsState.fResources = skobj->Resources(pdfContext->fPdfDoc); } - // TODO(edisonn): refactor common path with doXObject() - // This is a group? + // TODO(edisonn): MediaBox can be inherited!!!! + SkRect bbox = skobj->MediaBox(pdfContext->fPdfDoc); if (skobj->has_Group()) { - //TransparencyGroupDictionary* ... + SkPdfTransparencyGroupDictionary* tgroup = skobj->Group(pdfContext->fPdfDoc); + doGroup_before(pdfContext, canvas, bbox, tgroup, true); + } else { + canvas->save(); } + SkPdfNativeTokenizer* tokenizer = pdfContext->fPdfDoc->tokenizerOfStream(stream, pdfContext->fTmpPageAllocator); if (tokenizer != NULL) { @@ -1582,12 +1652,21 @@ PdfResult skpdfGraphicsStateApplyD(PdfContext* pdfContext, SkPdfArray* intervals } } - pdfContext->fGraphicsState.fDashArrayLength = cnt; double total = 0; for (int i = 0 ; i < cnt; i++) { pdfContext->fGraphicsState.fDashArray[i] = intervals->objAtAIndex(i)->scalarValue(); total += pdfContext->fGraphicsState.fDashArray[i]; } + if (cnt & 1) { + if (cnt == 1) { + pdfContext->fGraphicsState.fDashArray[1] = pdfContext->fGraphicsState.fDashArray[0]; + cnt++; + } else { + // TODO(edisonn): report error/warning + return kNYI_PdfResult; + } + } + pdfContext->fGraphicsState.fDashArrayLength = cnt; pdfContext->fGraphicsState.fDashPhase = phase->scalarValue(); if (pdfContext->fGraphicsState.fDashPhase == 0) { // other rules, changes? diff --git a/experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp b/experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp index 09b7a0b3a8..9ec5cc0925 100644 --- a/experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp +++ b/experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp @@ -855,7 +855,7 @@ const unsigned char* nextObject(int level, const unsigned char* start, const uns return current; } - if (tokenLen == 5 && start[0] == 'f' && start[1] == 'a' && start[2] == 'l' && start[3] == 's' && start[3] == 'e') { + if (tokenLen == 5 && start[0] == 'f' && start[1] == 'a' && start[2] == 'l' && start[3] == 's' && start[4] == 'e') { SkPdfObject::makeBoolean(false, token); return current; } diff --git a/experimental/PdfViewer/pdfparser/native/SkPdfObject.h b/experimental/PdfViewer/pdfparser/native/SkPdfObject.h index 9ac9a12509..5d86d9b8ad 100644 --- a/experimental/PdfViewer/pdfparser/native/SkPdfObject.h +++ b/experimental/PdfViewer/pdfparser/native/SkPdfObject.h @@ -169,7 +169,6 @@ public: return nyi; } - static void makeBoolean(bool value, SkPdfObject* obj) { SkASSERT(obj->fObjectType == kInvalid_PdfObjectType); @@ -703,7 +702,7 @@ public: inline bool boolValue() const { SkASSERT(fObjectType == kBoolean_PdfObjectType); - if (fObjectType == kBoolean_PdfObjectType) { + if (fObjectType != kBoolean_PdfObjectType) { // TODO(edisonn): log err return false; } diff --git a/experimental/PdfViewer/spec2def.py b/experimental/PdfViewer/spec2def.py index f1ab8a7f16..8f02ab8aca 100644 --- a/experimental/PdfViewer/spec2def.py +++ b/experimental/PdfViewer/spec2def.py @@ -118,7 +118,7 @@ tableToClassName = { 'TABLE 6.7': ['Type5HalftoneDictionary', 'Entries in a type 5 halftone dictionary'], 'TABLE 7.10': ['SoftMaskDictionary', 'Entries in a soft-mask dictionary', '', {'S': '[datatypes.PdfName(\'Alpha\'), datatypes.PdfName(\'Luminosity\')]'}], 'TABLE 7.12': ['SoftMaskImageDictionary', 'Additional entry in a soft-mask image dictionary', 'ImageDictionary', {'Subtype': '[datatypes.PdfName(\'Image\')]', 'ColorSpace': '[datatypes.PdfName(\'DeviceGray\'), datatypes.PdfName(\'Gray\')]'}], -'TABLE 7.13': ['TransparencyGroupDictionary', 'Additional entries specific to a transparency group attributes dictionary', 'XObjectDictionary', {'S': '[datatypes.PdfName(\'Transparency\')]'}], +'TABLE 7.13': ['TransparencyGroupDictionary', 'Additional entries specific to a transparency group attributes dictionary', '', {'S': '[datatypes.PdfName(\'Transparency\')]'}], 'TABLE 8.1': ['ViewerPreferencesDictionary', 'Entries in a viewer preferences dictionary'], 'TABLE 8.3': ['OutlineDictionary', 'Entries in the outline dictionary'], 'TABLE 8.4': ['OutlineItemDictionary', 'Entries in an outline item dictionary'], |