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
This commit is contained in:
edisonn@google.com 2013-08-02 20:24:48 +00:00
parent 48bc79194b
commit e2e01ffb94
5 changed files with 183 additions and 39 deletions

View File

@ -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) {

View File

@ -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.
canvas->save();
PdfOp_q(pdfContext, canvas, NULL);
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);
}
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);
pdfContext->fGraphicsState.applyGraphicsState(&paint, true);
paint.setColor(SK_ColorGREEN);
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);
} else {
paint.setStyle(SkPaint::kStroke_Style);
pdfContext->fGraphicsState.applyGraphicsState(&paint, true);
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;
}

View File

@ -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++;

View File

@ -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;

View File

@ -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'],