aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar vandebo@chromium.org <vandebo@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-05-24 16:39:05 +0000
committerGravatar vandebo@chromium.org <vandebo@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-05-24 16:39:05 +0000
commit481aef68333e01c19badda456d8e60bd1f1bee2a (patch)
treee2f472800cff801a1ddf334f64b9d79f3216a8b3
parent2f83940c4db5d17dcb4fd7df24d8002022730a85 (diff)
[PDF] Add clip support and some optimizations for "complex" xfer modes.
For Clear, Src, Dst/Src-In/Out, we have to consider the current clip, and potentially draw Dst, clipped to the inverse of the current clip before doing the operation of interest. For clear or src, if we haven't drawn anything, or the clip is empty, there's nothing to be done. For Src/Dst-In/Out, if either is empty, the result is empty. Review URL: http://codereview.appspot.com/4538082 git-svn-id: http://skia.googlecode.com/svn/trunk@1407 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--include/pdf/SkPDFDevice.h6
-rw-r--r--src/pdf/SkPDFDevice.cpp68
2 files changed, 61 insertions, 13 deletions
diff --git a/include/pdf/SkPDFDevice.h b/include/pdf/SkPDFDevice.h
index 0f634aac44..b6c1389100 100644
--- a/include/pdf/SkPDFDevice.h
+++ b/include/pdf/SkPDFDevice.h
@@ -169,6 +169,10 @@ private:
// Clear the passed clip from all existing content entries.
void clearClipFromContent(const SkClipStack* clipStack,
const SkRegion& clipRegion);
+ void drawFormXObjectWithClip(SkPDFFormXObject* form,
+ const SkClipStack* clipStack,
+ 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.
@@ -182,6 +186,8 @@ private:
const SkMatrix& matrix,
const SkPaint& paint);
void finishContentEntry(const SkPaint& paint);
+ bool isContentEmpty();
+
void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
const SkClipStack& clipStack,
const SkRegion& clipRegion,
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 63cf70288c..69cf804ca3 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -1034,9 +1034,24 @@ void SkPDFDevice::createFormXObjectFromDevice(
void SkPDFDevice::clearClipFromContent(const SkClipStack* clipStack,
const SkRegion& clipRegion) {
+ if (clipRegion.isEmpty() || isContentEmpty()) {
+ return;
+ }
SkRefPtr<SkPDFFormXObject> curContent;
createFormXObjectFromDevice(&curContent);
+ // Redraw what we already had, but with the clip as a mask.
+ drawFormXObjectWithClip(curContent.get(), clipStack, clipRegion, true);
+}
+
+void SkPDFDevice::drawFormXObjectWithClip(SkPDFFormXObject* xobject,
+ const SkClipStack* clipStack,
+ const SkRegion& clipRegion,
+ bool invertClip) {
+ if (clipRegion.isEmpty() && !invertClip) {
+ return;
+ }
+
// Create the mask.
SkMatrix identity;
identity.reset();
@@ -1049,18 +1064,19 @@ void SkPDFDevice::clearClipFromContent(const SkClipStack* clipStack,
SkRefPtr<SkPDFFormXObject> maskFormXObject;
createFormXObjectFromDevice(&maskFormXObject);
SkRefPtr<SkPDFGraphicState> sMaskGS =
- SkPDFGraphicState::getSMaskGraphicState(maskFormXObject.get(), false);
+ SkPDFGraphicState::getSMaskGraphicState(maskFormXObject.get(),
+ invertClip);
sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref.
- // Redraw what we already had, but with the clip as a mask.
+ // Draw the xobject with the clip as a mask.
setUpContentEntry(&fExistingClipStack, fExistingClipRegion, identity,
stockPaint);
SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
&fCurrentContentEntry->fContent);
SkPDFUtils::DrawFormXObject(fXObjectResources.count(),
&fCurrentContentEntry->fContent);
- fXObjectResources.push(curContent.get());
- curContent->ref();
+ fXObjectResources.push(xobject);
+ xobject->ref();
sMaskGS = SkPDFGraphicState::getNoSMaskGraphicState();
sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref.
@@ -1100,8 +1116,6 @@ bool SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
paint.getXfermode()->asMode(&xfermode);
}
- // For Clear and Src modes, we need to push down the inverse of the
- // current clip.
if (xfermode == SkXfermode::kClear_Mode ||
xfermode == SkXfermode::kSrc_Mode) {
this->clearClipFromContent(clipStack, clipRegion);
@@ -1114,12 +1128,16 @@ bool SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
xfermode == SkXfermode::kDstIn_Mode ||
xfermode == SkXfermode::kSrcOut_Mode ||
xfermode == SkXfermode::kDstOut_Mode) {
- SkASSERT(fDstFormXObject.get() == NULL);
- createFormXObjectFromDevice(&fDstFormXObject);
+ if (isContentEmpty()) {
+ return false;
+ } else {
+ SkASSERT(fDstFormXObject.get() == NULL);
+ createFormXObjectFromDevice(&fDstFormXObject);
+ }
}
// TODO(vandebo) Figure out how/if we can handle the following modes:
- // SrcAtop, DestAtop, Xor.
+ // SrcAtop, DestAtop, Xor, Plus.
// These xfer modes don't draw source at all.
if (xfermode == SkXfermode::kClear_Mode ||
@@ -1180,12 +1198,27 @@ void SkPDFDevice::finishContentEntry(const SkPaint& paint) {
xfermode != SkXfermode::kDstIn_Mode &&
xfermode != SkXfermode::kSrcOut_Mode &&
xfermode != SkXfermode::kDstOut_Mode) {
- SkASSERT(fDstFormXObject.get() == NULL);
return;
}
+ // 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;
+
SkRefPtr<SkPDFFormXObject> srcFormXObject;
- createFormXObjectFromDevice(&srcFormXObject);
+ if (!isContentEmpty()) {
+ createFormXObjectFromDevice(&srcFormXObject);
+ }
+
+ drawFormXObjectWithClip(fDstFormXObject.get(), &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();
@@ -1203,8 +1236,8 @@ void SkPDFDevice::finishContentEntry(const SkPaint& paint) {
} else {
sMaskGS = SkPDFGraphicState::getSMaskGraphicState(
srcFormXObject.get(), xfermode == SkXfermode::kDstOut_Mode);
- fXObjectResources.push(fDstFormXObject.get());
- fDstFormXObject->ref();
+ // fDstFormXObject already added to fXObjectResources in
+ // drawFormXObjectWithClip.
}
sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref.
SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
@@ -1222,6 +1255,15 @@ void SkPDFDevice::finishContentEntry(const SkPaint& paint) {
finishContentEntry(stockPaint);
}
+bool SkPDFDevice::isContentEmpty() {
+ if (!fContentEntries.get() || fContentEntries->fContent.getOffset() == 0) {
+ SkASSERT(!fContentEntries.get() || !fContentEntries->fNext.get());
+ return true;
+ }
+ return false;
+}
+
+
void SkPDFDevice::populateGraphicStateEntryFromPaint(
const SkMatrix& matrix,
const SkClipStack& clipStack,