blob: abda00fe3b90efcb82c93cd8137246d9eabffac1 [file] [log] [blame]
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPdfGraphicsState_DEFINED
#define SkPdfGraphicsState_DEFINED
#include "SkCanvas.h"
#include "SkPaint.h"
#include "SkPdfConfig.h"
#include "SkPdfUtils.h"
//#include "SkTDStack.h"
class SkPdfFont;
class SkPdfDoc;
class SkPdfNativeObject;
class SkPdfResourceDictionary;
class SkPdfSoftMaskDictionary;
class SkPdfNativeDoc;
class SkPdfAllocator;
// TODO(edisonn): move this class in include/core?
// Ref objects can't be dealt unless we use a specific class initialization
// The difference between SkTDStackNew and SkTDStack is that SkTDStackNew uses new/delete
// to be a manage c++ stuff (like initializations)
// Adobe limits it to 28, so 256 should be more than enough
#define MAX_NESTING 256
#include "SkTypes.h"
template <typename T> class SkTDStackNew : SkNoncopyable {
public:
SkTDStackNew() : fCount(0), fTotalCount(0), fLocalCount(0) {
fInitialRec.fNext = NULL;
fRec = &fInitialRec;
// fCount = kSlotCount;
}
~SkTDStackNew() {
Rec* rec = fRec;
while (rec != &fInitialRec) {
Rec* next = rec->fNext;
delete rec;
rec = next;
}
}
int count() const { return fLocalCount; }
int depth() const { return fLocalCount; }
bool empty() const { return fLocalCount == 0; }
bool nests() {
return fNestingLevel;
}
void nest() {
// We are are past max nesting levels, we will still continue to work, but we might fail
// to properly ignore errors. Ideally it should only mean poor rendering in exceptional
// cases
if (fNestingLevel >= 0 && fNestingLevel < MAX_NESTING) {
fNestings[fNestingLevel] = fLocalCount;
fLocalCount = 0;
}
fNestingLevel++;
}
void unnest() {
SkASSERT(fNestingLevel > 0);
fNestingLevel--;
if (fNestingLevel >= 0 && fNestingLevel < MAX_NESTING) {
// TODO(edisonn): warn if fLocal > 0
while (fLocalCount > 0) {
pop();
}
fLocalCount = fNestings[fNestingLevel];
}
}
T* push() {
SkASSERT(fCount <= kSlotCount);
if (fCount == kSlotCount) {
Rec* rec = new Rec();
rec->fNext = fRec;
fRec = rec;
fCount = 0;
}
++fTotalCount;
++fLocalCount;
return &fRec->fSlots[fCount++];
}
void push(const T& elem) { *this->push() = elem; }
const T& index(int idx) const {
SkASSERT(fRec && fCount > idx);
return fRec->fSlots[fCount - idx - 1];
}
T& index(int idx) {
SkASSERT(fRec && fCount > idx);
return fRec->fSlots[fCount - idx - 1];
}
const T& top() const {
SkASSERT(fRec && fCount > 0);
return fRec->fSlots[fCount - 1];
}
T& top() {
SkASSERT(fRec && fCount > 0);
return fRec->fSlots[fCount - 1];
}
void pop(T* elem) {
if (elem) {
*elem = fRec->fSlots[fCount - 1];
}
this->pop();
}
void pop() {
SkASSERT(fCount > 0 && fRec);
--fLocalCount;
--fTotalCount;
if (--fCount == 0) {
if (fRec != &fInitialRec) {
Rec* rec = fRec->fNext;
delete fRec;
fCount = kSlotCount;
fRec = rec;
} else {
SkASSERT(fTotalCount == 0);
}
}
}
private:
enum {
kSlotCount = 64
};
struct Rec;
friend struct Rec;
struct Rec {
Rec* fNext;
T fSlots[kSlotCount];
};
Rec fInitialRec;
Rec* fRec;
int fCount, fTotalCount, fLocalCount;
int fNestings[MAX_NESTING];
int fNestingLevel;
};
// TODO(edisonn): better class design.
class 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*
// TODO(edisonn): remove this public, let fields be private
// TODO(edisonn): make color space an enum!
public:
NotOwnedString fColorSpace;
SkPdfNativeObject* fPattern;
/*
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.
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() : fPattern(NULL), fColor(SK_ColorBLACK), fOpacity(1) {
NotOwnedString::init(&fColorSpace, "DeviceRGB");
}
void setColorSpace(NotOwnedString* colorSpace) {
fColorSpace = *colorSpace;
fPattern = NULL;
}
void setPatternColorSpace(SkPdfNativeObject* pattern) {
fColorSpace.fBuffer = (const unsigned char*)"Pattern";
fColorSpace.fBytes = 7; // strlen("Pattern")
fPattern = pattern;
}
void applyGraphicsState(SkPaint* paint) {
paint->setColor(SkColorSetA(fColor, (U8CPU)(fOpacity * 255)));
}
};
// TODO(edisonn): better class design.
struct SkPdfGraphicsState {
// TODO(edisonn): deprecate and remove these!
double fCurPosX;
double fCurPosY;
double fCurFontSize;
bool fTextBlock;
SkPdfFont* fSkFont;
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;
SkMatrix fContentStreamMatrix;
/*
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;
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;
/*
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 fBlendModes[256];
int fBlendModesLength;
/*
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.
*/
SkPdfSoftMaskDictionary* fSoftMaskDictionary;
// TODO(edisonn): make sMask private, add setter and getter, ref/unref/..., at the moment we most likely leask
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;
fCTM = SkMatrix::I();
fMatrixTm = SkMatrix::I();
fMatrixTlm = SkMatrix::I();
fPathClosed = true;
fLineWidth = 0;
fTextLeading = 0;
fWordSpace = 0;
fCharSpace = 0;
fHasClipPathToApply = false;
fResources = NULL;
fSkFont = NULL;
fLineCap = 0;
fLineJoin = 0;
fMiterLimit = 10.0;
fAphaConstant = 1.0;
fAlphaSource = false;
fDashArrayLength = 0;
fDashPhase = 0;
fBlendModesLength = 1;
fBlendModes[0] = SkXfermode::kSrc_Mode; // PDF: Normal Blend mode
fSMask = NULL;
}
// TODO(edisonn): make two functons instead, stroking and non stoking, avoid branching
void applyGraphicsState(SkPaint* paint, bool stroking);
};
// TODO(edisonn): better class design.
// TODO(edisonn): rename to SkPdfContext
class SkPdfContext {
public:
SkTDStackNew<SkPdfNativeObject*> fObjectStack;
SkTDStackNew<SkPdfGraphicsState> fStateStack;
SkPdfGraphicsState fGraphicsState;
SkPdfNativeDoc* fPdfDoc;
// TODO(edisonn): the allocator, could be freed after the page is done drawing.
SkPdfAllocator* fTmpPageAllocator;
SkMatrix fOriginalMatrix;
SkPdfContext(SkPdfNativeDoc* doc);
~SkPdfContext();
};
#endif // SkPdfGraphicsState_DEFINED