| Index: experimental/PdfViewer/SkPdfRenderer.cpp
|
| ===================================================================
|
| --- experimental/PdfViewer/SkPdfRenderer.cpp (revision 10438)
|
| +++ experimental/PdfViewer/SkPdfRenderer.cpp (working copy)
|
| @@ -634,11 +634,73 @@
|
| 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 @@
|
|
|
| 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 @@
|
|
|
| // 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 @@
|
|
|
| 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 @@
|
| }
|
| }
|
|
|
| - 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?
|
|
|