aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/pdf/SkPDFDevice.h38
-rw-r--r--src/pdf/SkPDFDevice.cpp361
2 files changed, 213 insertions, 186 deletions
diff --git a/include/pdf/SkPDFDevice.h b/include/pdf/SkPDFDevice.h
index b6c1389100..7d093dc5d9 100644
--- a/include/pdf/SkPDFDevice.h
+++ b/include/pdf/SkPDFDevice.h
@@ -17,6 +17,7 @@
#ifndef SkPDFDevice_DEFINED
#define SkPDFDevice_DEFINED
+#include "SkCanvas.h"
#include "SkDevice.h"
#include "SkPaint.h"
#include "SkPath.h"
@@ -35,6 +36,7 @@ class SkPDFShader;
class SkPDFStream;
// Private classes.
+class ContentEntryAccessor;
struct ContentEntry;
struct GraphicStateEntry;
@@ -141,6 +143,9 @@ protected:
private:
friend class SkPDFDeviceFactory;
+ // TODO(vandebo) push most of SkPDFDevice's state into a core object in
+ // order to get the right access levels without using friend.
+ friend class ContentEntryAccessor;
SkISize fPageSize;
SkISize fContentSize;
@@ -155,8 +160,7 @@ private:
SkTDArray<SkPDFShader*> fShaderResources;
SkTScopedPtr<ContentEntry> fContentEntries;
- ContentEntry* fCurrentContentEntry;
- SkRefPtr<SkPDFFormXObject> fDstFormXObject;
+ ContentEntry* fLastContentEntry;
// For use by the DeviceFactory.
SkPDFDevice(const SkISize& layerSize, const SkClipStack& existingClipStack,
@@ -174,18 +178,18 @@ private:
const SkRegion& clipRegion,
bool invertClip);
- // If the paint or clip is such that we shouldn't draw anything, these
- // return false and do not create a content entry.
- bool setUpContentEntry(const SkClipStack* clipStack,
- const SkRegion& clipRegion,
- const SkMatrix& matrix,
- const SkPaint& paint,
- bool hasText = false);
- bool setUpContentEntryForText(const SkClipStack* clipStack,
- const SkRegion& clipRegion,
- const SkMatrix& matrix,
- const SkPaint& paint);
- void finishContentEntry(const SkPaint& paint);
+ // If the paint or clip is such that we shouldn't draw anything, this
+ // returns NULL and does not create a content entry.
+ // setUpContentEntry and finishContentEntry can be used directly, but
+ // the preferred method is to use the ContentEntryAccessor helper class.
+ ContentEntry* setUpContentEntry(const SkClipStack* clipStack,
+ const SkRegion& clipRegion,
+ const SkMatrix& matrix,
+ const SkPaint& paint,
+ bool hasText,
+ SkRefPtr<SkPDFFormXObject>* dst);
+ void finishContentEntry(SkXfermode::Mode xfermode,
+ SkPDFFormXObject* dst);
bool isContentEmpty();
void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
@@ -196,11 +200,11 @@ private:
GraphicStateEntry* entry);
int addGraphicStateResource(SkPDFGraphicState* gs);
- void updateFont(const SkPaint& paint, uint16_t glyphID);
+ void updateFont(const SkPaint& paint, uint16_t glyphID,
+ ContentEntry* contentEntry);
int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
- void setTextTransform(SkScalar x, SkScalar y, SkScalar textSkewX);
- void internalDrawPaint(const SkPaint& paint);
+ void internalDrawPaint(const SkPaint& paint, ContentEntry* contentEntry);
void internalDrawBitmap(const SkMatrix& matrix,
const SkClipStack* clipStack,
const SkRegion& clipRegion,
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 69cf804ca3..316cd7c896 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -106,6 +106,19 @@ static void align_text(SkDrawCacheProc glyphCacheProc, const SkPaint& paint,
*y = *y - yAdj;
}
+static void set_text_transform(SkScalar x, SkScalar y, SkScalar textSkewX,
+ SkWStream* content) {
+ // Flip the text about the x-axis to account for origin swap and include
+ // the passed parameters.
+ content->writeText("1 0 ");
+ SkPDFScalar::Append(0 - textSkewX, content);
+ content->writeText(" -1 ");
+ SkPDFScalar::Append(x, content);
+ content->writeText(" ");
+ SkPDFScalar::Append(y, content);
+ content->writeText(" Tm\n");
+}
+
// It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the
// later being our representation of an object in the PDF file.
struct GraphicStateEntry {
@@ -159,12 +172,6 @@ bool GraphicStateEntry::compareInitialState(const GraphicStateEntry& b) {
(fTextScaleX == b.fTextScaleX && fTextFill == b.fTextFill));
}
-struct ContentEntry {
- GraphicStateEntry fState;
- SkDynamicMemoryWStream fContent;
- SkTScopedPtr<ContentEntry> fNext;
-};
-
class GraphicStackState {
public:
GraphicStackState(const SkClipStack& existingClipStack,
@@ -398,6 +405,56 @@ void GraphicStackState::updateDrawingState(const GraphicStateEntry& state) {
}
}
+struct ContentEntry {
+ GraphicStateEntry fState;
+ SkDynamicMemoryWStream fContent;
+ SkTScopedPtr<ContentEntry> fNext;
+};
+
+// A helper class to automatically finish a ContentEntry at the end of a
+// drawing method and maintain the state needed between set up and finish.
+class ContentEntryAccessor {
+public:
+ ContentEntryAccessor(SkPDFDevice* device, const SkDraw& draw,
+ const SkPaint& paint, bool hasText = false)
+ : fDevice(device),
+ fContentEntry(NULL),
+ fXfermode(SkXfermode::kSrcOver_Mode) {
+ init(draw.fClipStack, *draw.fClip, *draw.fMatrix, paint, hasText);
+ }
+ ContentEntryAccessor(SkPDFDevice* device, const SkClipStack* clipStack,
+ const SkRegion& clipRegion, const SkMatrix& matrix,
+ const SkPaint& paint, bool hasText = false)
+ : fDevice(device),
+ fContentEntry(NULL),
+ fXfermode(SkXfermode::kSrcOver_Mode) {
+ init(clipStack, clipRegion, matrix, paint, hasText);
+ }
+
+ ~ContentEntryAccessor() {
+ if (fContentEntry) {
+ fDevice->finishContentEntry(fXfermode, fDstFormXObject.get());
+ }
+ }
+
+ ContentEntry* entry() { return fContentEntry; }
+private:
+ SkPDFDevice* fDevice;
+ ContentEntry* fContentEntry;
+ SkXfermode::Mode fXfermode;
+ SkRefPtr<SkPDFFormXObject> fDstFormXObject;
+
+ void init(const SkClipStack* clipStack, const SkRegion& clipRegion,
+ const SkMatrix& matrix, const SkPaint& paint, bool hasText) {
+ if (paint.getXfermode()) {
+ paint.getXfermode()->asMode(&fXfermode);
+ }
+ fContentEntry = fDevice->setUpContentEntry(clipStack, clipRegion,
+ matrix, paint, hasText,
+ &fDstFormXObject);
+ }
+};
+
////////////////////////////////////////////////////////////////////////////////
SkDevice* SkPDFDeviceFactory::newDevice(SkCanvas* c, SkBitmap::Config config,
@@ -440,7 +497,7 @@ SkPDFDevice::SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize,
: SkDevice(NULL, makeContentBitmap(contentSize, &initialTransform), false),
fPageSize(pageSize),
fContentSize(contentSize),
- fCurrentContentEntry(NULL) {
+ fLastContentEntry(NULL) {
// Skia generally uses the top left as the origin but PDF natively has the
// origin at the bottom left. This matrix corrects for that. But that only
// needs to be done once, we don't do it when layering.
@@ -463,7 +520,7 @@ SkPDFDevice::SkPDFDevice(const SkISize& layerSize,
fContentSize(layerSize),
fExistingClipStack(existingClipStack),
fExistingClipRegion(existingClipRegion),
- fCurrentContentEntry(NULL) {
+ fLastContentEntry(NULL) {
fInitialTransform.reset();
this->init();
}
@@ -475,7 +532,7 @@ SkPDFDevice::~SkPDFDevice() {
void SkPDFDevice::init() {
fResourceDict = NULL;
fContentEntries.reset();
- fCurrentContentEntry = NULL;
+ fLastContentEntry = NULL;
}
SkDeviceFactory* SkPDFDevice::onNewDeviceFactory() {
@@ -498,39 +555,35 @@ void SkPDFDevice::clear(SkColor color) {
paint.setStyle(SkPaint::kFill_Style);
SkMatrix identity;
identity.reset();
- if (!setUpContentEntry(&fExistingClipStack, fExistingClipRegion, identity,
- paint)) {
- return;
- }
-
- internalDrawPaint(paint);
- finishContentEntry(paint);
+ ContentEntryAccessor content(this, &fExistingClipStack, fExistingClipRegion,
+ identity, paint);
+ internalDrawPaint(paint, content.entry());
}
void SkPDFDevice::drawPaint(const SkDraw& d, const SkPaint& paint) {
SkPaint newPaint = paint;
newPaint.setStyle(SkPaint::kFill_Style);
- if (!setUpContentEntry(d.fClipStack, *d.fClip, *d.fMatrix, newPaint)) {
- return;
- }
-
- internalDrawPaint(newPaint);
- finishContentEntry(newPaint);
+ ContentEntryAccessor content(this, d, newPaint);
+ internalDrawPaint(newPaint, content.entry());
}
-void SkPDFDevice::internalDrawPaint(const SkPaint& paint) {
+void SkPDFDevice::internalDrawPaint(const SkPaint& paint,
+ ContentEntry* contentEntry) {
+ if (!contentEntry) {
+ return;
+ }
SkRect bbox = SkRect::MakeWH(SkIntToScalar(this->width()),
SkIntToScalar(this->height()));
SkMatrix totalTransform = fInitialTransform;
- totalTransform.preConcat(fCurrentContentEntry->fState.fMatrix);
+ totalTransform.preConcat(contentEntry->fState.fMatrix);
SkMatrix inverse;
inverse.reset();
totalTransform.invert(&inverse);
inverse.mapRect(&bbox);
- SkPDFUtils::AppendRectangle(bbox, &fCurrentContentEntry->fContent);
+ SkPDFUtils::AppendRectangle(bbox, &contentEntry->fContent);
SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType,
- &fCurrentContentEntry->fContent);
+ &contentEntry->fContent);
}
void SkPDFDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode,
@@ -577,44 +630,43 @@ void SkPDFDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode,
}
}
-
- if (!setUpContentEntry(d.fClipStack, *d.fClip, *d.fMatrix, *paint)) {
+ ContentEntryAccessor content(this, d, *paint);
+ if (!content.entry()) {
return;
}
switch (mode) {
case SkCanvas::kPolygon_PointMode:
SkPDFUtils::MoveTo(points[0].fX, points[0].fY,
- &fCurrentContentEntry->fContent);
+ &content.entry()->fContent);
for (size_t i = 1; i < count; i++) {
SkPDFUtils::AppendLine(points[i].fX, points[i].fY,
- &fCurrentContentEntry->fContent);
+ &content.entry()->fContent);
}
- SkPDFUtils::StrokePath(&fCurrentContentEntry->fContent);
+ SkPDFUtils::StrokePath(&content.entry()->fContent);
break;
case SkCanvas::kLines_PointMode:
for (size_t i = 0; i < count/2; i++) {
SkPDFUtils::MoveTo(points[i * 2].fX, points[i * 2].fY,
- &fCurrentContentEntry->fContent);
+ &content.entry()->fContent);
SkPDFUtils::AppendLine(points[i * 2 + 1].fX,
points[i * 2 + 1].fY,
- &fCurrentContentEntry->fContent);
- SkPDFUtils::StrokePath(&fCurrentContentEntry->fContent);
+ &content.entry()->fContent);
+ SkPDFUtils::StrokePath(&content.entry()->fContent);
}
break;
case SkCanvas::kPoints_PointMode:
SkASSERT(paint->getStrokeCap() == SkPaint::kRound_Cap);
for (size_t i = 0; i < count; i++) {
SkPDFUtils::MoveTo(points[i].fX, points[i].fY,
- &fCurrentContentEntry->fContent);
- SkPDFUtils::ClosePath(&fCurrentContentEntry->fContent);
- SkPDFUtils::StrokePath(&fCurrentContentEntry->fContent);
+ &content.entry()->fContent);
+ SkPDFUtils::ClosePath(&content.entry()->fContent);
+ SkPDFUtils::StrokePath(&content.entry()->fContent);
}
break;
default:
SkASSERT(false);
}
- finishContentEntry(*paint);
}
void SkPDFDevice::drawRect(const SkDraw& d, const SkRect& r,
@@ -628,14 +680,14 @@ void SkPDFDevice::drawRect(const SkDraw& d, const SkRect& r,
drawPath(d, path, paint, NULL, true);
return;
}
- if (!setUpContentEntry(d.fClipStack, *d.fClip, *d.fMatrix, paint)) {
+
+ ContentEntryAccessor content(this, d, paint);
+ if (!content.entry()) {
return;
}
-
- SkPDFUtils::AppendRectangle(r, &fCurrentContentEntry->fContent);
+ SkPDFUtils::AppendRectangle(r, &content.entry()->fContent);
SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType,
- &fCurrentContentEntry->fContent);
- finishContentEntry(paint);
+ &content.entry()->fContent);
}
void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& origPath,
@@ -681,13 +733,13 @@ void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& origPath,
return;
}
- if (!setUpContentEntry(d.fClipStack, *d.fClip, *d.fMatrix, paint)) {
+ ContentEntryAccessor content(this, d, paint);
+ if (!content.entry()) {
return;
}
- SkPDFUtils::EmitPath(*pathPtr, &fCurrentContentEntry->fContent);
+ SkPDFUtils::EmitPath(*pathPtr, &content.entry()->fContent);
SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(),
- &fCurrentContentEntry->fContent);
- finishContentEntry(paint);
+ &content.entry()->fContent);
}
void SkPDFDevice::drawBitmap(const SkDraw& d, const SkBitmap& bitmap,
@@ -717,8 +769,8 @@ void SkPDFDevice::drawSprite(const SkDraw& d, const SkBitmap& bitmap,
void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
SkScalar x, SkScalar y, const SkPaint& paint) {
SkPaint textPaint = calculate_text_paint(paint);
- if (!setUpContentEntryForText(d.fClipStack, *d.fClip, *d.fMatrix,
- textPaint)) {
+ ContentEntryAccessor content(this, d, textPaint, true);
+ if (!content.entry()) {
return;
}
@@ -746,23 +798,24 @@ void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
align_text(glyphCacheProc, textPaint, glyphIDs, numGlyphs, &x, &y,
widthPtr);
- fCurrentContentEntry->fContent.writeText("BT\n");
- setTextTransform(x, y, textPaint.getTextSkewX());
+ content.entry()->fContent.writeText("BT\n");
+ set_text_transform(x, y, textPaint.getTextSkewX(),
+ &content.entry()->fContent);
size_t consumedGlyphCount = 0;
while (numGlyphs > consumedGlyphCount) {
- updateFont(textPaint, glyphIDs[consumedGlyphCount]);
- SkPDFFont* font = fCurrentContentEntry->fState.fFont;
+ updateFont(textPaint, glyphIDs[consumedGlyphCount], content.entry());
+ SkPDFFont* font = content.entry()->fState.fFont;
size_t availableGlyphs =
font->glyphsToPDFFontEncoding(glyphIDs + consumedGlyphCount,
numGlyphs - consumedGlyphCount);
SkString encodedString =
SkPDFString::formatString(glyphIDs + consumedGlyphCount,
availableGlyphs, font->multiByteGlyphs());
- fCurrentContentEntry->fContent.writeText(encodedString.c_str());
+ content.entry()->fContent.writeText(encodedString.c_str());
consumedGlyphCount += availableGlyphs;
- fCurrentContentEntry->fContent.writeText(" Tj\n");
+ content.entry()->fContent.writeText(" Tj\n");
}
- fCurrentContentEntry->fContent.writeText("ET\n");
+ content.entry()->fContent.writeText("ET\n");
// Draw underline and/or strikethrough if the paint has them.
// drawPosText() and drawTextOnPath() don't draw underline or strikethrough
@@ -783,7 +836,6 @@ void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
drawRect(d, r, paint);
}
}
- finishContentEntry(textPaint);
}
void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
@@ -791,8 +843,8 @@ void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
int scalarsPerPos, const SkPaint& paint) {
SkASSERT(1 == scalarsPerPos || 2 == scalarsPerPos);
SkPaint textPaint = calculate_text_paint(paint);
- if (!setUpContentEntryForText(d.fClipStack, *d.fClip, *d.fMatrix,
- textPaint)) {
+ ContentEntryAccessor content(this, d, textPaint, true);
+ if (!content.entry()) {
return;
}
@@ -814,28 +866,28 @@ void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
}
SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
- fCurrentContentEntry->fContent.writeText("BT\n");
- updateFont(textPaint, glyphIDs[0]);
+ content.entry()->fContent.writeText("BT\n");
+ updateFont(textPaint, glyphIDs[0], content.entry());
for (size_t i = 0; i < numGlyphs; i++) {
- SkPDFFont* font = fCurrentContentEntry->fState.fFont;
+ SkPDFFont* font = content.entry()->fState.fFont;
uint16_t encodedValue = glyphIDs[i];
if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) {
- updateFont(textPaint, glyphIDs[i]);
+ updateFont(textPaint, glyphIDs[i], content.entry());
i--;
continue;
}
SkScalar x = pos[i * scalarsPerPos];
SkScalar y = scalarsPerPos == 1 ? constY : pos[i * scalarsPerPos + 1];
align_text(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y, NULL);
- setTextTransform(x, y, textPaint.getTextSkewX());
+ set_text_transform(x, y, textPaint.getTextSkewX(),
+ &content.entry()->fContent);
SkString encodedString =
SkPDFString::formatString(&encodedValue, 1,
font->multiByteGlyphs());
- fCurrentContentEntry->fContent.writeText(encodedString.c_str());
- fCurrentContentEntry->fContent.writeText(" Tj\n");
+ content.entry()->fContent.writeText(encodedString.c_str());
+ content.entry()->fContent.writeText(" Tj\n");
}
- fCurrentContentEntry->fContent.writeText("ET\n");
- finishContentEntry(textPaint);
+ content.entry()->fContent.writeText("ET\n");
}
void SkPDFDevice::drawTextOnPath(const SkDraw& d, const void* text, size_t len,
@@ -868,7 +920,8 @@ void SkPDFDevice::drawDevice(const SkDraw& d, SkDevice* device, int x, int y,
SkMatrix matrix;
matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
- if (!setUpContentEntry(d.fClipStack, *d.fClip, matrix, paint)) {
+ ContentEntryAccessor content(this, d.fClipStack, *d.fClip, matrix, paint);
+ if (!content.entry()) {
return;
}
@@ -877,8 +930,7 @@ void SkPDFDevice::drawDevice(const SkDraw& d, SkDevice* device, int x, int y,
SkPDFFormXObject* xobject = new SkPDFFormXObject(pdfDevice);
fXObjectResources.push(xobject); // Transfer reference.
SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
- &fCurrentContentEntry->fContent);
- finishContentEntry(paint);
+ &content.entry()->fContent);
}
const SkRefPtr<SkPDFDict>& SkPDFDevice::getResourceDict() {
@@ -1069,29 +1121,32 @@ void SkPDFDevice::drawFormXObjectWithClip(SkPDFFormXObject* xobject,
sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref.
// Draw the xobject with the clip as a mask.
- setUpContentEntry(&fExistingClipStack, fExistingClipRegion, identity,
- stockPaint);
+ ContentEntryAccessor content(this, &fExistingClipStack, fExistingClipRegion,
+ identity, stockPaint);
+ if (!content.entry()) {
+ return;
+ }
SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
- &fCurrentContentEntry->fContent);
+ &content.entry()->fContent);
SkPDFUtils::DrawFormXObject(fXObjectResources.count(),
- &fCurrentContentEntry->fContent);
+ &content.entry()->fContent);
fXObjectResources.push(xobject);
xobject->ref();
sMaskGS = SkPDFGraphicState::getNoSMaskGraphicState();
sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref.
SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
- &fCurrentContentEntry->fContent);
- finishContentEntry(stockPaint);
+ &content.entry()->fContent);
}
-bool SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
- const SkRegion& clipRegion,
- const SkMatrix& matrix,
- const SkPaint& paint,
- bool hasText) {
+ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
+ const SkRegion& clipRegion,
+ const SkMatrix& matrix,
+ const SkPaint& paint,
+ bool hasText,
+ SkRefPtr<SkPDFFormXObject>* dst) {
if (clipRegion.isEmpty()) {
- return false;
+ return NULL;
}
// The clip stack can come from an SkDraw where it is technically optional.
@@ -1119,44 +1174,32 @@ bool SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
if (xfermode == SkXfermode::kClear_Mode ||
xfermode == SkXfermode::kSrc_Mode) {
this->clearClipFromContent(clipStack, clipRegion);
- }
-
- // For the following modes, we use both source and destination, but
- // we use one as a smask for the other, so we have to make form xobjects
- // out of both of them: SrcIn, DstIn, SrcOut, DstOut.
- if (xfermode == SkXfermode::kSrcIn_Mode ||
- xfermode == SkXfermode::kDstIn_Mode ||
- xfermode == SkXfermode::kSrcOut_Mode ||
- xfermode == SkXfermode::kDstOut_Mode) {
+ } else if (xfermode == SkXfermode::kSrcIn_Mode ||
+ xfermode == SkXfermode::kDstIn_Mode ||
+ xfermode == SkXfermode::kSrcOut_Mode ||
+ xfermode == SkXfermode::kDstOut_Mode) {
+ // For the following modes, we use both source and destination, but
+ // we use one as a smask for the other, so we have to make form xobjects
+ // out of both of them: SrcIn, DstIn, SrcOut, DstOut.
if (isContentEmpty()) {
- return false;
+ return NULL;
} else {
- SkASSERT(fDstFormXObject.get() == NULL);
- createFormXObjectFromDevice(&fDstFormXObject);
+ createFormXObjectFromDevice(dst);
}
}
-
// TODO(vandebo) Figure out how/if we can handle the following modes:
// SrcAtop, DestAtop, Xor, Plus.
// These xfer modes don't draw source at all.
if (xfermode == SkXfermode::kClear_Mode ||
xfermode == SkXfermode::kDst_Mode) {
- return false;
- }
-
- // If the previous content entry was for DstOver reset fCurrentContentEntry.
- if (fCurrentContentEntry && xfermode != SkXfermode::kDstOver_Mode) {
- while (fCurrentContentEntry->fNext.get()) {
- fCurrentContentEntry = fCurrentContentEntry->fNext.get();
- }
+ return NULL;
}
ContentEntry* entry;
SkTScopedPtr<ContentEntry> newEntry;
- if (fCurrentContentEntry &&
- fCurrentContentEntry->fContent.getOffset() == 0) {
- entry = fCurrentContentEntry;
+ if (fLastContentEntry && fLastContentEntry->fContent.getOffset() == 0) {
+ entry = fLastContentEntry;
} else {
newEntry.reset(new ContentEntry);
entry = newEntry.get();
@@ -1164,95 +1207,87 @@ bool SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint,
hasText, &entry->fState);
- if (fCurrentContentEntry && xfermode != SkXfermode::kDstOver_Mode &&
- entry->fState.compareInitialState(fCurrentContentEntry->fState)) {
- return true;
+ if (fLastContentEntry && xfermode != SkXfermode::kDstOver_Mode &&
+ entry->fState.compareInitialState(fLastContentEntry->fState)) {
+ return fLastContentEntry;
}
- if (!fCurrentContentEntry) {
+ if (!fLastContentEntry) {
fContentEntries.reset(entry);
+ fLastContentEntry = entry;
} else if (xfermode == SkXfermode::kDstOver_Mode) {
entry->fNext.reset(fContentEntries.release());
fContentEntries.reset(entry);
} else {
- fCurrentContentEntry->fNext.reset(entry);
+ fLastContentEntry->fNext.reset(entry);
+ fLastContentEntry = entry;
}
newEntry.release();
- fCurrentContentEntry = entry;
- return true;
-}
-
-bool SkPDFDevice::setUpContentEntryForText(const SkClipStack* clipStack,
- const SkRegion& clipRegion,
- const SkMatrix& matrix,
- const SkPaint& paint) {
- return setUpContentEntry(clipStack, clipRegion, matrix, paint, true);
+ return entry;
}
-void SkPDFDevice::finishContentEntry(const SkPaint& paint) {
- SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode;
- if (paint.getXfermode()) {
- paint.getXfermode()->asMode(&xfermode);
- }
+void SkPDFDevice::finishContentEntry(const SkXfermode::Mode xfermode,
+ SkPDFFormXObject* dst) {
if (xfermode != SkXfermode::kSrcIn_Mode &&
xfermode != SkXfermode::kDstIn_Mode &&
xfermode != SkXfermode::kSrcOut_Mode &&
xfermode != SkXfermode::kDstOut_Mode) {
+ SkASSERT(!dst);
return;
}
+ SkASSERT(dst);
+ SkASSERT(!fContentEntries->fNext.get());
// We have to make a copy of these here because changing the current
// content into a form xobject will destroy them.
- SkClipStack clipStack = fCurrentContentEntry->fState.fClipStack;
- SkRegion clipRegion = fCurrentContentEntry->fState.fClipRegion;
+ SkClipStack clipStack = fContentEntries->fState.fClipStack;
+ SkRegion clipRegion = fContentEntries->fState.fClipRegion;
SkRefPtr<SkPDFFormXObject> srcFormXObject;
if (!isContentEmpty()) {
createFormXObjectFromDevice(&srcFormXObject);
}
- drawFormXObjectWithClip(fDstFormXObject.get(), &clipStack, clipRegion,
- true);
+ drawFormXObjectWithClip(dst, &clipStack, clipRegion, true);
// We've redrawn dst minus the clip area, if there's no src, we're done.
if (!srcFormXObject.get()) {
- fDstFormXObject = NULL;
return;
}
SkMatrix identity;
identity.reset();
SkPaint stockPaint;
- setUpContentEntry(&fExistingClipStack, fExistingClipRegion, identity,
- stockPaint);
+ ContentEntryAccessor inClipContentEntry(this, &fExistingClipStack,
+ fExistingClipRegion, identity,
+ stockPaint);
+ if (!inClipContentEntry.entry()) {
+ return;
+ }
SkRefPtr<SkPDFGraphicState> sMaskGS;
if (xfermode == SkXfermode::kSrcIn_Mode ||
xfermode == SkXfermode::kSrcOut_Mode) {
sMaskGS = SkPDFGraphicState::getSMaskGraphicState(
- fDstFormXObject.get(), xfermode == SkXfermode::kSrcOut_Mode);
+ dst, xfermode == SkXfermode::kSrcOut_Mode);
fXObjectResources.push(srcFormXObject.get());
srcFormXObject->ref();
} else {
sMaskGS = SkPDFGraphicState::getSMaskGraphicState(
srcFormXObject.get(), xfermode == SkXfermode::kDstOut_Mode);
- // fDstFormXObject already added to fXObjectResources in
- // drawFormXObjectWithClip.
+ // dst already added to fXObjectResources in drawFormXObjectWithClip.
}
sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref.
SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
- &fCurrentContentEntry->fContent);
+ &inClipContentEntry.entry()->fContent);
SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
- &fCurrentContentEntry->fContent);
+ &inClipContentEntry.entry()->fContent);
sMaskGS = SkPDFGraphicState::getNoSMaskGraphicState();
sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref.
SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
- &fCurrentContentEntry->fContent);
-
- fDstFormXObject = NULL;
- finishContentEntry(stockPaint);
+ &inClipContentEntry.entry()->fContent);
}
bool SkPDFDevice::isContentEmpty() {
@@ -1292,7 +1327,7 @@ void SkPDFDevice::populateGraphicStateEntryFromPaint(
// PDF doesn't support kClamp_TileMode, so we simulate it by making
// a pattern the size of the current clip.
- SkIRect bounds = fCurrentContentEntry->fState.fClipRegion.getBounds();
+ SkIRect bounds = clipRegion.getBounds();
pdfShader = SkPDFShader::getPDFShader(*shader, transform, bounds);
SkSafeUnref(pdfShader.get()); // getShader and SkRefPtr both took a ref
@@ -1364,19 +1399,19 @@ int SkPDFDevice::addGraphicStateResource(SkPDFGraphicState* gs) {
return result;
}
-void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID) {
+void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID,
+ ContentEntry* contentEntry) {
SkTypeface* typeface = paint.getTypeface();
- if (fCurrentContentEntry->fState.fFont == NULL ||
- fCurrentContentEntry->fState.fTextSize != paint.getTextSize() ||
- !fCurrentContentEntry->fState.fFont->hasGlyph(glyphID)) {
+ if (contentEntry->fState.fFont == NULL ||
+ contentEntry->fState.fTextSize != paint.getTextSize() ||
+ !contentEntry->fState.fFont->hasGlyph(glyphID)) {
int fontIndex = getFontResourceIndex(typeface, glyphID);
- fCurrentContentEntry->fContent.writeText("/F");
- fCurrentContentEntry->fContent.writeDecAsText(fontIndex);
- fCurrentContentEntry->fContent.writeText(" ");
- SkPDFScalar::Append(paint.getTextSize(),
- &fCurrentContentEntry->fContent);
- fCurrentContentEntry->fContent.writeText(" Tf\n");
- fCurrentContentEntry->fState.fFont = fFontResources[fontIndex];
+ contentEntry->fContent.writeText("/F");
+ contentEntry->fContent.writeDecAsText(fontIndex);
+ contentEntry->fContent.writeText(" ");
+ SkPDFScalar::Append(paint.getTextSize(), &contentEntry->fContent);
+ contentEntry->fContent.writeText(" Tf\n");
+ contentEntry->fState.fFont = fFontResources[fontIndex];
}
}
@@ -1392,18 +1427,6 @@ int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) {
return resourceIndex;
}
-void SkPDFDevice::setTextTransform(SkScalar x, SkScalar y, SkScalar textSkewX) {
- // Flip the text about the x-axis to account for origin swap and include
- // the passed parameters.
- fCurrentContentEntry->fContent.writeText("1 0 ");
- SkPDFScalar::Append(0 - textSkewX, &fCurrentContentEntry->fContent);
- fCurrentContentEntry->fContent.writeText(" -1 ");
- SkPDFScalar::Append(x, &fCurrentContentEntry->fContent);
- fCurrentContentEntry->fContent.writeText(" ");
- SkPDFScalar::Append(y, &fCurrentContentEntry->fContent);
- fCurrentContentEntry->fContent.writeText(" Tm\n");
-}
-
void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix,
const SkClipStack* clipStack,
const SkRegion& clipRegion,
@@ -1419,7 +1442,8 @@ void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix,
scaled.postScale(SkIntToScalar(subset.width()),
SkIntToScalar(subset.height()));
scaled.postConcat(matrix);
- if (!setUpContentEntry(clipStack, clipRegion, scaled, paint)) {
+ ContentEntryAccessor content(this, clipStack, clipRegion, scaled, paint);
+ if (!content.entry()) {
return;
}
@@ -1434,6 +1458,5 @@ void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix,
fXObjectResources.push(image); // Transfer reference.
SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
- &fCurrentContentEntry->fContent);
- finishContentEntry(paint);
+ &content.entry()->fContent);
}