aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/pdf
diff options
context:
space:
mode:
authorGravatar vandebo@chromium.org <vandebo@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-10-30 20:48:05 +0000
committerGravatar vandebo@chromium.org <vandebo@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-10-30 20:48:05 +0000
commit3b416216d1e90cb8b1bba41bb95806fe2d40da88 (patch)
tree6b976e9d875a4aebf64868d3fe09890db6c4866c /src/pdf
parentc1362424b864ee3ae7aa44971985e5481057363a (diff)
[PDF] Improve complex xfer mode support.
Xfer mode applies only to the shape of the source drawing, not everything in the clip as in currently implemented. It's just that the current gm examples draw a shape that fills the visible layer. R=edisonn@google.com, reed@google.com Review URL: https://codereview.appspot.com/4631078 git-svn-id: http://skia.googlecode.com/svn/trunk@12034 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/pdf')
-rw-r--r--src/pdf/SkPDFDevice.cpp357
-rw-r--r--src/pdf/SkPDFGraphicState.cpp7
2 files changed, 245 insertions, 119 deletions
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index a7d2bd459a..91f8e87487 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -480,7 +480,8 @@ void GraphicStackState::updateClip(const SkClipStack& clipStack,
bool needRegion = false;
const SkClipStack::Element* clipEntry;
for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) {
- if (clipEntry->getOp() != SkRegion::kIntersect_Op || clipEntry->isInverseFilled()) {
+ if (clipEntry->getOp() != SkRegion::kIntersect_Op ||
+ clipEntry->isInverseFilled()) {
needRegion = true;
break;
}
@@ -619,7 +620,8 @@ public:
const SkPaint& paint, bool hasText = false)
: fDevice(device),
fContentEntry(NULL),
- fXfermode(SkXfermode::kSrcOver_Mode) {
+ fXfermode(SkXfermode::kSrcOver_Mode),
+ fDstFormXObject(NULL) {
init(draw.fClipStack, *draw.fClip, *draw.fMatrix, paint, hasText);
}
ScopedContentEntry(SkPDFDevice* device, const SkClipStack* clipStack,
@@ -627,27 +629,67 @@ public:
const SkPaint& paint, bool hasText = false)
: fDevice(device),
fContentEntry(NULL),
- fXfermode(SkXfermode::kSrcOver_Mode) {
+ fXfermode(SkXfermode::kSrcOver_Mode),
+ fDstFormXObject(NULL) {
init(clipStack, clipRegion, matrix, paint, hasText);
}
~ScopedContentEntry() {
if (fContentEntry) {
- fDevice->finishContentEntry(fXfermode, fDstFormXObject);
+ SkPath* shape = &fShape;
+ if (shape->isEmpty()) {
+ shape = NULL;
+ }
+ fDevice->finishContentEntry(fXfermode, fDstFormXObject, shape);
}
SkSafeUnref(fDstFormXObject);
}
ContentEntry* entry() { return fContentEntry; }
+
+ /* Returns true when we explicitly need the shape of the drawing. */
+ bool needShape() {
+ switch (fXfermode) {
+ case SkXfermode::kClear_Mode:
+ case SkXfermode::kSrc_Mode:
+ case SkXfermode::kSrcIn_Mode:
+ case SkXfermode::kSrcOut_Mode:
+ case SkXfermode::kDstIn_Mode:
+ case SkXfermode::kDstOut_Mode:
+ case SkXfermode::kSrcATop_Mode:
+ case SkXfermode::kDstATop_Mode:
+ case SkXfermode::kModulate_Mode:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /* Returns true unless we only need the shape of the drawing. */
+ bool needSource() {
+ if (fXfermode == SkXfermode::kClear_Mode) {
+ return false;
+ }
+ return true;
+ }
+
+ /* If the shape is different than the alpha component of the content, then
+ * setShape should be called with the shape. In particular, images and
+ * devices have rectangular shape.
+ */
+ void setShape(const SkPath& shape) {
+ fShape = shape;
+ }
+
private:
SkPDFDevice* fDevice;
ContentEntry* fContentEntry;
SkXfermode::Mode fXfermode;
SkPDFFormXObject* fDstFormXObject;
+ SkPath fShape;
void init(const SkClipStack* clipStack, const SkRegion& clipRegion,
const SkMatrix& matrix, const SkPaint& paint, bool hasText) {
- fDstFormXObject = NULL;
// Shape has to be flatten before we get here.
if (matrix.hasPerspective()) {
NOT_IMPLEMENTED(!matrix.hasPerspective(), false);
@@ -1054,7 +1096,8 @@ void SkPDFDevice::drawBitmap(const SkDraw& d, const SkBitmap& bitmap,
SkMatrix transform = matrix;
transform.postConcat(*d.fMatrix);
- this->internalDrawBitmap(transform, d.fClipStack, *d.fClip, bitmap, NULL, paint);
+ this->internalDrawBitmap(transform, d.fClipStack, *d.fClip, bitmap, NULL,
+ paint);
}
void SkPDFDevice::drawSprite(const SkDraw& d, const SkBitmap& bitmap,
@@ -1065,7 +1108,8 @@ void SkPDFDevice::drawSprite(const SkDraw& d, const SkBitmap& bitmap,
SkMatrix matrix;
matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
- this->internalDrawBitmap(matrix, d.fClipStack, *d.fClip, bitmap, NULL, paint);
+ this->internalDrawBitmap(matrix, d.fClipStack, *d.fClip, bitmap, NULL,
+ paint);
}
void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
@@ -1170,7 +1214,8 @@ void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
// find all the typefaces needed to resolve this run of text
bool usesOriginalTypeface = false;
for (uint16_t x = 0; x < numGlyphs; ++x) {
- // optimization that checks to see if original typeface can resolve the glyph
+ // optimization that checks to see if original typeface can resolve
+ // the glyph
if (glyphIDs[x] < origGlyphCount) {
usesOriginalTypeface = true;
continue;
@@ -1178,9 +1223,11 @@ void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
// find the fallback typeface that supports this glyph
TypefaceFallbackData data;
- data.typeface = SkGetTypefaceForGlyphID(glyphIDs[x], origFace.get(),
- paint.getPaintOptionsAndroid(),
- &data.lowerBounds, &data.upperBounds);
+ data.typeface =
+ SkGetTypefaceForGlyphID(glyphIDs[x], origFace.get(),
+ paint.getPaintOptionsAndroid(),
+ &data.lowerBounds,
+ &data.upperBounds);
// add the typeface and its data if we don't have it
if (data.typeface && !visitedTypefaces.contains(data)) {
visitedTypefaces.push(data);
@@ -1208,7 +1255,8 @@ void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
int tmpGlyphCount = 0;
for (uint16_t y = 0; y < numGlyphs; ++y) {
- if (glyphIDs[y] >= data.lowerBounds && glyphIDs[y] < data.upperBounds) {
+ if (glyphIDs[y] >= data.lowerBounds &&
+ glyphIDs[y] < data.upperBounds) {
tmpGlyphIDs[tmpGlyphCount] = glyphIDs[y] - data.lowerBounds;
memcpy(&(tmpPos[tmpGlyphCount * scalarsPerPos]),
&(pos[y * scalarsPerPos]),
@@ -1286,8 +1334,8 @@ void SkPDFDevice::drawVertices(const SkDraw& d, SkCanvas::VertexMode,
NOT_IMPLEMENTED("drawVerticies", true);
}
-void SkPDFDevice::drawDevice(const SkDraw& d, SkBaseDevice* device, int x, int y,
- const SkPaint& paint) {
+void SkPDFDevice::drawDevice(const SkDraw& d, SkBaseDevice* device,
+ int x, int y, const SkPaint& paint) {
if ((device->getDeviceCapabilities() & kVector_Capability) == 0) {
// If we somehow get a raster device, do what our parent would do.
INHERITED::drawDevice(d, device, x, y, paint);
@@ -1306,10 +1354,18 @@ void SkPDFDevice::drawDevice(const SkDraw& d, SkBaseDevice* device, int x, int y
if (!content.entry()) {
return;
}
+ if (content.needShape()) {
+ SkPath shape;
+ shape.addRect(SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y),
+ device->width(), device->height()));
+ content.setShape(shape);
+ }
+ if (!content.needSource()) {
+ return;
+ }
- SkPDFFormXObject* xobject = new SkPDFFormXObject(pdfDevice);
- fXObjectResources.push(xobject); // Transfer reference.
- SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
+ SkAutoTUnref<SkPDFFormXObject> xObject(new SkPDFFormXObject(pdfDevice));
+ SkPDFUtils::DrawFormXObject(this->addXObjectResource(xObject.get()),
&content.entry()->fContent);
// Merge glyph sets from the drawn device.
@@ -1552,7 +1608,8 @@ bool SkPDFDevice::handleRectAnnotation(const SkRect& r, const SkMatrix& matrix,
handleLinkToURL(urlData, r, matrix);
return p.isNoDrawAnnotation();
}
- SkData* linkToName = annotationInfo->find(SkAnnotationKeys::Link_Named_Dest_Key());
+ SkData* linkToName = annotationInfo->find(
+ SkAnnotationKeys::Link_Named_Dest_Key());
if (linkToName) {
handleLinkToNamedDest(linkToName, r, matrix);
return p.isNoDrawAnnotation();
@@ -1567,7 +1624,8 @@ bool SkPDFDevice::handlePointAnnotation(const SkPoint* points, size_t count,
if (!annotationInfo) {
return false;
}
- SkData* nameData = annotationInfo->find(SkAnnotationKeys::Define_Named_Dest_Key());
+ SkData* nameData = annotationInfo->find(
+ SkAnnotationKeys::Define_Named_Dest_Key());
if (nameData) {
for (size_t i = 0; i < count; i++) {
defineNamedDestination(nameData, points[i], matrix);
@@ -1577,7 +1635,8 @@ bool SkPDFDevice::handlePointAnnotation(const SkPoint* points, size_t count,
return false;
}
-SkPDFDict* SkPDFDevice::createLinkAnnotation(const SkRect& r, const SkMatrix& matrix) {
+SkPDFDict* SkPDFDevice::createLinkAnnotation(const SkRect& r,
+ const SkMatrix& matrix) {
SkMatrix transform = matrix;
transform.postConcat(fInitialTransform);
SkRect translatedRect;
@@ -1663,7 +1722,8 @@ void SkPDFDevice::appendDestinations(SkPDFDict* dict, SkPDFObject* page) {
pdfDest->appendScalar(dest->point.x());
pdfDest->appendScalar(dest->point.y());
pdfDest->appendInt(0); // Leave zoom unchanged
- dict->insert(static_cast<const char *>(dest->nameData->data()), pdfDest);
+ dict->insert(static_cast<const char *>(dest->nameData->data()),
+ pdfDest);
}
}
@@ -1677,51 +1737,31 @@ SkPDFFormXObject* SkPDFDevice::createFormXObjectFromDevice() {
return xobject;
}
-void SkPDFDevice::clearClipFromContent(const SkClipStack* clipStack,
- const SkRegion& clipRegion) {
- if (clipRegion.isEmpty() || isContentEmpty()) {
- return;
- }
- SkAutoTUnref<SkPDFFormXObject> curContent(createFormXObjectFromDevice());
-
- // Redraw what we already had, but with the clip as a mask.
- drawFormXObjectWithClip(curContent, clipStack, clipRegion, true);
-}
-
-void SkPDFDevice::drawFormXObjectWithClip(SkPDFFormXObject* xobject,
+void SkPDFDevice::drawFormXObjectWithMask(int xObjectIndex,
+ SkPDFFormXObject* mask,
const SkClipStack* clipStack,
const SkRegion& clipRegion,
+ SkXfermode::Mode mode,
bool invertClip) {
if (clipRegion.isEmpty() && !invertClip) {
return;
}
- // Create the mask.
- SkMatrix identity;
- identity.reset();
- SkDraw draw;
- draw.fMatrix = &identity;
- draw.fClip = &clipRegion;
- draw.fClipStack = clipStack;
- SkPaint stockPaint;
- this->drawPaint(draw, stockPaint);
- SkAutoTUnref<SkPDFFormXObject> maskFormXObject(createFormXObjectFromDevice());
SkAutoTUnref<SkPDFGraphicState> sMaskGS(
- SkPDFGraphicState::GetSMaskGraphicState(maskFormXObject, invertClip,
- SkPDFGraphicState::kAlpha_SMaskMode));
+ SkPDFGraphicState::GetSMaskGraphicState(
+ mask, invertClip, SkPDFGraphicState::kAlpha_SMaskMode));
- // Draw the xobject with the clip as a mask.
- ScopedContentEntry content(this, &fExistingClipStack, fExistingClipRegion,
- identity, stockPaint);
+ SkMatrix identity;
+ identity.reset();
+ SkPaint paint;
+ paint.setXfermodeMode(mode);
+ ScopedContentEntry content(this, clipStack, clipRegion, identity, paint);
if (!content.entry()) {
return;
}
SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
&content.entry()->fContent);
- SkPDFUtils::DrawFormXObject(fXObjectResources.count(),
- &content.entry()->fContent);
- fXObjectResources.push(xobject);
- xobject->ref();
+ SkPDFUtils::DrawFormXObject(xObjectIndex, &content.entry()->fContent);
sMaskGS.reset(SkPDFGraphicState::GetNoSMaskGraphicState());
SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
@@ -1762,28 +1802,32 @@ ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
paint.getXfermode()->asMode(&xfermode);
}
- if (xfermode == SkXfermode::kClear_Mode ||
- xfermode == SkXfermode::kSrc_Mode) {
- this->clearClipFromContent(clipStack, clipRegion);
- } 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 NULL;
- } else {
+ // For the following modes, we want to handle source and destination
+ // separately, so make an object of what's already there.
+ if (xfermode == SkXfermode::kClear_Mode ||
+ xfermode == SkXfermode::kSrc_Mode ||
+ xfermode == SkXfermode::kSrcIn_Mode ||
+ xfermode == SkXfermode::kDstIn_Mode ||
+ xfermode == SkXfermode::kSrcOut_Mode ||
+ xfermode == SkXfermode::kDstOut_Mode ||
+ xfermode == SkXfermode::kSrcATop_Mode ||
+ xfermode == SkXfermode::kDstATop_Mode ||
+ xfermode == SkXfermode::kModulate_Mode) {
+ if (!isContentEmpty()) {
*dst = createFormXObjectFromDevice();
+ SkASSERT(isContentEmpty());
+ } else if (xfermode != SkXfermode::kSrc_Mode &&
+ xfermode != SkXfermode::kSrcOut_Mode) {
+ // Except for Src and SrcOut, if there isn't anything already there,
+ // then we're done.
+ return NULL;
}
}
// TODO(vandebo): Figure out how/if we can handle the following modes:
- // SrcAtop, DestAtop, Xor, Plus.
+ // Xor, Plus.
- // These xfer modes don't draw source at all.
- if (xfermode == SkXfermode::kClear_Mode ||
- xfermode == SkXfermode::kDst_Mode) {
+ // Dst xfer mode doesn't draw source at all.
+ if (xfermode == SkXfermode::kDst_Mode) {
return NULL;
}
@@ -1821,70 +1865,135 @@ ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
}
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) {
+ SkPDFFormXObject* dst,
+ SkPath* shape) {
+ if (xfermode != SkXfermode::kClear_Mode &&
+ xfermode != SkXfermode::kSrc_Mode &&
+ xfermode != SkXfermode::kSrcIn_Mode &&
+ xfermode != SkXfermode::kDstIn_Mode &&
+ xfermode != SkXfermode::kSrcOut_Mode &&
+ xfermode != SkXfermode::kDstOut_Mode &&
+ xfermode != SkXfermode::kSrcATop_Mode &&
+ xfermode != SkXfermode::kDstATop_Mode &&
+ xfermode != SkXfermode::kModulate_Mode) {
SkASSERT(!dst);
return;
}
+ if (!dst) {
+ SkASSERT(xfermode == SkXfermode::kSrc_Mode ||
+ xfermode == SkXfermode::kSrcOut_Mode);
+ return;
+ }
ContentEntry* contentEntries = getContentEntries()->get();
SkASSERT(dst);
SkASSERT(!contentEntries->fNext.get());
// We have to make a copy of these here because changing the current
- // content into a form xobject will destroy them.
+ // content into a form-xobject will destroy them.
SkClipStack clipStack = contentEntries->fState.fClipStack;
SkRegion clipRegion = contentEntries->fState.fClipRegion;
SkAutoTUnref<SkPDFFormXObject> srcFormXObject;
- if (!isContentEmpty()) {
+ if (isContentEmpty()) {
+ SkASSERT(xfermode == SkXfermode::kClear_Mode);
+ } else {
+ SkASSERT(!fContentEntries->fNext.get());
srcFormXObject.reset(createFormXObjectFromDevice());
}
- drawFormXObjectWithClip(dst, &clipStack, clipRegion, true);
+ SkMatrix identity;
+ identity.reset();
- // We've redrawn dst minus the clip area, if there's no src, we're done.
- if (!srcFormXObject.get()) {
- return;
+ // TODO(vandebo) srcFormXObject may contain alpha, but here we want it
+ // without alpha.
+ if (xfermode == SkXfermode::kSrcATop_Mode) {
+ // TODO(vandebo): In order to properly support SrcATop we have to track
+ // the shape of what's been drawn at all times. It's the intersection of
+ // the non-transparent parts of the device and the outlines (shape) of
+ // all images and devices drawn.
+ drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), dst,
+ &clipStack, clipRegion,
+ SkXfermode::kSrcOver_Mode, true);
+ } else {
+ SkAutoTUnref<SkPDFFormXObject> dstMaskStorage;
+ SkPDFFormXObject* dstMask = srcFormXObject.get();
+ if (shape != NULL) {
+ // Draw shape into a form-xobject.
+ SkDraw d;
+ d.fMatrix = &identity;
+ d.fClip = &clipRegion;
+ d.fClipStack = &clipStack;
+ SkPaint filledPaint;
+ filledPaint.setColor(SK_ColorBLACK);
+ filledPaint.setStyle(SkPaint::kFill_Style);
+ this->drawPath(d, *shape, filledPaint, NULL, true);
+
+ dstMaskStorage.reset(createFormXObjectFromDevice());
+ dstMask = dstMaskStorage.get();
+ }
+ drawFormXObjectWithMask(addXObjectResource(dst), dstMask, &clipStack,
+ clipRegion, SkXfermode::kSrcOver_Mode, true);
}
- SkMatrix identity;
- identity.reset();
SkPaint stockPaint;
- ScopedContentEntry inClipContentEntry(this, &fExistingClipStack,
- fExistingClipRegion, identity,
- stockPaint);
- if (!inClipContentEntry.entry()) {
+
+ if (xfermode == SkXfermode::kClear_Mode) {
+ return;
+ } else if (xfermode == SkXfermode::kSrc_Mode ||
+ xfermode == SkXfermode::kDstATop_Mode) {
+ ScopedContentEntry content(this, &clipStack, clipRegion, identity,
+ stockPaint);
+ if (content.entry()) {
+ SkPDFUtils::DrawFormXObject(
+ this->addXObjectResource(srcFormXObject.get()),
+ &content.entry()->fContent);
+ }
+ if (xfermode == SkXfermode::kSrc_Mode) {
+ return;
+ }
+ } else if (xfermode == SkXfermode::kSrcATop_Mode) {
+ ScopedContentEntry content(this, &clipStack, clipRegion, identity,
+ stockPaint);
+ if (content.entry()) {
+ SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst),
+ &content.entry()->fContent);
+ }
+ }
+
+ SkASSERT(xfermode == SkXfermode::kSrcIn_Mode ||
+ xfermode == SkXfermode::kDstIn_Mode ||
+ xfermode == SkXfermode::kSrcOut_Mode ||
+ xfermode == SkXfermode::kDstOut_Mode ||
+ xfermode == SkXfermode::kSrcATop_Mode ||
+ xfermode == SkXfermode::kDstATop_Mode ||
+ xfermode == SkXfermode::kModulate_Mode);
+
+ ScopedContentEntry inShapeContentEntry(this, &fExistingClipStack,
+ fExistingClipRegion, identity,
+ stockPaint);
+ if (!inShapeContentEntry.entry()) {
return;
}
- SkAutoTUnref<SkPDFGraphicState> sMaskGS;
if (xfermode == SkXfermode::kSrcIn_Mode ||
- xfermode == SkXfermode::kSrcOut_Mode) {
- sMaskGS.reset(SkPDFGraphicState::GetSMaskGraphicState(
- dst,
- xfermode == SkXfermode::kSrcOut_Mode,
- SkPDFGraphicState::kAlpha_SMaskMode));
- fXObjectResources.push(srcFormXObject.get());
- srcFormXObject.get()->ref();
+ xfermode == SkXfermode::kSrcOut_Mode ||
+ xfermode == SkXfermode::kSrcATop_Mode) {
+ drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), dst,
+ &clipStack, clipRegion,
+ SkXfermode::kSrcOver_Mode,
+ xfermode == SkXfermode::kSrcOut_Mode);
} else {
- sMaskGS.reset(SkPDFGraphicState::GetSMaskGraphicState(
- srcFormXObject.get(),
- xfermode == SkXfermode::kDstOut_Mode,
- SkPDFGraphicState::kAlpha_SMaskMode));
- // dst already added to fXObjectResources in drawFormXObjectWithClip.
+ SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode;
+ if (xfermode == SkXfermode::kModulate_Mode) {
+ drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()),
+ dst, &clipStack, clipRegion,
+ SkXfermode::kSrcOver_Mode, false);
+ mode = SkXfermode::kMultiply_Mode;
+ }
+ drawFormXObjectWithMask(addXObjectResource(dst), srcFormXObject.get(),
+ &clipStack, clipRegion, mode,
+ xfermode == SkXfermode::kDstOut_Mode);
}
- SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
- &inClipContentEntry.entry()->fContent);
-
- SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
- &inClipContentEntry.entry()->fContent);
-
- sMaskGS.reset(SkPDFGraphicState::GetNoSMaskGraphicState());
- SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
- &inClipContentEntry.entry()->fContent);
}
bool SkPDFDevice::isContentEmpty() {
@@ -1996,6 +2105,18 @@ int SkPDFDevice::addGraphicStateResource(SkPDFGraphicState* gs) {
return result;
}
+int SkPDFDevice::addXObjectResource(SkPDFObject* xObject) {
+ // Assumes that xobject has been canonicalized (so we can directly compare
+ // pointers).
+ int result = fXObjectResources.find(xObject);
+ if (result < 0) {
+ result = fXObjectResources.count();
+ fXObjectResources.push(xObject);
+ xObject->ref();
+ }
+ return result;
+}
+
void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID,
ContentEntry* contentEntry) {
SkTypeface* typeface = paint.getTypeface();
@@ -2015,7 +2136,8 @@ void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID,
}
int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) {
- SkAutoTUnref<SkPDFFont> newFont(SkPDFFont::GetFontResource(typeface, glyphID));
+ SkAutoTUnref<SkPDFFont> newFont(SkPDFFont::GetFontResource(typeface,
+ glyphID));
int resourceIndex = fFontResources.find(newFont.get());
if (resourceIndex < 0) {
resourceIndex = fFontResources.count();
@@ -2119,21 +2241,26 @@ void SkPDFDevice::internalDrawBitmap(const SkMatrix& origMatrix,
SkIntToScalar(subset.height()));
scaled.postConcat(matrix);
ScopedContentEntry content(this, clipStack, *clipRegion, scaled, paint);
- if (!content.entry()) {
+ if (!content.entry() || (srcRect && !subset.intersect(*srcRect))) {
return;
}
-
- if (srcRect && !subset.intersect(*srcRect)) {
+ if (content.needShape()) {
+ SkPath shape;
+ shape.addRect(SkRect::MakeWH(subset.width(), subset.height()));
+ shape.transform(matrix);
+ content.setShape(shape);
+ }
+ if (!content.needSource()) {
return;
}
- SkPDFImage* image = SkPDFImage::CreateImage(*bitmap, subset, fEncoder);
+ SkAutoTUnref<SkPDFImage> image(
+ SkPDFImage::CreateImage(*bitmap, subset, fEncoder));
if (!image) {
return;
}
- fXObjectResources.push(image); // Transfer reference.
- SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
+ SkPDFUtils::DrawFormXObject(this->addXObjectResource(image.get()),
&content.entry()->fContent);
}
diff --git a/src/pdf/SkPDFGraphicState.cpp b/src/pdf/SkPDFGraphicState.cpp
index 43d22f308e..9f8edfd206 100644
--- a/src/pdf/SkPDFGraphicState.cpp
+++ b/src/pdf/SkPDFGraphicState.cpp
@@ -14,8 +14,6 @@
static const char* blend_mode_from_xfermode(SkXfermode::Mode mode) {
switch (mode) {
case SkXfermode::kSrcOver_Mode: return "Normal";
- // kModulate is not really like multipy but similar most of the time.
- case SkXfermode::kModulate_Mode:
case SkXfermode::kMultiply_Mode: return "Multiply";
case SkXfermode::kScreen_Mode: return "Screen";
case SkXfermode::kOverlay_Mode: return "Overlay";
@@ -41,11 +39,12 @@ static const char* blend_mode_from_xfermode(SkXfermode::Mode mode) {
case SkXfermode::kDstIn_Mode:
case SkXfermode::kSrcOut_Mode:
case SkXfermode::kDstOut_Mode:
+ case SkXfermode::kSrcATop_Mode:
+ case SkXfermode::kDstATop_Mode:
+ case SkXfermode::kModulate_Mode:
return "Normal";
// TODO(vandebo): Figure out if we can support more of these modes.
- case SkXfermode::kSrcATop_Mode:
- case SkXfermode::kDstATop_Mode:
case SkXfermode::kXor_Mode:
case SkXfermode::kPlus_Mode:
return NULL;