virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
const SkPaint&);
+ enum DrawingArea {
+ kContent_DrawingArea, // Drawing area for the page content.
+ kMargin_DrawingArea, // Drawing area for the margin content.
+ };
+
+ /** Sets the drawing area for the device. Subsequent draw calls are directed
+ * to the specific drawing area (margin or content). The default drawing
+ * area is the content drawing area.
+ */
+ void setDrawingArea(DrawingArea drawingArea);
+
// PDF specific methods.
/** Returns a reference to the resource dictionary for this device.
SkTScopedPtr<ContentEntry> fContentEntries;
ContentEntry* fLastContentEntry;
+ SkTScopedPtr<ContentEntry> fMarginContentEntries;
+ ContentEntry* fLastMarginContentEntry;
+ DrawingArea fDrawingArea;
+
+ // Accessor and setter functions based on the current DrawingArea.
+ SkTScopedPtr<ContentEntry>& getContentEntries();
+ ContentEntry* getLastContentEntry();
+ void setLastContentEntry(ContentEntry* contentEntry);
SkPDFDevice(const SkISize& layerSize, const SkClipStack& existingClipStack,
const SkRegion& existingClipRegion);
const SkIRect* srcRect,
const SkPaint& paint);
+ /** Helper method for copyContentToData. It is responsible for copying the
+ * list of content entries |entry| to |data|.
+ */
+ void copyContentEntriesToData(ContentEntry* entry, SkWStream* data) const;
+
// Disable the default copy and assign implementation.
SkPDFDevice(const SkPDFDevice&);
void operator=(const SkPDFDevice&);
: SkDevice(makeContentBitmap(contentSize, &initialTransform)),
fPageSize(pageSize),
fContentSize(contentSize),
- fLastContentEntry(NULL) {
+ fLastContentEntry(NULL),
+ fLastMarginContentEntry(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.
fContentSize(layerSize),
fExistingClipStack(existingClipStack),
fExistingClipRegion(existingClipRegion),
- fLastContentEntry(NULL) {
+ fLastContentEntry(NULL),
+ fLastMarginContentEntry(NULL) {
fInitialTransform.reset();
this->init();
}
fResourceDict = NULL;
fContentEntries.reset();
fLastContentEntry = NULL;
+ fMarginContentEntries.reset();
+ fLastMarginContentEntry = NULL;
+ fDrawingArea = kContent_DrawingArea;
}
void SkPDFDevice::cleanUp() {
&content.entry()->fContent);
}
+ContentEntry* SkPDFDevice::getLastContentEntry() {
+ if (fDrawingArea == kContent_DrawingArea) {
+ return fLastContentEntry;
+ } else {
+ return fLastMarginContentEntry;
+ }
+}
+
+SkTScopedPtr<ContentEntry>& SkPDFDevice::getContentEntries() {
+ if (fDrawingArea == kContent_DrawingArea) {
+ return fContentEntries;
+ } else {
+ return fMarginContentEntries;
+ }
+}
+
+void SkPDFDevice::setLastContentEntry(ContentEntry* contentEntry) {
+ if (fDrawingArea == kContent_DrawingArea) {
+ fLastContentEntry = contentEntry;
+ } else {
+ fLastMarginContentEntry = contentEntry;
+ }
+}
+
+void SkPDFDevice::setDrawingArea(DrawingArea drawingArea) {
+ // TODO(ctguil): Verify this isn't called when a ScopedContentEntry exists.
+ fDrawingArea = drawingArea;
+}
+
const SkRefPtr<SkPDFDict>& SkPDFDevice::getResourceDict() {
if (fResourceDict.get() == NULL) {
fResourceDict = new SkPDFDict;
return result;
}
+void SkPDFDevice::copyContentEntriesToData(ContentEntry* entry,
+ SkWStream* data) const {
+ GraphicStackState gsState(fExistingClipStack, fExistingClipRegion, data);
+ while(entry != NULL) {
+ SkIPoint translation = this->getOrigin();
+ translation.negate();
+ gsState.updateClip(entry->fState.fClipStack, entry->fState.fClipRegion,
+ translation);
+ gsState.updateMatrix(entry->fState.fMatrix);
+ gsState.updateDrawingState(entry->fState);
+
+ SkAutoDataUnref copy(entry->fContent.copyToData());
+ data->write(copy.data(), copy.size());
+ entry = entry->fNext.get();
+ }
+ gsState.drainStack();
+}
+
SkData* SkPDFDevice::copyContentToData() const {
SkDynamicMemoryWStream data;
if (fInitialTransform.getType() != SkMatrix::kIdentity_Mask) {
SkPDFUtils::AppendTransform(fInitialTransform, &data);
}
+
+ // TODO(aayushkumar): Apply clip along the margins. Currently, webkit
+ // colors the contentArea white before it starts drawing into it and
+ // that currently acts as our clip.
+ // Also, think about adding a transform here (or assume that the values
+ // sent across account for that)
+ SkPDFDevice::copyContentEntriesToData(fMarginContentEntries.get(), &data);
+
// If the content area is the entire page, then we don't need to clip
// the content area (PDF area clips to the page size). Otherwise,
// we have to clip to the content area; we've already applied the
emit_clip(NULL, &r, &data);
}
- GraphicStackState gsState(fExistingClipStack, fExistingClipRegion, &data);
- for (ContentEntry* entry = fContentEntries.get();
- entry != NULL;
- entry = entry->fNext.get()) {
- SkIPoint translation = this->getOrigin();
- translation.negate();
- gsState.updateClip(entry->fState.fClipStack, entry->fState.fClipRegion,
- translation);
- gsState.updateMatrix(entry->fState.fMatrix);
- gsState.updateDrawingState(entry->fState);
-
- SkAutoDataUnref copy(entry->fContent.copyToData());
- data.write(copy.data(), copy.size());
- }
- gsState.drainStack();
+ SkPDFDevice::copyContentEntriesToData(fContentEntries.get(), &data);
// potentially we could cache this SkData, and only rebuild it if we
// see that our state has changed.
ContentEntry* entry;
SkTScopedPtr<ContentEntry> newEntry;
- if (fLastContentEntry && fLastContentEntry->fContent.getOffset() == 0) {
- entry = fLastContentEntry;
+
+ ContentEntry* lastContentEntry = getLastContentEntry();
+ if (lastContentEntry && lastContentEntry->fContent.getOffset() == 0) {
+ entry = lastContentEntry;
} else {
newEntry.reset(new ContentEntry);
entry = newEntry.get();
populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint,
hasText, &entry->fState);
- if (fLastContentEntry && xfermode != SkXfermode::kDstOver_Mode &&
- entry->fState.compareInitialState(fLastContentEntry->fState)) {
- return fLastContentEntry;
+ if (lastContentEntry && xfermode != SkXfermode::kDstOver_Mode &&
+ entry->fState.compareInitialState(lastContentEntry->fState)) {
+ return lastContentEntry;
}
- if (!fLastContentEntry) {
- fContentEntries.reset(entry);
- fLastContentEntry = entry;
+ SkTScopedPtr<ContentEntry>& contentEntries = getContentEntries();
+ if (!lastContentEntry) {
+ contentEntries.reset(entry);
+ setLastContentEntry(entry);
} else if (xfermode == SkXfermode::kDstOver_Mode) {
- entry->fNext.reset(fContentEntries.release());
- fContentEntries.reset(entry);
+ entry->fNext.reset(contentEntries.release());
+ contentEntries.reset(entry);
} else {
- fLastContentEntry->fNext.reset(entry);
- fLastContentEntry = entry;
+ lastContentEntry->fNext.reset(entry);
+ setLastContentEntry(entry);
}
newEntry.release();
return entry;
SkASSERT(!dst);
return;
}
+
+ SkTScopedPtr<ContentEntry>& contentEntries = getContentEntries();
SkASSERT(dst);
- SkASSERT(!fContentEntries->fNext.get());
-
+ 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.
- SkClipStack clipStack = fContentEntries->fState.fClipStack;
- SkRegion clipRegion = fContentEntries->fState.fClipRegion;
+ SkClipStack clipStack = contentEntries->fState.fClipStack;
+ SkRegion clipRegion = contentEntries->fState.fClipRegion;
SkRefPtr<SkPDFFormXObject> srcFormXObject;
if (!isContentEmpty()) {
}
bool SkPDFDevice::isContentEmpty() {
- if (!fContentEntries.get() || fContentEntries->fContent.getOffset() == 0) {
- SkASSERT(!fContentEntries.get() || !fContentEntries->fNext.get());
+ SkTScopedPtr<ContentEntry>& contentEntries = getContentEntries();
+ if (!contentEntries.get() || contentEntries->fContent.getOffset() == 0) {
+ SkASSERT(!contentEntries.get() || !contentEntries->fNext.get());
return true;
}
return false;
}
-
void SkPDFDevice::populateGraphicStateEntryFromPaint(
const SkMatrix& matrix,
const SkClipStack& clipStack,