pdfviewer: gs operator implementation: dashing and font
Review URL: https://codereview.chromium.org/20810002 git-svn-id: http://skia.googlecode.com/svn/trunk@10403 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
27e21fe577
commit
a0cefa18fc
@ -1,6 +1,8 @@
|
||||
#include "SkPdfBasics.h"
|
||||
#include "SkPdfNativeTokenizer.h"
|
||||
|
||||
#include "SkDashPathEffect.h"
|
||||
|
||||
PdfContext::PdfContext(SkNativeParsedPDF* doc)
|
||||
: fPdfDoc(doc)
|
||||
, fTmpPageAllocator(new SkPdfAllocator()) {
|
||||
@ -9,3 +11,25 @@ PdfContext::PdfContext(SkNativeParsedPDF* doc)
|
||||
PdfContext::~PdfContext() {
|
||||
delete fTmpPageAllocator;
|
||||
}
|
||||
|
||||
void SkPdfGraphicsState::applyGraphicsState(SkPaint* paint, bool stroking) {
|
||||
if (stroking) {
|
||||
fStroking.applyGraphicsState(paint);
|
||||
} else {
|
||||
fNonStroking.applyGraphicsState(paint);
|
||||
}
|
||||
|
||||
// TODO(edisonn): get this from pdfContext->options,
|
||||
// or pdfContext->addPaintOptions(&paint);
|
||||
paint->setAntiAlias(true);
|
||||
|
||||
// TODO(edisonn): miter, ...
|
||||
if (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) {
|
||||
paint->setPathEffect(new SkDashPathEffect(fDashArray, fDashArrayLength, fDashPhase))->unref();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,8 +20,28 @@ class SkPdfAllocator;
|
||||
|
||||
// TODO(edisonn): better class design.
|
||||
struct SkPdfColorOperator {
|
||||
|
||||
/*
|
||||
color space name or array The current color space in which color values are to be interpreted
|
||||
(see Section 4.5, “Color Spaces”). There are two separate color space
|
||||
parameters: one for stroking and one for all other painting opera-
|
||||
tions. Initial value: DeviceGray.
|
||||
*/
|
||||
|
||||
// TODO(edisonn): implement the array part too
|
||||
// does not own the char*
|
||||
NotOwnedString fColorSpace;
|
||||
|
||||
|
||||
/*
|
||||
color (various) The current color to be used during painting operations (see Section
|
||||
4.5, “Color Spaces”). The type and interpretation of this parameter
|
||||
depend on the current color space; for most color spaces, a color
|
||||
value consists of one to four numbers. There are two separate color
|
||||
parameters: one for stroking and one for all other painting opera-
|
||||
tions. Initial value: black.
|
||||
*/
|
||||
|
||||
SkColor fColor;
|
||||
double fOpacity; // ca or CA
|
||||
// TODO(edisonn): add here other color space options.
|
||||
@ -42,10 +62,7 @@ struct SkPdfColorOperator {
|
||||
|
||||
// TODO(edisonn): better class design.
|
||||
struct SkPdfGraphicsState {
|
||||
SkMatrix fMatrix;
|
||||
SkMatrix fMatrixTm;
|
||||
SkMatrix fMatrixTlm;
|
||||
|
||||
// TODO(edisonn): deprecate and remove these!
|
||||
double fCurPosX;
|
||||
double fCurPosY;
|
||||
|
||||
@ -55,6 +72,35 @@ struct SkPdfGraphicsState {
|
||||
SkPath fPath;
|
||||
bool fPathClosed;
|
||||
|
||||
|
||||
|
||||
double fTextLeading;
|
||||
double fWordSpace;
|
||||
double fCharSpace;
|
||||
|
||||
SkPdfResourceDictionary* fResources;
|
||||
|
||||
|
||||
// TODO(edisonn): move most of these in canvas/paint?
|
||||
// we could have some in canvas (matrixes?),
|
||||
// some in 2 paints (stroking paint and non stroking paint)
|
||||
|
||||
// TABLE 4.2 Device-independent graphics state parameters
|
||||
/*
|
||||
* CTM array The current transformation matrix, which maps positions from user
|
||||
coordinates to device coordinates (see Section 4.2, “Coordinate Sys-
|
||||
tems”). This matrix is modified by each application of the coordi-
|
||||
nate transformation operator, cm. Initial value: a matrix that
|
||||
transforms default user coordinates to device coordinates.
|
||||
*/
|
||||
SkMatrix fCTM;
|
||||
|
||||
/*
|
||||
clipping path (internal) The current clipping path, which defines the boundary against
|
||||
which all output is to be cropped (see Section 4.4.3, “Clipping Path
|
||||
Operators”). Initial value: the boundary of the entire imageable
|
||||
portion of the output page.
|
||||
*/
|
||||
// Clip that is applied after the drawing is done!!!
|
||||
bool fHasClipPathToApply;
|
||||
SkPath fClipPath;
|
||||
@ -62,21 +108,208 @@ struct SkPdfGraphicsState {
|
||||
SkPdfColorOperator fStroking;
|
||||
SkPdfColorOperator fNonStroking;
|
||||
|
||||
/*
|
||||
text state (various) A set of nine graphics state parameters that pertain only to the
|
||||
painting of text. These include parameters that select the font, scale
|
||||
the glyphs to an appropriate size, and accomplish other effects. The
|
||||
text state parameters are described in Section 5.2, “Text State
|
||||
Parameters and Operators.”
|
||||
*/
|
||||
|
||||
// TODO(edisonn): add SkPdfTextState class. remove these two existing fields
|
||||
SkMatrix fMatrixTm;
|
||||
SkMatrix fMatrixTlm;
|
||||
|
||||
|
||||
/*
|
||||
line width number The thickness, in user space units, of paths to be stroked (see “Line
|
||||
Width” on page 152). Initial value: 1.0.
|
||||
*/
|
||||
double fLineWidth;
|
||||
double fTextLeading;
|
||||
double fWordSpace;
|
||||
double fCharSpace;
|
||||
|
||||
SkPdfResourceDictionary* fResources;
|
||||
|
||||
/*
|
||||
line cap integer A code specifying the shape of the endpoints for any open path that
|
||||
is stroked (see “Line Cap Style” on page 153). Initial value: 0, for
|
||||
square butt caps.
|
||||
*/
|
||||
// TODO (edisonn): implement defaults - page 153
|
||||
int fLineCap;
|
||||
|
||||
/*
|
||||
line join integer A code specifying the shape of joints between connected segments
|
||||
of a stroked path (see “Line Join Style” on page 153). Initial value: 0,
|
||||
for mitered joins.
|
||||
*/
|
||||
// TODO (edisonn): implement defaults - page 153
|
||||
int fLineJoin;
|
||||
|
||||
/*
|
||||
miter limit number The maximum length of mitered line joins for stroked paths (see
|
||||
“Miter Limit” on page 153). This parameter limits the length of
|
||||
“spikes” produced when line segments join at sharp angles. Initial
|
||||
value: 10.0, for a miter cutoff below approximately 11.5 degrees.
|
||||
*/
|
||||
// TODO (edisonn): implement defaults - page 153
|
||||
double fMiterLimit;
|
||||
|
||||
/*
|
||||
dash pattern array and A description of the dash pattern to be used when paths are
|
||||
number stroked (see “Line Dash Pattern” on page 155). Initial value: a solid
|
||||
line.
|
||||
*/
|
||||
SkScalar fDashArray[256]; // TODO(edisonn): allocate array?
|
||||
int fDashArrayLength;
|
||||
SkScalar fDashPhase;
|
||||
|
||||
|
||||
/*
|
||||
rendering intent name The rendering intent to be used when converting CIE-based colors
|
||||
to device colors (see “Rendering Intents” on page 197). Default
|
||||
value: RelativeColorimetric.
|
||||
*/
|
||||
// TODO(edisonn): seems paper only. Verify.
|
||||
|
||||
/*
|
||||
stroke adjustment boolean (PDF 1.2) A flag specifying whether to compensate for possible ras-
|
||||
terization effects when stroking a path with a line width that is
|
||||
small relative to the pixel resolution of the output device (see Sec-
|
||||
tion 6.5.4, “Automatic Stroke Adjustment”). Note that this is con-
|
||||
sidered a device-independent parameter, even though the details of
|
||||
its effects are device-dependent. Initial value: false.
|
||||
*/
|
||||
// TODO(edisonn): stroke adjustment low priority.
|
||||
|
||||
|
||||
/*
|
||||
blend mode name or array (PDF 1.4) The current blend mode to be used in the transparent
|
||||
imaging model (see Sections 7.2.4, “Blend Mode,” and 7.5.2, “Spec-
|
||||
ifying Blending Color Space and Blend Mode”). This parameter is
|
||||
implicitly reset to its initial value at the beginning of execution of a
|
||||
transparency group XObject (see Section 7.5.5, “Transparency
|
||||
Group XObjects”). Initial value: Normal.
|
||||
*/
|
||||
SkXfermode::Mode fBlendMode;
|
||||
|
||||
/*
|
||||
soft mask dictionary (PDF 1.4) A soft-mask dictionary (see “Soft-Mask Dictionaries” on
|
||||
or name page 445) specifying the mask shape or mask opacity values to be
|
||||
used in the transparent imaging model (see “Source Shape and
|
||||
Opacity” on page 421 and “Mask Shape and Opacity” on page 443),
|
||||
or the name None if no such mask is specified. This parameter is
|
||||
implicitly reset to its initial value at the beginning of execution of a
|
||||
transparency group XObject (see Section 7.5.5, “Transparency
|
||||
Group XObjects”). Initial value: None.
|
||||
*/
|
||||
SkBitmap fSMask;
|
||||
|
||||
|
||||
/*
|
||||
alpha constant number (PDF 1.4) The constant shape or constant opacity value to be used
|
||||
in the transparent imaging model (see “Source Shape and Opacity”
|
||||
on page 421 and “Constant Shape and Opacity” on page 444).
|
||||
There are two separate alpha constant parameters: one for stroking
|
||||
and one for all other painting operations. This parameter is implic-
|
||||
itly reset to its initial value at the beginning of execution of a trans-
|
||||
parency group XObject (see Section 7.5.5, “Transparency Group
|
||||
XObjects”). Initial value: 1.0.
|
||||
*/
|
||||
double fAphaConstant;
|
||||
|
||||
/*
|
||||
alpha source boolean (PDF 1.4) A flag specifying whether the current soft mask and alpha
|
||||
constant parameters are to be interpreted as shape values (true) or
|
||||
opacity values (false). This flag also governs the interpretation of
|
||||
the SMask entry, if any, in an image dictionary (see Section 4.8.4,
|
||||
“Image Dictionaries”). Initial value: false.
|
||||
*/
|
||||
bool fAlphaSource;
|
||||
|
||||
|
||||
// TODO(edisonn): Device-dependent seem to be required only on the actual physical printer?
|
||||
// TABLE 4.3 Device-dependent graphics state parameters
|
||||
/*
|
||||
overprint boolean (PDF 1.2) A flag specifying (on output devices that support the
|
||||
overprint control feature) whether painting in one set of colorants
|
||||
should cause the corresponding areas of other colorants to be
|
||||
erased (false) or left unchanged (true); see Section 4.5.6, “Over-
|
||||
print Control.” In PDF 1.3, there are two separate overprint param-
|
||||
eters: one for stroking and one for all other painting operations.
|
||||
Initial value: false.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
overprint mode number (PDF 1.3) A code specifying whether a color component value of 0
|
||||
in a DeviceCMYK color space should erase that component (0) or
|
||||
leave it unchanged (1) when overprinting (see Section 4.5.6, “Over-
|
||||
print Control”). Initial value: 0.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
black generation function (PDF 1.2) A function that calculates the level of the black color
|
||||
or name component to use when converting RGB colors to CMYK (see Sec-
|
||||
tion 6.2.3, “Conversion from DeviceRGB to DeviceCMYK”). Initial
|
||||
value: installation-dependent.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
undercolor removal function (PDF 1.2) A function that calculates the reduction in the levels of
|
||||
or name the cyan, magenta, and yellow color components to compensate for
|
||||
the amount of black added by black generation (see Section 6.2.3,
|
||||
“Conversion from DeviceRGB to DeviceCMYK”). Initial value: in-
|
||||
stallation-dependent.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
transfer function, (PDF 1.2) A function that adjusts device gray or color component
|
||||
array, or name levels to compensate for nonlinear response in a particular out-
|
||||
put device (see Section 6.3, “Transfer Functions”). Initial value:
|
||||
installation-dependent.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
halftone dictionary, (PDF 1.2) A halftone screen for gray and color rendering, specified
|
||||
stream, or name as a halftone dictionary or stream (see Section 6.4, “Halftones”).
|
||||
Initial value: installation-dependent.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
flatness number The precision with which curves are to be rendered on the output
|
||||
device (see Section 6.5.1, “Flatness Tolerance”). The value of this
|
||||
parameter gives the maximum error tolerance, measured in output
|
||||
device pixels; smaller numbers give smoother curves at the expense
|
||||
of more computation and memory use. Initial value: 1.0.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
smoothness number (PDF 1.3) The precision with which color gradients are to be ren-
|
||||
dered on the output device (see Section 6.5.2, “Smoothness Toler-
|
||||
ance”). The value of this parameter gives the maximum error
|
||||
tolerance, expressed as a fraction of the range of each color compo-
|
||||
nent; smaller numbers give smoother color transitions at the
|
||||
expense of more computation and memory use. Initial value:
|
||||
installation-dependent.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
SkPdfGraphicsState() {
|
||||
fCurPosX = 0.0;
|
||||
fCurPosY = 0.0;
|
||||
fCurFontSize = 0.0;
|
||||
fTextBlock = false;
|
||||
fMatrix = SkMatrix::I();
|
||||
fCTM = SkMatrix::I();
|
||||
fMatrixTm = SkMatrix::I();
|
||||
fMatrixTlm = SkMatrix::I();
|
||||
fPathClosed = true;
|
||||
@ -87,22 +320,18 @@ struct SkPdfGraphicsState {
|
||||
fHasClipPathToApply = false;
|
||||
fResources = NULL;
|
||||
fSkFont = NULL;
|
||||
fLineCap = 0;
|
||||
fLineJoin = 0;
|
||||
fMiterLimit = 10.0;
|
||||
fAphaConstant = 1.0;
|
||||
fAlphaSource = false;
|
||||
fDashArrayLength = 0;
|
||||
fDashPhase = 0;
|
||||
fBlendMode = SkXfermode::kSrc_Mode; // PDF: Normal Blend mode
|
||||
}
|
||||
|
||||
void applyGraphicsState(SkPaint* paint, bool stroking) {
|
||||
if (stroking) {
|
||||
fStroking.applyGraphicsState(paint);
|
||||
} else {
|
||||
fNonStroking.applyGraphicsState(paint);
|
||||
}
|
||||
|
||||
// TODO(edisonn): get this from pdfContext->options,
|
||||
// or pdfContext->addPaintOptions(&paint);
|
||||
paint->setAntiAlias(true);
|
||||
|
||||
// TODO(edisonn): dashing, miter, ...
|
||||
paint->setStrokeWidth(SkDoubleToScalar(fLineWidth));
|
||||
}
|
||||
// TODO(edisonn): make two functons instead, stroking and non stoking, avoid branching
|
||||
void applyGraphicsState(SkPaint* paint, bool stroking);
|
||||
};
|
||||
|
||||
// TODO(edisonn): better class design.
|
||||
|
@ -598,7 +598,7 @@ static PdfResult doXObject_Image(PdfContext* pdfContext, SkCanvas* canvas, SkPdf
|
||||
SkBitmap sMask = getSmaskFromObject(pdfContext, skpdfimage);
|
||||
|
||||
canvas->save();
|
||||
canvas->setMatrix(pdfContext->fGraphicsState.fMatrix);
|
||||
canvas->setMatrix(pdfContext->fGraphicsState.fCTM);
|
||||
|
||||
#if 1
|
||||
SkScalar z = SkIntToScalar(0);
|
||||
@ -608,7 +608,7 @@ static PdfResult doXObject_Image(PdfContext* pdfContext, SkCanvas* canvas, SkPdf
|
||||
SkPoint to[4] = {SkPoint::Make(z, one), SkPoint::Make(one, one), SkPoint::Make(one, z), SkPoint::Make(z, z)};
|
||||
SkMatrix flip;
|
||||
SkAssertResult(flip.setPolyToPoly(from, to, 4));
|
||||
SkMatrix solveImageFlip = pdfContext->fGraphicsState.fMatrix;
|
||||
SkMatrix solveImageFlip = pdfContext->fGraphicsState.fCTM;
|
||||
solveImageFlip.preConcat(flip);
|
||||
canvas->setMatrix(solveImageFlip);
|
||||
#endif
|
||||
@ -648,18 +648,18 @@ static PdfResult doXObject_Form(PdfContext* pdfContext, SkCanvas* canvas, SkPdfT
|
||||
pdfContext->fGraphicsState.fResources = skobj->Resources(pdfContext->fPdfDoc);
|
||||
}
|
||||
|
||||
SkTraceMatrix(pdfContext->fGraphicsState.fMatrix, "Current matrix");
|
||||
SkTraceMatrix(pdfContext->fGraphicsState.fCTM, "Current matrix");
|
||||
|
||||
if (skobj->has_Matrix()) {
|
||||
pdfContext->fGraphicsState.fMatrix.preConcat(skobj->Matrix(pdfContext->fPdfDoc));
|
||||
pdfContext->fGraphicsState.fMatrixTm = pdfContext->fGraphicsState.fMatrix;
|
||||
pdfContext->fGraphicsState.fMatrixTlm = pdfContext->fGraphicsState.fMatrix;
|
||||
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.fMatrix, "Total matrix");
|
||||
SkTraceMatrix(pdfContext->fGraphicsState.fCTM, "Total matrix");
|
||||
|
||||
canvas->setMatrix(pdfContext->fGraphicsState.fMatrix);
|
||||
canvas->setMatrix(pdfContext->fGraphicsState.fCTM);
|
||||
|
||||
if (skobj->has_BBox()) {
|
||||
canvas->clipRect(skobj->BBox(pdfContext->fPdfDoc), SkRegion::kIntersect_Op, true); // TODO(edisonn): AA from settings.
|
||||
@ -700,15 +700,15 @@ PdfResult doType3Char(PdfContext* pdfContext, SkCanvas* canvas, const SkPdfObjec
|
||||
pdfContext->fGraphicsState.fMatrixTm.preConcat(matrix);
|
||||
pdfContext->fGraphicsState.fMatrixTm.preScale(SkDoubleToScalar(textSize), SkDoubleToScalar(textSize));
|
||||
|
||||
pdfContext->fGraphicsState.fMatrix = pdfContext->fGraphicsState.fMatrixTm;
|
||||
pdfContext->fGraphicsState.fMatrixTlm = pdfContext->fGraphicsState.fMatrix;
|
||||
pdfContext->fGraphicsState.fCTM = pdfContext->fGraphicsState.fMatrixTm;
|
||||
pdfContext->fGraphicsState.fMatrixTlm = pdfContext->fGraphicsState.fCTM;
|
||||
|
||||
SkTraceMatrix(pdfContext->fGraphicsState.fMatrix, "Total matrix");
|
||||
SkTraceMatrix(pdfContext->fGraphicsState.fCTM, "Total matrix");
|
||||
|
||||
canvas->setMatrix(pdfContext->fGraphicsState.fMatrix);
|
||||
canvas->setMatrix(pdfContext->fGraphicsState.fCTM);
|
||||
|
||||
SkRect rm = bBox;
|
||||
pdfContext->fGraphicsState.fMatrix.mapRect(&rm);
|
||||
pdfContext->fGraphicsState.fCTM.mapRect(&rm);
|
||||
|
||||
SkTraceRect(rm, "bbox mapped");
|
||||
|
||||
@ -810,7 +810,7 @@ static PdfResult PdfOp_cm(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
|
||||
// tx ty
|
||||
SkMatrix matrix = SkMatrixFromPdfMatrix(array);
|
||||
|
||||
pdfContext->fGraphicsState.fMatrix.preConcat(matrix);
|
||||
pdfContext->fGraphicsState.fCTM.preConcat(matrix);
|
||||
|
||||
#ifdef PDF_TRACE
|
||||
printf("cm ");
|
||||
@ -818,7 +818,7 @@ static PdfResult PdfOp_cm(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
|
||||
printf("%f ", array[i]);
|
||||
}
|
||||
printf("\n");
|
||||
SkTraceMatrix(pdfContext->fGraphicsState.fMatrix, "cm");
|
||||
SkTraceMatrix(pdfContext->fGraphicsState.fCTM, "cm");
|
||||
#endif
|
||||
|
||||
return kOK_PdfResult;
|
||||
@ -889,7 +889,7 @@ static PdfResult PdfOp_Tm(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
|
||||
array[5] = f;
|
||||
|
||||
SkMatrix matrix = SkMatrixFromPdfMatrix(array);
|
||||
matrix.postConcat(pdfContext->fGraphicsState.fMatrix);
|
||||
matrix.postConcat(pdfContext->fGraphicsState.fCTM);
|
||||
|
||||
// TODO(edisonn): Text positioning.
|
||||
pdfContext->fGraphicsState.fMatrixTm = matrix;
|
||||
@ -1044,7 +1044,7 @@ static PdfResult PdfOp_fillAndStroke(PdfContext* pdfContext, SkCanvas* canvas, b
|
||||
path.close();
|
||||
}
|
||||
|
||||
canvas->setMatrix(pdfContext->fGraphicsState.fMatrix);
|
||||
canvas->setMatrix(pdfContext->fGraphicsState.fCTM);
|
||||
|
||||
SkPaint paint;
|
||||
|
||||
@ -1131,7 +1131,7 @@ static PdfResult PdfOp_b_star(PdfContext* pdfContext, SkCanvas* canvas, PdfToken
|
||||
}
|
||||
|
||||
static PdfResult PdfOp_n(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) {
|
||||
canvas->setMatrix(pdfContext->fGraphicsState.fMatrix);
|
||||
canvas->setMatrix(pdfContext->fGraphicsState.fCTM);
|
||||
if (pdfContext->fGraphicsState.fHasClipPathToApply) {
|
||||
#ifndef PDF_DEBUG_NO_CLIPING
|
||||
canvas->clipPath(pdfContext->fGraphicsState.fClipPath, SkRegion::kIntersect_Op, true);
|
||||
@ -1148,8 +1148,8 @@ static PdfResult PdfOp_n(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
|
||||
|
||||
static PdfResult PdfOp_BT(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) {
|
||||
pdfContext->fGraphicsState.fTextBlock = true;
|
||||
pdfContext->fGraphicsState.fMatrixTm = pdfContext->fGraphicsState.fMatrix;
|
||||
pdfContext->fGraphicsState.fMatrixTlm = pdfContext->fGraphicsState.fMatrix;
|
||||
pdfContext->fGraphicsState.fMatrixTm = pdfContext->fGraphicsState.fCTM;
|
||||
pdfContext->fGraphicsState.fMatrixTlm = pdfContext->fGraphicsState.fCTM;
|
||||
|
||||
return kPartial_PdfResult;
|
||||
}
|
||||
@ -1162,15 +1162,7 @@ static PdfResult PdfOp_ET(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
|
||||
return kPartial_PdfResult;
|
||||
}
|
||||
|
||||
//font size Tf Set the text font, Tf
|
||||
//, to font and the text font size, Tfs, to size. font is the name of a
|
||||
//font resource in the Fontsubdictionary of the current resource dictionary; size is
|
||||
//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 PdfResult PdfOp_Tf(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) {
|
||||
pdfContext->fGraphicsState.fCurFontSize = pdfContext->fObjectStack.top()->numberValue(); pdfContext->fObjectStack.pop();
|
||||
SkPdfObject* fontName = pdfContext->fObjectStack.top(); pdfContext->fObjectStack.pop();
|
||||
|
||||
PdfResult skpdfGraphicsStateApplyFontCore(PdfContext* pdfContext, const SkPdfObject* fontName, double fontSize) {
|
||||
#ifdef PDF_TRACE
|
||||
printf("font name: %s\n", fontName->nameValue2().c_str());
|
||||
#endif
|
||||
@ -1190,9 +1182,21 @@ static PdfResult PdfOp_Tf(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
|
||||
pdfContext->fGraphicsState.fSkFont = skfont;
|
||||
}
|
||||
}
|
||||
pdfContext->fGraphicsState.fCurFontSize = fontSize;
|
||||
return kIgnoreError_PdfResult;
|
||||
}
|
||||
|
||||
//font size Tf Set the text font, Tf
|
||||
//, to font and the text font size, Tfs, to size. font is the name of a
|
||||
//font resource in the Fontsubdictionary of the current resource dictionary; size is
|
||||
//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 PdfResult PdfOp_Tf(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) {
|
||||
double fontSize = pdfContext->fObjectStack.top()->numberValue(); pdfContext->fObjectStack.pop();
|
||||
SkPdfObject* fontName = pdfContext->fObjectStack.top(); pdfContext->fObjectStack.pop();
|
||||
return skpdfGraphicsStateApplyFontCore(pdfContext, fontName, fontSize);
|
||||
}
|
||||
|
||||
static PdfResult PdfOp_Tj(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) {
|
||||
if (!pdfContext->fGraphicsState.fTextBlock) {
|
||||
// TODO(edisonn): try to recover and draw it any way?
|
||||
@ -1519,6 +1523,89 @@ static PdfResult PdfOp_i(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoope
|
||||
return kNYI_PdfResult;
|
||||
}
|
||||
|
||||
|
||||
// TODO(edisonn): security review here, make sure all parameters are valid, and safe.
|
||||
void skpdfGraphicsStateApply_ca(PdfContext* pdfContext, double ca) {
|
||||
pdfContext->fGraphicsState.fNonStroking.fOpacity = ca;
|
||||
}
|
||||
|
||||
void skpdfGraphicsStateApply_CA(PdfContext* pdfContext, double CA) {
|
||||
pdfContext->fGraphicsState.fStroking.fOpacity = CA;
|
||||
}
|
||||
|
||||
void skpdfGraphicsStateApplyLW(PdfContext* pdfContext, double lineWidth) {
|
||||
pdfContext->fGraphicsState.fLineWidth = lineWidth;
|
||||
}
|
||||
|
||||
void skpdfGraphicsStateApplyLC(PdfContext* pdfContext, int64_t lineCap) {
|
||||
pdfContext->fGraphicsState.fLineCap = (int)lineCap;
|
||||
}
|
||||
|
||||
void skpdfGraphicsStateApplyLJ(PdfContext* pdfContext, int64_t lineJoin) {
|
||||
pdfContext->fGraphicsState.fLineJoin = (int)lineJoin;
|
||||
}
|
||||
|
||||
void skpdfGraphicsStateApplyML(PdfContext* pdfContext, double miterLimit) {
|
||||
pdfContext->fGraphicsState.fMiterLimit = miterLimit;
|
||||
}
|
||||
|
||||
void skpdfGraphicsStateApplyD(PdfContext* 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
|
||||
return;
|
||||
}
|
||||
|
||||
SkPdfArray* intervals = (SkPdfArray*)dash->objAtAIndex(0);
|
||||
int cnt = intervals->size();
|
||||
if (cnt >= 256) {
|
||||
// TODO(edisonn): report error/warning, unsuported;
|
||||
// TODO(edisonn): alloc memory
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
if (!intervals->objAtAIndex(i)->isNumber()) {
|
||||
// TODO(edisonn): report error/warning
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pdfContext->fGraphicsState.fDashPhase = dash->objAtAIndex(1)->scalarValue();
|
||||
pdfContext->fGraphicsState.fDashArrayLength = cnt;
|
||||
for (int i = 0 ; i < cnt; i++) {
|
||||
pdfContext->fGraphicsState.fDashArray[i] = intervals->objAtAIndex(i)->scalarValue();
|
||||
}
|
||||
}
|
||||
|
||||
void skpdfGraphicsStateApplyFont(PdfContext* pdfContext, SkPdfArray* fontAndSize) {
|
||||
if (!fontAndSize || fontAndSize->isArray() || fontAndSize->size() != 2 || !fontAndSize->objAtAIndex(0)->isName() || !fontAndSize->objAtAIndex(1)->isNumber()) {
|
||||
// TODO(edisonn): report error/warning
|
||||
return;
|
||||
}
|
||||
skpdfGraphicsStateApplyFontCore(pdfContext, fontAndSize->objAtAIndex(0), fontAndSize->objAtAIndex(1)->numberValue());
|
||||
}
|
||||
|
||||
void skpdfGraphicsStateApplyBM_name(PdfContext* pdfContext, const std::string& blendMode) {
|
||||
// TODO(edisonn): verify input
|
||||
}
|
||||
|
||||
void skpdfGraphicsStateApplyBM_array(PdfContext* pdfContext, SkPdfArray* blendModes) {
|
||||
// TODO(edisonn): verify input
|
||||
}
|
||||
|
||||
void skpdfGraphicsStateApplySMask_name(PdfContext* pdfContext, const std::string& sMask) {
|
||||
// TODO(edisonn): verify input
|
||||
}
|
||||
|
||||
void skpdfGraphicsStateApplySMask_dict(PdfContext* pdfContext, SkPdfDictionary* sMask) {
|
||||
// TODO(edisonn): verify input
|
||||
}
|
||||
|
||||
void skpdfGraphicsStateApplyAIS(PdfContext* pdfContext, bool alphaSource) {
|
||||
pdfContext->fGraphicsState.fAlphaSource = alphaSource;
|
||||
}
|
||||
|
||||
|
||||
//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 PdfResult PdfOp_gs(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLooper** looper) {
|
||||
@ -1550,16 +1637,60 @@ static PdfResult PdfOp_gs(PdfContext* pdfContext, SkCanvas* canvas, PdfTokenLoop
|
||||
return kIgnoreError_PdfResult;
|
||||
}
|
||||
|
||||
if (gs->has_CA()) {
|
||||
pdfContext->fGraphicsState.fStroking.fOpacity = gs->CA(pdfContext->fPdfDoc);
|
||||
if (gs->has_LW()) {
|
||||
skpdfGraphicsStateApplyLW(pdfContext, gs->LW(pdfContext->fPdfDoc));
|
||||
}
|
||||
|
||||
if (gs->has_LC()) {
|
||||
skpdfGraphicsStateApplyLC(pdfContext, gs->LC(pdfContext->fPdfDoc));
|
||||
}
|
||||
|
||||
if (gs->has_LJ()) {
|
||||
skpdfGraphicsStateApplyLJ(pdfContext, gs->LJ(pdfContext->fPdfDoc));
|
||||
}
|
||||
|
||||
if (gs->has_ML()) {
|
||||
skpdfGraphicsStateApplyML(pdfContext, gs->ML(pdfContext->fPdfDoc));
|
||||
}
|
||||
|
||||
if (gs->has_D()) {
|
||||
skpdfGraphicsStateApplyD(pdfContext, gs->D(pdfContext->fPdfDoc));
|
||||
}
|
||||
|
||||
if (gs->has_Font()) {
|
||||
skpdfGraphicsStateApplyFont(pdfContext, gs->Font(pdfContext->fPdfDoc));
|
||||
}
|
||||
|
||||
if (gs->has_BM()) {
|
||||
if (gs->isBMAName(pdfContext->fPdfDoc)) {
|
||||
skpdfGraphicsStateApplyBM_name(pdfContext, gs->getBMAsName(pdfContext->fPdfDoc));
|
||||
} else if (gs->isBMAArray(pdfContext->fPdfDoc)) {
|
||||
skpdfGraphicsStateApplyBM_array(pdfContext, gs->getBMAsArray(pdfContext->fPdfDoc));
|
||||
} else {
|
||||
// TODO(edisonn): report/warn
|
||||
}
|
||||
}
|
||||
|
||||
if (gs->has_SMask()) {
|
||||
if (gs->isSMaskAName(pdfContext->fPdfDoc)) {
|
||||
skpdfGraphicsStateApplySMask_name(pdfContext, gs->getSMaskAsName(pdfContext->fPdfDoc));
|
||||
} else if (gs->isSMaskADictionary(pdfContext->fPdfDoc)) {
|
||||
skpdfGraphicsStateApplySMask_dict(pdfContext, gs->getSMaskAsDictionary(pdfContext->fPdfDoc));
|
||||
} else {
|
||||
// TODO(edisonn): report/warn
|
||||
}
|
||||
}
|
||||
|
||||
if (gs->has_ca()) {
|
||||
pdfContext->fGraphicsState.fNonStroking.fOpacity = gs->ca(pdfContext->fPdfDoc);
|
||||
skpdfGraphicsStateApply_ca(pdfContext, gs->ca(pdfContext->fPdfDoc));
|
||||
}
|
||||
|
||||
if (gs->has_LW()) {
|
||||
pdfContext->fGraphicsState.fLineWidth = gs->LW(pdfContext->fPdfDoc);
|
||||
if (gs->has_CA()) {
|
||||
skpdfGraphicsStateApply_CA(pdfContext, gs->CA(pdfContext->fPdfDoc));
|
||||
}
|
||||
|
||||
if (gs->has_AIS()) {
|
||||
skpdfGraphicsStateApplyAIS(pdfContext, gs->AIS(pdfContext->fPdfDoc));
|
||||
}
|
||||
|
||||
return kNYI_PdfResult;
|
||||
@ -1993,9 +2124,9 @@ bool SkPdfRenderer::renderPage(int page, SkCanvas* canvas, const SkRect& dst) co
|
||||
SkTraceMatrix(pdfContext.fOriginalMatrix, "Original matrix");
|
||||
|
||||
|
||||
pdfContext.fGraphicsState.fMatrix = pdfContext.fOriginalMatrix;
|
||||
pdfContext.fGraphicsState.fMatrixTm = pdfContext.fGraphicsState.fMatrix;
|
||||
pdfContext.fGraphicsState.fMatrixTlm = pdfContext.fGraphicsState.fMatrix;
|
||||
pdfContext.fGraphicsState.fCTM = pdfContext.fOriginalMatrix;
|
||||
pdfContext.fGraphicsState.fMatrixTm = pdfContext.fGraphicsState.fCTM;
|
||||
pdfContext.fGraphicsState.fMatrixTlm = pdfContext.fGraphicsState.fCTM;
|
||||
|
||||
#ifndef PDF_DEBUG_NO_PAGE_CLIPING
|
||||
canvas->clipRect(dst, SkRegion::kIntersect_Op, true);
|
||||
|
@ -607,6 +607,17 @@ public:
|
||||
return fObjectType == kReal_PdfObjectType ? fRealValue : fIntegerValue;
|
||||
}
|
||||
|
||||
inline SkScalar scalarValue() const {
|
||||
SkASSERT(isNumber());
|
||||
|
||||
if (!isNumber()) {
|
||||
// TODO(edisonn): log err
|
||||
return SkIntToScalar(0);
|
||||
}
|
||||
return fObjectType == kReal_PdfObjectType ? SkDoubleToScalar(fRealValue) :
|
||||
SkIntToScalar(fIntegerValue);
|
||||
}
|
||||
|
||||
int referenceId() const {
|
||||
SkASSERT(fObjectType == kReference_PdfObjectType);
|
||||
return fRef.fId;
|
||||
|
@ -71,6 +71,7 @@
|
||||
],
|
||||
'dependencies': [
|
||||
'core.gyp:core',
|
||||
'effects.gyp:effects',
|
||||
'images.gyp:images',
|
||||
'zlib.gyp:zlib',
|
||||
],
|
||||
|
Loading…
Reference in New Issue
Block a user