aboutsummaryrefslogtreecommitdiffhomepage
path: root/experimental/PdfViewer
diff options
context:
space:
mode:
authorGravatar edisonn@google.com <edisonn@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-08-02 20:24:48 +0000
committerGravatar edisonn@google.com <edisonn@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-08-02 20:24:48 +0000
commite2e01ffb948468d4c3701f7f2a1d0c5ea75657f4 (patch)
tree9e1ca623196d33cf57a13b1d5ef19cffd9cf62a4 /experimental/PdfViewer
parent48bc79194b52460e712a620dcf845e4836941c2b (diff)
pdfviewer: implementation of one type of pattern - simple tile patern, colored, with xstep and ystep positive.
Review URL: https://codereview.chromium.org/21919003 git-svn-id: http://skia.googlecode.com/svn/trunk@10523 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'experimental/PdfViewer')
-rw-r--r--experimental/PdfViewer/SkPdfBasics.h25
-rw-r--r--experimental/PdfViewer/SkPdfRenderer.cpp179
-rw-r--r--experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp2
-rw-r--r--experimental/PdfViewer/pdfparser/native/SkPdfObject.h12
-rw-r--r--experimental/PdfViewer/spec2def.py2
5 files changed, 182 insertions, 38 deletions
diff --git a/experimental/PdfViewer/SkPdfBasics.h b/experimental/PdfViewer/SkPdfBasics.h
index 28a18c5bc5..a681eca710 100644
--- a/experimental/PdfViewer/SkPdfBasics.h
+++ b/experimental/PdfViewer/SkPdfBasics.h
@@ -20,7 +20,7 @@ class SkNativeParsedPDF;
class SkPdfAllocator;
// TODO(edisonn): better class design.
-struct SkPdfColorOperator {
+class SkPdfColorOperator {
/*
color space name or array The current color space in which color values are to be interpreted
@@ -31,8 +31,11 @@ struct SkPdfColorOperator {
// TODO(edisonn): implement the array part too
// does not own the char*
+// TODO(edisonn): remove this public, let fields be private
+// TODO(edisonn): make color space an enum!
+public:
NotOwnedString fColorSpace;
-
+ SkPdfObject* fPattern;
/*
color (various) The current color to be used during painting operations (see Section
@@ -45,15 +48,29 @@ struct SkPdfColorOperator {
SkColor fColor;
double fOpacity; // ca or CA
+
// TODO(edisonn): add here other color space options.
+public:
void setRGBColor(SkColor color) {
// TODO(edisonn): ASSERT DeviceRGB is the color space.
+ fPattern = NULL;
fColor = color;
}
// TODO(edisonn): double check the default values for all fields.
- SkPdfColorOperator() : fColor(SK_ColorBLACK), fOpacity(1) {
- NotOwnedString::init(&fColorSpace);
+ SkPdfColorOperator() : fPattern(NULL), fColor(SK_ColorBLACK), fOpacity(1) {
+ NotOwnedString::init(&fColorSpace, "DeviceRGB");
+ }
+
+ void setColorSpace(NotOwnedString* colorSpace) {
+ fColorSpace = *colorSpace;
+ fPattern = NULL;
+ }
+
+ void setPatternColorSpace(SkPdfObject* pattern) {
+ fColorSpace.fBuffer = (const unsigned char*)"Pattern";
+ fColorSpace.fBytes = 7; // strlen("Pattern")
+ fPattern = pattern;
}
void applyGraphicsState(SkPaint* paint) {
diff --git a/experimental/PdfViewer/SkPdfRenderer.cpp b/experimental/PdfViewer/SkPdfRenderer.cpp
index bbd036a00b..5b8edc3ee3 100644
--- a/experimental/PdfViewer/SkPdfRenderer.cpp
+++ b/experimental/PdfViewer/SkPdfRenderer.cpp
@@ -739,6 +739,64 @@ static PdfResult doXObject_Form(PdfContext* pdfContext, SkCanvas* canvas, SkPdfT
return kPartial_PdfResult;
}
+
+// TODO(edisonn): Extract a class like ObjWithStream
+static PdfResult doXObject_Pattern(PdfContext* pdfContext, SkCanvas* canvas, SkPdfType1PatternDictionary* skobj) {
+ if (!skobj || !skobj->hasStream()) {
+ return kIgnoreError_PdfResult;
+ }
+
+ if (!skobj->has_BBox()) {
+ return kIgnoreError_PdfResult;
+ }
+
+ PdfOp_q(pdfContext, canvas, NULL);
+
+ canvas->save();
+
+
+ if (skobj->Resources(pdfContext->fPdfDoc)) {
+ pdfContext->fGraphicsState.fResources = skobj->Resources(pdfContext->fPdfDoc);
+ }
+
+ SkTraceMatrix(pdfContext->fGraphicsState.fCTM, "Current matrix");
+
+ if (skobj->has_Matrix()) {
+ pdfContext->fGraphicsState.fCTM.preConcat(skobj->Matrix(pdfContext->fPdfDoc));
+ pdfContext->fGraphicsState.fMatrixTm = pdfContext->fGraphicsState.fCTM;
+ pdfContext->fGraphicsState.fMatrixTlm = pdfContext->fGraphicsState.fCTM;
+ // TODO(edisonn) reset matrixTm and matricTlm also?
+ }
+
+ SkTraceMatrix(pdfContext->fGraphicsState.fCTM, "Total matrix");
+
+ canvas->setMatrix(pdfContext->fGraphicsState.fCTM);
+
+ 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.
+
+ SkPdfStream* stream = (SkPdfStream*)skobj;
+
+ SkPdfNativeTokenizer* tokenizer =
+ pdfContext->fPdfDoc->tokenizerOfStream(stream, pdfContext->fTmpPageAllocator);
+ if (tokenizer != NULL) {
+ PdfMainLooper looper(NULL, tokenizer, pdfContext, canvas);
+ looper.loop();
+ delete tokenizer;
+ }
+
+ // 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.
+
+ canvas->restore();
+ PdfOp_Q(pdfContext, canvas, NULL);
+ return kPartial_PdfResult;
+}
+
+
//static PdfResult doXObject_PS(PdfContext* pdfContext, SkCanvas* canvas, const SkPdfObject* obj) {
// return kNYI_PdfResult;
//}
@@ -826,9 +884,14 @@ static PdfResult doXObject(PdfContext* pdfContext, SkCanvas* canvas, const SkPdf
return doXObject_Form(pdfContext, canvas, (SkPdfType1FormDictionary*)obj);
//case kObjectDictionaryXObjectPS_SkPdfObjectType:
//return doXObject_PS(skxobj.asPS());
- default:
- return kIgnoreError_PdfResult;
+ default: {
+ if (pdfContext->fPdfDoc->mapper()->mapType1PatternDictionary(obj) != kNone_SkPdfObjectType) {
+ SkPdfType1PatternDictionary* pattern = (SkPdfType1PatternDictionary*)obj;
+ return doXObject_Pattern(pdfContext, canvas, pattern);
+ }
+ }
}
+ return kIgnoreError_PdfResult;
}
static PdfResult doPage(PdfContext* pdfContext, SkCanvas* canvas, SkPdfPageObjectDictionary* skobj) {
@@ -1165,29 +1228,100 @@ static PdfResult PdfOp_fillAndStroke(PdfContext* pdfContext, SkCanvas* canvas, b
if (fill && !stroke && path.isLine(line)) {
paint.setStyle(SkPaint::kStroke_Style);
+ // TODO(edisonn): implement this with patterns
pdfContext->fGraphicsState.applyGraphicsState(&paint, false);
paint.setStrokeWidth(SkDoubleToScalar(0));
canvas->drawPath(path, paint);
} else {
if (fill) {
- paint.setStyle(SkPaint::kFill_Style);
- if (evenOdd) {
- path.setFillType(SkPath::kEvenOdd_FillType);
- }
+ if (strncmp((char*)pdfContext->fGraphicsState.fNonStroking.fColorSpace.fBuffer, "Pattern", strlen("Pattern")) == 0 &&
+ pdfContext->fGraphicsState.fNonStroking.fPattern != NULL) {
+
+ // TODO(edisonn): we can use a shader here, like imageshader to draw fast. ultimately,
+ // if this is not possible, and we are in rasper mode, and the cells don't intersect, we could even have multiple cpus.
- pdfContext->fGraphicsState.applyGraphicsState(&paint, false);
+ canvas->save();
+ PdfOp_q(pdfContext, canvas, NULL);
- canvas->drawPath(path, paint);
+ if (evenOdd) {
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ }
+ canvas->clipPath(path);
+
+ if (pdfContext->fPdfDoc->mapper()->mapType1PatternDictionary(pdfContext->fGraphicsState.fNonStroking.fPattern) != kNone_SkPdfObjectType) {
+ SkPdfType1PatternDictionary* pattern = (SkPdfType1PatternDictionary*)pdfContext->fGraphicsState.fNonStroking.fPattern;
+
+ // TODO(edisonn): constants
+ // TODO(edisonn): colored
+ if (pattern->PaintType(pdfContext->fPdfDoc) == 1) {
+ int xStep = (int)pattern->XStep(pdfContext->fPdfDoc);
+ int yStep = (int)pattern->YStep(pdfContext->fPdfDoc);
+
+ SkRect bounds = path.getBounds();
+ SkScalar x;
+ SkScalar y;
+
+ // TODO(edisonn): xstep and ystep can be negative, and we need to iterate in reverse
+
+ y = bounds.top();
+ int totalx = 0;
+ int totaly = 0;
+ while (y < bounds.bottom()) {
+ x = bounds.left();
+ totalx = 0;
+
+ while (x < bounds.right()) {
+ doXObject(pdfContext, canvas, pattern);
+
+ pdfContext->fGraphicsState.fCTM.preTranslate(SkIntToScalar(xStep), SkIntToScalar(0));
+ totalx += xStep;
+ x += SkIntToScalar(xStep);
+ }
+ pdfContext->fGraphicsState.fCTM.preTranslate(SkIntToScalar(-totalx), SkIntToScalar(0));
+
+ pdfContext->fGraphicsState.fCTM.preTranslate(SkIntToScalar(0), SkIntToScalar(-yStep));
+ totaly += yStep;
+ y += SkIntToScalar(yStep);
+ }
+ pdfContext->fGraphicsState.fCTM.preTranslate(SkIntToScalar(0), SkIntToScalar(totaly));
+ }
+ }
+
+ // apply matrix
+ // get xstep, y step, bbox ... for cliping, and bos of the path
+
+ PdfOp_Q(pdfContext, canvas, NULL);
+ canvas->restore();
+ } else {
+ paint.setStyle(SkPaint::kFill_Style);
+ if (evenOdd) {
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ }
+
+ pdfContext->fGraphicsState.applyGraphicsState(&paint, false);
+
+ canvas->drawPath(path, paint);
+ }
}
if (stroke) {
- paint.setStyle(SkPaint::kStroke_Style);
+ if (false && strncmp((char*)pdfContext->fGraphicsState.fNonStroking.fColorSpace.fBuffer, "Pattern", strlen("Pattern")) == 0) {
+ // TODO(edisonn): implement Pattern for strokes
+ paint.setStyle(SkPaint::kStroke_Style);
+
+ paint.setColor(SK_ColorGREEN);
+
+ path.setFillType(SkPath::kWinding_FillType); // reset it, just in case it messes up the stroke
+ canvas->drawPath(path, paint);
+ } else {
+ paint.setStyle(SkPaint::kStroke_Style);
- pdfContext->fGraphicsState.applyGraphicsState(&paint, true);
+ pdfContext->fGraphicsState.applyGraphicsState(&paint, true);
- path.setFillType(SkPath::kWinding_FillType); // reset it, just in case it messes up the stroke
- canvas->drawPath(path, paint);
+ path.setFillType(SkPath::kWinding_FillType); // reset it, just in case it messes up the stroke
+ canvas->drawPath(path, paint);
+ }
}
}
@@ -1459,16 +1593,16 @@ static PdfResult PdfOp_SCN_scn(PdfContext* pdfContext, SkCanvas* canvas, SkPdfCo
SkPdfObject* name = pdfContext->fObjectStack.top(); pdfContext->fObjectStack.pop();
//Next, get the ExtGState Dictionary from the Resource Dictionary:
- SkPdfDictionary* extGStateDictionary = pdfContext->fGraphicsState.fResources->Pattern(pdfContext->fPdfDoc);
+ SkPdfDictionary* patternResources = pdfContext->fGraphicsState.fResources->Pattern(pdfContext->fPdfDoc);
- if (extGStateDictionary == NULL) {
+ if (patternResources == NULL) {
#ifdef PDF_TRACE
printf("ExtGState is NULL!\n");
#endif
return kIgnoreError_PdfResult;
}
- /*SkPdfObject* value = */pdfContext->fPdfDoc->resolveReference(extGStateDictionary->get(name));
+ colorOperator->setPatternColorSpace(pdfContext->fPdfDoc->resolveReference(patternResources->get(name)));
}
// TODO(edisonn): SCN supports more color spaces than SCN. Read and implement spec.
@@ -2262,21 +2396,6 @@ void PdfInlineImageLooper::loop() {
}
PdfResult PdfInlineImageLooper::done() {
-
- // TODO(edisonn): long to short names
- // TODO(edisonn): set properties in a map
- // TODO(edisonn): extract bitmap stream, check if PoDoFo has public utilities to uncompress
- // the stream.
-
- SkBitmap bitmap;
- setup_bitmap(&bitmap, 50, 50, SK_ColorRED);
-
- // TODO(edisonn): matrix use.
- // Draw dummy red square, to show the prezence of the inline image.
- fCanvas->drawBitmap(bitmap,
- SkDoubleToScalar(0),
- SkDoubleToScalar(0),
- NULL);
return kNYI_PdfResult;
}
diff --git a/experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp b/experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp
index 9ec5cc0925..8dd5d30c5c 100644
--- a/experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp
+++ b/experimental/PdfViewer/pdfparser/native/SkPdfNativeTokenizer.cpp
@@ -28,7 +28,7 @@ static char* strrstrk(char* hayStart, char* hayEnd, const char* needle) {
return NULL;
}
-#ifdef PDF_TRACE
+#ifdef PDF_TRACE_TOKENIZER
static void TRACE_INDENT(int level, const char* type) {
static int id = 0;
id++;
diff --git a/experimental/PdfViewer/pdfparser/native/SkPdfObject.h b/experimental/PdfViewer/pdfparser/native/SkPdfObject.h
index 5e3bcdbe1d..29780d07cc 100644
--- a/experimental/PdfViewer/pdfparser/native/SkPdfObject.h
+++ b/experimental/PdfViewer/pdfparser/native/SkPdfObject.h
@@ -839,7 +839,7 @@ public:
}
}
- SkString toString(int firstRowLevel = 0, int level = 0) const {
+ SkString toString(int firstRowLevel = 0, int level = 0) {
SkString str;
appendSpaces(&str, firstRowLevel);
switch (fObjectType) {
@@ -905,7 +905,15 @@ public:
appendSpaces(&str, level);
str.append(">>");
if (hasStream()) {
- str.append("stream HAS_STREAM endstream");
+ const unsigned char* stream = NULL;
+ size_t length = 0;
+ if (GetFilteredStreamRef(&stream, &length)) {
+ str.append("stream");
+ str.append((const char*)stream, length > 256 ? 256 : length);
+ str.append("endstream");
+ } else {
+ str.append("stream STREAM_ERROR endstream");
+ }
}
}
break;
diff --git a/experimental/PdfViewer/spec2def.py b/experimental/PdfViewer/spec2def.py
index 8f02ab8aca..ed2ce0120a 100644
--- a/experimental/PdfViewer/spec2def.py
+++ b/experimental/PdfViewer/spec2def.py
@@ -86,7 +86,7 @@ tableToClassName = {
'TABLE 4.15': ['LabColorSpaceDictionary', 'Entries in a Lab color space dictionary'],
'TABLE 4.16': ['IccProfileStreamDictionary', 'Additional entries specific to an ICC profile stream dictionary'],
'TABLE 4.20': ['DeviceNColorSpaceDictionary', 'Entry in a DeviceN color space attributes dictionary'],
-'TABLE 4.22': ['Type1PatternDictionary', 'Additional entries specific to a type 1 pattern dictionary'],
+'TABLE 4.22': ['Type1PatternDictionary', 'Additional entries specific to a type 1 pattern dictionary', '', {'PatternType': '[datatypes.PdfInteger(1)]'}],
'TABLE 4.23': ['Type2PatternDictionary', 'Entries in a type 2 pattern dictionary'],
'TABLE 4.25': ['ShadingDictionary', 'Entries common to all shading dictionaries'],
'TABLE 4.26': ['Type1ShadingDictionary', 'Additional entries specific to a type 1 shading dictionary', 'ShadingDictionary'],