[PDF] Refactor content stream creation in SkPDFDevice to support more xfermodes.
Instead of writing all drawing and state updates into the final content stream immediately, this change creates a new ContentEntry each time the transform, clip, or paint changes. Drawing is done into a stream in the ContentEntry. When the consumer asks for the content, we combine all the ContentEntries with appropriate updates to the state (clip, transform, paint) in between. This allows us to modify the clip even after a drawing has completed. It also lets us remove ContentEntries with no drawing. Further optimization can be done to better use the stack features of PDF, for now we follow the previous model of having a single clip followed by a single transform on the graphic state stack. Push rectangle logic into SkPDFUtil::AppendRectangle. Change private functions to adhere to coding standards. Review URL: http://codereview.appspot.com/4459041 git-svn-id: http://skia.googlecode.com/svn/trunk@1269 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
7744c205f2
commit
9fbdf87518
@ -42,6 +42,7 @@ public:
|
||||
B2FIter(const SkClipStack& stack);
|
||||
|
||||
struct Clip {
|
||||
friend bool operator==(const Clip& a, const Clip& b);
|
||||
const SkRect* fRect; // if non-null, this is a rect clip
|
||||
const SkPath* fPath; // if non-null, this is a path clip
|
||||
SkRegion::Op fOp;
|
||||
|
@ -17,11 +17,12 @@
|
||||
#ifndef SkPDFDevice_DEFINED
|
||||
#define SkPDFDevice_DEFINED
|
||||
|
||||
#include "SkRefCnt.h"
|
||||
#include "SkDevice.h"
|
||||
#include "SkStream.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkRefCnt.h"
|
||||
#include "SkStream.h"
|
||||
#include "SkTScopedPtr.h"
|
||||
|
||||
class SkPDFArray;
|
||||
class SkPDFDevice;
|
||||
@ -32,6 +33,10 @@ class SkPDFObject;
|
||||
class SkPDFShader;
|
||||
class SkPDFStream;
|
||||
|
||||
// Private classes.
|
||||
struct ContentEntry;
|
||||
struct GraphicStateEntry;
|
||||
|
||||
class SkPDFDeviceFactory : public SkDeviceFactory {
|
||||
virtual SkDevice* newDevice(SkCanvas*, SkBitmap::Config, int width,
|
||||
int height, bool isOpaque, bool isForLayer);
|
||||
@ -70,13 +75,6 @@ public:
|
||||
|
||||
virtual void clear(SkColor color);
|
||||
|
||||
/** Called with the correct matrix and clip before this device is drawn
|
||||
to using those settings. If your subclass overrides this, be sure to
|
||||
call through to the base class as well.
|
||||
*/
|
||||
virtual void setMatrixClip(const SkMatrix&, const SkRegion&,
|
||||
const SkClipStack&);
|
||||
|
||||
virtual bool readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
|
||||
return false;
|
||||
}
|
||||
@ -141,7 +139,10 @@ protected:
|
||||
|
||||
private:
|
||||
SkISize fPageSize;
|
||||
SkISize fContentSize;
|
||||
SkMatrix fInitialTransform;
|
||||
SkClipStack fExistingClipStack;
|
||||
SkRegion fExistingClipRegion;
|
||||
SkRefPtr<SkPDFDict> fResourceDict;
|
||||
|
||||
SkTDArray<SkPDFGraphicState*> fGraphicStateResources;
|
||||
@ -149,49 +150,45 @@ private:
|
||||
SkTDArray<SkPDFFont*> fFontResources;
|
||||
SkTDArray<SkPDFShader*> fShaderResources;
|
||||
|
||||
// In PDF, transforms and clips can only be undone by popping the graphic
|
||||
// state to before the transform or clip was applied. Because it can be
|
||||
// a lot of work to reapply a clip and because this class has to apply
|
||||
// different transforms to accomplish various operations, the clip is
|
||||
// always applied before a transform and always at a different graphic
|
||||
// state-stack level than a transform. This strategy results in the
|
||||
// following possible states for the graphic state stack:
|
||||
// empty: (identity transform and clip to page)
|
||||
// one entry: a transform
|
||||
// one entry: a clip
|
||||
// two entries: a clip and then a transform
|
||||
// Pointers are owned by the respective Resources list.
|
||||
struct GraphicStackEntry {
|
||||
SkColor fColor;
|
||||
SkScalar fTextSize;
|
||||
SkScalar fTextScaleX;
|
||||
SkPaint::Style fTextFill;
|
||||
SkPDFFont* fFont;
|
||||
SkPDFShader* fShader;
|
||||
SkPDFGraphicState* fGraphicState;
|
||||
SkRegion fClip;
|
||||
SkMatrix fTransform;
|
||||
};
|
||||
struct GraphicStackEntry fGraphicStack[3];
|
||||
int fGraphicStackIndex;
|
||||
|
||||
SkDynamicMemoryWStream fContent;
|
||||
SkTScopedPtr<ContentEntry> fContentEntries;
|
||||
ContentEntry* fCurrentContentEntry;
|
||||
|
||||
void init();
|
||||
void cleanUp();
|
||||
void updateGSFromPaint(const SkPaint& newPaint, bool forText);
|
||||
void setExistingClip(const SkClipStack& clipStack,
|
||||
const SkRegion& clipRegion);
|
||||
|
||||
void setUpContentEntry(const SkClipStack& clipStack,
|
||||
const SkRegion& clipRegion,
|
||||
const SkMatrix& matrix,
|
||||
const SkPaint& paint,
|
||||
bool hasText = false);
|
||||
void setUpContentEntryForText(const SkClipStack& clipStack,
|
||||
const SkRegion& clipRegion,
|
||||
const SkMatrix& matrix,
|
||||
const SkPaint& paint);
|
||||
void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
|
||||
const SkClipStack& clipStack,
|
||||
const SkRegion& clipRegion,
|
||||
const SkPaint& paint,
|
||||
bool hasText,
|
||||
GraphicStateEntry* entry);
|
||||
|
||||
void updateFont(const SkPaint& paint, uint16_t glyphID);
|
||||
int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
|
||||
|
||||
void pushGS();
|
||||
void popGS();
|
||||
void setTextTransform(SkScalar x, SkScalar y, SkScalar textSkewX);
|
||||
void internalDrawPaint(const SkPaint& paint);
|
||||
void internalDrawRect(const SkRect& r, const SkPaint& paint);
|
||||
void internalDrawBitmap(const SkMatrix& matrix, const SkBitmap& bitmap,
|
||||
const SkIRect* srcRect, const SkPaint& paint);
|
||||
|
||||
SkMatrix setTransform(const SkMatrix& matrix);
|
||||
void internalDrawPaint(const SkPaint& paint);
|
||||
void internalDrawBitmap(const SkMatrix& matrix,
|
||||
const SkClipStack& clipStack,
|
||||
const SkRegion& clipRegion,
|
||||
const SkBitmap& bitmap,
|
||||
const SkIRect* srcRect,
|
||||
const SkPaint& paint);
|
||||
|
||||
// Disable the default copy and assign implementation.
|
||||
SkPDFDevice(const SkPDFDevice&);
|
||||
void operator=(const SkPDFDevice&);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -22,6 +22,7 @@
|
||||
class SkMatrix;
|
||||
class SkPath;
|
||||
class SkPDFArray;
|
||||
class SkRect;
|
||||
|
||||
#if 0
|
||||
#define PRINT_NOT_IMPL(str) fprintf(stderr, str)
|
||||
@ -47,8 +48,7 @@ public:
|
||||
static void AppendCubic(SkScalar ctl1X, SkScalar ctl1Y,
|
||||
SkScalar ctl2X, SkScalar ctl2Y,
|
||||
SkScalar dstX, SkScalar dstY, SkWStream* content);
|
||||
static void AppendRectangle(SkScalar x, SkScalar y, SkScalar w, SkScalar h,
|
||||
SkWStream* content);
|
||||
static void AppendRectangle(const SkRect& rect, SkWStream* content);
|
||||
static void EmitPath(const SkPath& path, SkWStream* content);
|
||||
static void ClosePath(SkWStream* content);
|
||||
static void PaintPath(SkPaint::Style style, SkPath::FillType fill,
|
||||
|
@ -181,6 +181,13 @@ void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op) {
|
||||
SkClipStack::B2FIter::B2FIter() {
|
||||
}
|
||||
|
||||
bool operator==(const SkClipStack::B2FIter::Clip& a,
|
||||
const SkClipStack::B2FIter::Clip& b) {
|
||||
return a.fOp == b.fOp &&
|
||||
((a.fRect == NULL && b.fRect == NULL) || *a.fRect == *b.fRect) &&
|
||||
((a.fPath == NULL && b.fPath == NULL) || *a.fPath == *b.fPath);
|
||||
}
|
||||
|
||||
SkClipStack::B2FIter::B2FIter(const SkClipStack& stack) {
|
||||
this->reset(stack);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -85,15 +85,17 @@ void SkPDFUtils::AppendCubic(SkScalar ctl1X, SkScalar ctl1Y,
|
||||
}
|
||||
|
||||
// static
|
||||
void SkPDFUtils::AppendRectangle(SkScalar x, SkScalar y,
|
||||
SkScalar w, SkScalar h, SkWStream* content) {
|
||||
SkPDFScalar::Append(x, content);
|
||||
void SkPDFUtils::AppendRectangle(const SkRect& rect, SkWStream* content) {
|
||||
// Skia has 0,0 at top left, pdf at bottom left. Do the right thing.
|
||||
SkScalar bottom = SkMinScalar(rect.fBottom, rect.fTop);
|
||||
|
||||
SkPDFScalar::Append(rect.fLeft, content);
|
||||
content->writeText(" ");
|
||||
SkPDFScalar::Append(y, content);
|
||||
SkPDFScalar::Append(bottom, content);
|
||||
content->writeText(" ");
|
||||
SkPDFScalar::Append(w, content);
|
||||
SkPDFScalar::Append(rect.width(), content);
|
||||
content->writeText(" ");
|
||||
SkPDFScalar::Append(h, content);
|
||||
SkPDFScalar::Append(rect.height(), content);
|
||||
content->writeText(" re\n");
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user