[PDF] Add helper class to manage ContentEntry set up and completion.
This stack object helper class calls finishContentEntry when it goes out of scope, maintains the current content entry, and manages the dst form xobject when it is needed. This can be made cleaner by moving the guts of SkPDFDevice into a core object, which can expose setUp/finishContentEntry as public, but that is left as a todo. Review URL: http://codereview.appspot.com/4515126 git-svn-id: http://skia.googlecode.com/svn/trunk@1409 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
8f096724a2
commit
b069c8cfcd
@ -17,6 +17,7 @@
|
|||||||
#ifndef SkPDFDevice_DEFINED
|
#ifndef SkPDFDevice_DEFINED
|
||||||
#define SkPDFDevice_DEFINED
|
#define SkPDFDevice_DEFINED
|
||||||
|
|
||||||
|
#include "SkCanvas.h"
|
||||||
#include "SkDevice.h"
|
#include "SkDevice.h"
|
||||||
#include "SkPaint.h"
|
#include "SkPaint.h"
|
||||||
#include "SkPath.h"
|
#include "SkPath.h"
|
||||||
@ -35,6 +36,7 @@ class SkPDFShader;
|
|||||||
class SkPDFStream;
|
class SkPDFStream;
|
||||||
|
|
||||||
// Private classes.
|
// Private classes.
|
||||||
|
class ContentEntryAccessor;
|
||||||
struct ContentEntry;
|
struct ContentEntry;
|
||||||
struct GraphicStateEntry;
|
struct GraphicStateEntry;
|
||||||
|
|
||||||
@ -141,6 +143,9 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
friend class SkPDFDeviceFactory;
|
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 fPageSize;
|
||||||
SkISize fContentSize;
|
SkISize fContentSize;
|
||||||
@ -155,8 +160,7 @@ private:
|
|||||||
SkTDArray<SkPDFShader*> fShaderResources;
|
SkTDArray<SkPDFShader*> fShaderResources;
|
||||||
|
|
||||||
SkTScopedPtr<ContentEntry> fContentEntries;
|
SkTScopedPtr<ContentEntry> fContentEntries;
|
||||||
ContentEntry* fCurrentContentEntry;
|
ContentEntry* fLastContentEntry;
|
||||||
SkRefPtr<SkPDFFormXObject> fDstFormXObject;
|
|
||||||
|
|
||||||
// For use by the DeviceFactory.
|
// For use by the DeviceFactory.
|
||||||
SkPDFDevice(const SkISize& layerSize, const SkClipStack& existingClipStack,
|
SkPDFDevice(const SkISize& layerSize, const SkClipStack& existingClipStack,
|
||||||
@ -174,18 +178,18 @@ private:
|
|||||||
const SkRegion& clipRegion,
|
const SkRegion& clipRegion,
|
||||||
bool invertClip);
|
bool invertClip);
|
||||||
|
|
||||||
// If the paint or clip is such that we shouldn't draw anything, these
|
// If the paint or clip is such that we shouldn't draw anything, this
|
||||||
// return false and do not create a content entry.
|
// returns NULL and does not create a content entry.
|
||||||
bool setUpContentEntry(const SkClipStack* clipStack,
|
// setUpContentEntry and finishContentEntry can be used directly, but
|
||||||
const SkRegion& clipRegion,
|
// the preferred method is to use the ContentEntryAccessor helper class.
|
||||||
const SkMatrix& matrix,
|
ContentEntry* setUpContentEntry(const SkClipStack* clipStack,
|
||||||
const SkPaint& paint,
|
const SkRegion& clipRegion,
|
||||||
bool hasText = false);
|
const SkMatrix& matrix,
|
||||||
bool setUpContentEntryForText(const SkClipStack* clipStack,
|
const SkPaint& paint,
|
||||||
const SkRegion& clipRegion,
|
bool hasText,
|
||||||
const SkMatrix& matrix,
|
SkRefPtr<SkPDFFormXObject>* dst);
|
||||||
const SkPaint& paint);
|
void finishContentEntry(SkXfermode::Mode xfermode,
|
||||||
void finishContentEntry(const SkPaint& paint);
|
SkPDFFormXObject* dst);
|
||||||
bool isContentEmpty();
|
bool isContentEmpty();
|
||||||
|
|
||||||
void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
|
void populateGraphicStateEntryFromPaint(const SkMatrix& matrix,
|
||||||
@ -196,11 +200,11 @@ private:
|
|||||||
GraphicStateEntry* entry);
|
GraphicStateEntry* entry);
|
||||||
int addGraphicStateResource(SkPDFGraphicState* gs);
|
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);
|
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,
|
void internalDrawBitmap(const SkMatrix& matrix,
|
||||||
const SkClipStack* clipStack,
|
const SkClipStack* clipStack,
|
||||||
const SkRegion& clipRegion,
|
const SkRegion& clipRegion,
|
||||||
|
@ -106,6 +106,19 @@ static void align_text(SkDrawCacheProc glyphCacheProc, const SkPaint& paint,
|
|||||||
*y = *y - yAdj;
|
*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
|
// It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the
|
||||||
// later being our representation of an object in the PDF file.
|
// later being our representation of an object in the PDF file.
|
||||||
struct GraphicStateEntry {
|
struct GraphicStateEntry {
|
||||||
@ -159,12 +172,6 @@ bool GraphicStateEntry::compareInitialState(const GraphicStateEntry& b) {
|
|||||||
(fTextScaleX == b.fTextScaleX && fTextFill == b.fTextFill));
|
(fTextScaleX == b.fTextScaleX && fTextFill == b.fTextFill));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ContentEntry {
|
|
||||||
GraphicStateEntry fState;
|
|
||||||
SkDynamicMemoryWStream fContent;
|
|
||||||
SkTScopedPtr<ContentEntry> fNext;
|
|
||||||
};
|
|
||||||
|
|
||||||
class GraphicStackState {
|
class GraphicStackState {
|
||||||
public:
|
public:
|
||||||
GraphicStackState(const SkClipStack& existingClipStack,
|
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,
|
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),
|
: SkDevice(NULL, makeContentBitmap(contentSize, &initialTransform), false),
|
||||||
fPageSize(pageSize),
|
fPageSize(pageSize),
|
||||||
fContentSize(contentSize),
|
fContentSize(contentSize),
|
||||||
fCurrentContentEntry(NULL) {
|
fLastContentEntry(NULL) {
|
||||||
// Skia generally uses the top left as the origin but PDF natively has the
|
// 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
|
// 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.
|
// needs to be done once, we don't do it when layering.
|
||||||
@ -463,7 +520,7 @@ SkPDFDevice::SkPDFDevice(const SkISize& layerSize,
|
|||||||
fContentSize(layerSize),
|
fContentSize(layerSize),
|
||||||
fExistingClipStack(existingClipStack),
|
fExistingClipStack(existingClipStack),
|
||||||
fExistingClipRegion(existingClipRegion),
|
fExistingClipRegion(existingClipRegion),
|
||||||
fCurrentContentEntry(NULL) {
|
fLastContentEntry(NULL) {
|
||||||
fInitialTransform.reset();
|
fInitialTransform.reset();
|
||||||
this->init();
|
this->init();
|
||||||
}
|
}
|
||||||
@ -475,7 +532,7 @@ SkPDFDevice::~SkPDFDevice() {
|
|||||||
void SkPDFDevice::init() {
|
void SkPDFDevice::init() {
|
||||||
fResourceDict = NULL;
|
fResourceDict = NULL;
|
||||||
fContentEntries.reset();
|
fContentEntries.reset();
|
||||||
fCurrentContentEntry = NULL;
|
fLastContentEntry = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkDeviceFactory* SkPDFDevice::onNewDeviceFactory() {
|
SkDeviceFactory* SkPDFDevice::onNewDeviceFactory() {
|
||||||
@ -498,39 +555,35 @@ void SkPDFDevice::clear(SkColor color) {
|
|||||||
paint.setStyle(SkPaint::kFill_Style);
|
paint.setStyle(SkPaint::kFill_Style);
|
||||||
SkMatrix identity;
|
SkMatrix identity;
|
||||||
identity.reset();
|
identity.reset();
|
||||||
if (!setUpContentEntry(&fExistingClipStack, fExistingClipRegion, identity,
|
ContentEntryAccessor content(this, &fExistingClipStack, fExistingClipRegion,
|
||||||
paint)) {
|
identity, paint);
|
||||||
return;
|
internalDrawPaint(paint, content.entry());
|
||||||
}
|
|
||||||
|
|
||||||
internalDrawPaint(paint);
|
|
||||||
finishContentEntry(paint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPDFDevice::drawPaint(const SkDraw& d, const SkPaint& paint) {
|
void SkPDFDevice::drawPaint(const SkDraw& d, const SkPaint& paint) {
|
||||||
SkPaint newPaint = paint;
|
SkPaint newPaint = paint;
|
||||||
newPaint.setStyle(SkPaint::kFill_Style);
|
newPaint.setStyle(SkPaint::kFill_Style);
|
||||||
if (!setUpContentEntry(d.fClipStack, *d.fClip, *d.fMatrix, newPaint)) {
|
ContentEntryAccessor content(this, d, newPaint);
|
||||||
return;
|
internalDrawPaint(newPaint, content.entry());
|
||||||
}
|
|
||||||
|
|
||||||
internalDrawPaint(newPaint);
|
|
||||||
finishContentEntry(newPaint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPDFDevice::internalDrawPaint(const SkPaint& paint) {
|
void SkPDFDevice::internalDrawPaint(const SkPaint& paint,
|
||||||
|
ContentEntry* contentEntry) {
|
||||||
|
if (!contentEntry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
SkRect bbox = SkRect::MakeWH(SkIntToScalar(this->width()),
|
SkRect bbox = SkRect::MakeWH(SkIntToScalar(this->width()),
|
||||||
SkIntToScalar(this->height()));
|
SkIntToScalar(this->height()));
|
||||||
SkMatrix totalTransform = fInitialTransform;
|
SkMatrix totalTransform = fInitialTransform;
|
||||||
totalTransform.preConcat(fCurrentContentEntry->fState.fMatrix);
|
totalTransform.preConcat(contentEntry->fState.fMatrix);
|
||||||
SkMatrix inverse;
|
SkMatrix inverse;
|
||||||
inverse.reset();
|
inverse.reset();
|
||||||
totalTransform.invert(&inverse);
|
totalTransform.invert(&inverse);
|
||||||
inverse.mapRect(&bbox);
|
inverse.mapRect(&bbox);
|
||||||
|
|
||||||
SkPDFUtils::AppendRectangle(bbox, &fCurrentContentEntry->fContent);
|
SkPDFUtils::AppendRectangle(bbox, &contentEntry->fContent);
|
||||||
SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType,
|
SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType,
|
||||||
&fCurrentContentEntry->fContent);
|
&contentEntry->fContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPDFDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode,
|
void SkPDFDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode,
|
||||||
@ -577,44 +630,43 @@ void SkPDFDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContentEntryAccessor content(this, d, *paint);
|
||||||
if (!setUpContentEntry(d.fClipStack, *d.fClip, *d.fMatrix, *paint)) {
|
if (!content.entry()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case SkCanvas::kPolygon_PointMode:
|
case SkCanvas::kPolygon_PointMode:
|
||||||
SkPDFUtils::MoveTo(points[0].fX, points[0].fY,
|
SkPDFUtils::MoveTo(points[0].fX, points[0].fY,
|
||||||
&fCurrentContentEntry->fContent);
|
&content.entry()->fContent);
|
||||||
for (size_t i = 1; i < count; i++) {
|
for (size_t i = 1; i < count; i++) {
|
||||||
SkPDFUtils::AppendLine(points[i].fX, points[i].fY,
|
SkPDFUtils::AppendLine(points[i].fX, points[i].fY,
|
||||||
&fCurrentContentEntry->fContent);
|
&content.entry()->fContent);
|
||||||
}
|
}
|
||||||
SkPDFUtils::StrokePath(&fCurrentContentEntry->fContent);
|
SkPDFUtils::StrokePath(&content.entry()->fContent);
|
||||||
break;
|
break;
|
||||||
case SkCanvas::kLines_PointMode:
|
case SkCanvas::kLines_PointMode:
|
||||||
for (size_t i = 0; i < count/2; i++) {
|
for (size_t i = 0; i < count/2; i++) {
|
||||||
SkPDFUtils::MoveTo(points[i * 2].fX, points[i * 2].fY,
|
SkPDFUtils::MoveTo(points[i * 2].fX, points[i * 2].fY,
|
||||||
&fCurrentContentEntry->fContent);
|
&content.entry()->fContent);
|
||||||
SkPDFUtils::AppendLine(points[i * 2 + 1].fX,
|
SkPDFUtils::AppendLine(points[i * 2 + 1].fX,
|
||||||
points[i * 2 + 1].fY,
|
points[i * 2 + 1].fY,
|
||||||
&fCurrentContentEntry->fContent);
|
&content.entry()->fContent);
|
||||||
SkPDFUtils::StrokePath(&fCurrentContentEntry->fContent);
|
SkPDFUtils::StrokePath(&content.entry()->fContent);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SkCanvas::kPoints_PointMode:
|
case SkCanvas::kPoints_PointMode:
|
||||||
SkASSERT(paint->getStrokeCap() == SkPaint::kRound_Cap);
|
SkASSERT(paint->getStrokeCap() == SkPaint::kRound_Cap);
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
SkPDFUtils::MoveTo(points[i].fX, points[i].fY,
|
SkPDFUtils::MoveTo(points[i].fX, points[i].fY,
|
||||||
&fCurrentContentEntry->fContent);
|
&content.entry()->fContent);
|
||||||
SkPDFUtils::ClosePath(&fCurrentContentEntry->fContent);
|
SkPDFUtils::ClosePath(&content.entry()->fContent);
|
||||||
SkPDFUtils::StrokePath(&fCurrentContentEntry->fContent);
|
SkPDFUtils::StrokePath(&content.entry()->fContent);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SkASSERT(false);
|
SkASSERT(false);
|
||||||
}
|
}
|
||||||
finishContentEntry(*paint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPDFDevice::drawRect(const SkDraw& d, const SkRect& r,
|
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);
|
drawPath(d, path, paint, NULL, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!setUpContentEntry(d.fClipStack, *d.fClip, *d.fMatrix, paint)) {
|
|
||||||
|
ContentEntryAccessor content(this, d, paint);
|
||||||
|
if (!content.entry()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
SkPDFUtils::AppendRectangle(r, &content.entry()->fContent);
|
||||||
SkPDFUtils::AppendRectangle(r, &fCurrentContentEntry->fContent);
|
|
||||||
SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType,
|
SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType,
|
||||||
&fCurrentContentEntry->fContent);
|
&content.entry()->fContent);
|
||||||
finishContentEntry(paint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& origPath,
|
void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& origPath,
|
||||||
@ -681,13 +733,13 @@ void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& origPath,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!setUpContentEntry(d.fClipStack, *d.fClip, *d.fMatrix, paint)) {
|
ContentEntryAccessor content(this, d, paint);
|
||||||
|
if (!content.entry()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SkPDFUtils::EmitPath(*pathPtr, &fCurrentContentEntry->fContent);
|
SkPDFUtils::EmitPath(*pathPtr, &content.entry()->fContent);
|
||||||
SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(),
|
SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(),
|
||||||
&fCurrentContentEntry->fContent);
|
&content.entry()->fContent);
|
||||||
finishContentEntry(paint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPDFDevice::drawBitmap(const SkDraw& d, const SkBitmap& bitmap,
|
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,
|
void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
|
||||||
SkScalar x, SkScalar y, const SkPaint& paint) {
|
SkScalar x, SkScalar y, const SkPaint& paint) {
|
||||||
SkPaint textPaint = calculate_text_paint(paint);
|
SkPaint textPaint = calculate_text_paint(paint);
|
||||||
if (!setUpContentEntryForText(d.fClipStack, *d.fClip, *d.fMatrix,
|
ContentEntryAccessor content(this, d, textPaint, true);
|
||||||
textPaint)) {
|
if (!content.entry()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -746,23 +798,24 @@ void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
|
|||||||
SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
|
SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
|
||||||
align_text(glyphCacheProc, textPaint, glyphIDs, numGlyphs, &x, &y,
|
align_text(glyphCacheProc, textPaint, glyphIDs, numGlyphs, &x, &y,
|
||||||
widthPtr);
|
widthPtr);
|
||||||
fCurrentContentEntry->fContent.writeText("BT\n");
|
content.entry()->fContent.writeText("BT\n");
|
||||||
setTextTransform(x, y, textPaint.getTextSkewX());
|
set_text_transform(x, y, textPaint.getTextSkewX(),
|
||||||
|
&content.entry()->fContent);
|
||||||
size_t consumedGlyphCount = 0;
|
size_t consumedGlyphCount = 0;
|
||||||
while (numGlyphs > consumedGlyphCount) {
|
while (numGlyphs > consumedGlyphCount) {
|
||||||
updateFont(textPaint, glyphIDs[consumedGlyphCount]);
|
updateFont(textPaint, glyphIDs[consumedGlyphCount], content.entry());
|
||||||
SkPDFFont* font = fCurrentContentEntry->fState.fFont;
|
SkPDFFont* font = content.entry()->fState.fFont;
|
||||||
size_t availableGlyphs =
|
size_t availableGlyphs =
|
||||||
font->glyphsToPDFFontEncoding(glyphIDs + consumedGlyphCount,
|
font->glyphsToPDFFontEncoding(glyphIDs + consumedGlyphCount,
|
||||||
numGlyphs - consumedGlyphCount);
|
numGlyphs - consumedGlyphCount);
|
||||||
SkString encodedString =
|
SkString encodedString =
|
||||||
SkPDFString::formatString(glyphIDs + consumedGlyphCount,
|
SkPDFString::formatString(glyphIDs + consumedGlyphCount,
|
||||||
availableGlyphs, font->multiByteGlyphs());
|
availableGlyphs, font->multiByteGlyphs());
|
||||||
fCurrentContentEntry->fContent.writeText(encodedString.c_str());
|
content.entry()->fContent.writeText(encodedString.c_str());
|
||||||
consumedGlyphCount += availableGlyphs;
|
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.
|
// Draw underline and/or strikethrough if the paint has them.
|
||||||
// drawPosText() and drawTextOnPath() don't draw underline or strikethrough
|
// 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);
|
drawRect(d, r, paint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finishContentEntry(textPaint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
|
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) {
|
int scalarsPerPos, const SkPaint& paint) {
|
||||||
SkASSERT(1 == scalarsPerPos || 2 == scalarsPerPos);
|
SkASSERT(1 == scalarsPerPos || 2 == scalarsPerPos);
|
||||||
SkPaint textPaint = calculate_text_paint(paint);
|
SkPaint textPaint = calculate_text_paint(paint);
|
||||||
if (!setUpContentEntryForText(d.fClipStack, *d.fClip, *d.fMatrix,
|
ContentEntryAccessor content(this, d, textPaint, true);
|
||||||
textPaint)) {
|
if (!content.entry()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -814,28 +866,28 @@ void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
|
|||||||
}
|
}
|
||||||
|
|
||||||
SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
|
SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
|
||||||
fCurrentContentEntry->fContent.writeText("BT\n");
|
content.entry()->fContent.writeText("BT\n");
|
||||||
updateFont(textPaint, glyphIDs[0]);
|
updateFont(textPaint, glyphIDs[0], content.entry());
|
||||||
for (size_t i = 0; i < numGlyphs; i++) {
|
for (size_t i = 0; i < numGlyphs; i++) {
|
||||||
SkPDFFont* font = fCurrentContentEntry->fState.fFont;
|
SkPDFFont* font = content.entry()->fState.fFont;
|
||||||
uint16_t encodedValue = glyphIDs[i];
|
uint16_t encodedValue = glyphIDs[i];
|
||||||
if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) {
|
if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) {
|
||||||
updateFont(textPaint, glyphIDs[i]);
|
updateFont(textPaint, glyphIDs[i], content.entry());
|
||||||
i--;
|
i--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
SkScalar x = pos[i * scalarsPerPos];
|
SkScalar x = pos[i * scalarsPerPos];
|
||||||
SkScalar y = scalarsPerPos == 1 ? constY : pos[i * scalarsPerPos + 1];
|
SkScalar y = scalarsPerPos == 1 ? constY : pos[i * scalarsPerPos + 1];
|
||||||
align_text(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y, NULL);
|
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 =
|
SkString encodedString =
|
||||||
SkPDFString::formatString(&encodedValue, 1,
|
SkPDFString::formatString(&encodedValue, 1,
|
||||||
font->multiByteGlyphs());
|
font->multiByteGlyphs());
|
||||||
fCurrentContentEntry->fContent.writeText(encodedString.c_str());
|
content.entry()->fContent.writeText(encodedString.c_str());
|
||||||
fCurrentContentEntry->fContent.writeText(" Tj\n");
|
content.entry()->fContent.writeText(" Tj\n");
|
||||||
}
|
}
|
||||||
fCurrentContentEntry->fContent.writeText("ET\n");
|
content.entry()->fContent.writeText("ET\n");
|
||||||
finishContentEntry(textPaint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPDFDevice::drawTextOnPath(const SkDraw& d, const void* text, size_t len,
|
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;
|
SkMatrix matrix;
|
||||||
matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -877,8 +930,7 @@ void SkPDFDevice::drawDevice(const SkDraw& d, SkDevice* device, int x, int y,
|
|||||||
SkPDFFormXObject* xobject = new SkPDFFormXObject(pdfDevice);
|
SkPDFFormXObject* xobject = new SkPDFFormXObject(pdfDevice);
|
||||||
fXObjectResources.push(xobject); // Transfer reference.
|
fXObjectResources.push(xobject); // Transfer reference.
|
||||||
SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
|
SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
|
||||||
&fCurrentContentEntry->fContent);
|
&content.entry()->fContent);
|
||||||
finishContentEntry(paint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const SkRefPtr<SkPDFDict>& SkPDFDevice::getResourceDict() {
|
const SkRefPtr<SkPDFDict>& SkPDFDevice::getResourceDict() {
|
||||||
@ -1069,29 +1121,32 @@ void SkPDFDevice::drawFormXObjectWithClip(SkPDFFormXObject* xobject,
|
|||||||
sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref.
|
sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref.
|
||||||
|
|
||||||
// Draw the xobject with the clip as a mask.
|
// Draw the xobject with the clip as a mask.
|
||||||
setUpContentEntry(&fExistingClipStack, fExistingClipRegion, identity,
|
ContentEntryAccessor content(this, &fExistingClipStack, fExistingClipRegion,
|
||||||
stockPaint);
|
identity, stockPaint);
|
||||||
|
if (!content.entry()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
|
SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
|
||||||
&fCurrentContentEntry->fContent);
|
&content.entry()->fContent);
|
||||||
SkPDFUtils::DrawFormXObject(fXObjectResources.count(),
|
SkPDFUtils::DrawFormXObject(fXObjectResources.count(),
|
||||||
&fCurrentContentEntry->fContent);
|
&content.entry()->fContent);
|
||||||
fXObjectResources.push(xobject);
|
fXObjectResources.push(xobject);
|
||||||
xobject->ref();
|
xobject->ref();
|
||||||
|
|
||||||
sMaskGS = SkPDFGraphicState::getNoSMaskGraphicState();
|
sMaskGS = SkPDFGraphicState::getNoSMaskGraphicState();
|
||||||
sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref.
|
sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref.
|
||||||
SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
|
SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
|
||||||
&fCurrentContentEntry->fContent);
|
&content.entry()->fContent);
|
||||||
finishContentEntry(stockPaint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
|
ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
|
||||||
const SkRegion& clipRegion,
|
const SkRegion& clipRegion,
|
||||||
const SkMatrix& matrix,
|
const SkMatrix& matrix,
|
||||||
const SkPaint& paint,
|
const SkPaint& paint,
|
||||||
bool hasText) {
|
bool hasText,
|
||||||
|
SkRefPtr<SkPDFFormXObject>* dst) {
|
||||||
if (clipRegion.isEmpty()) {
|
if (clipRegion.isEmpty()) {
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The clip stack can come from an SkDraw where it is technically optional.
|
// 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 ||
|
if (xfermode == SkXfermode::kClear_Mode ||
|
||||||
xfermode == SkXfermode::kSrc_Mode) {
|
xfermode == SkXfermode::kSrc_Mode) {
|
||||||
this->clearClipFromContent(clipStack, clipRegion);
|
this->clearClipFromContent(clipStack, clipRegion);
|
||||||
}
|
} else if (xfermode == SkXfermode::kSrcIn_Mode ||
|
||||||
|
xfermode == SkXfermode::kDstIn_Mode ||
|
||||||
// For the following modes, we use both source and destination, but
|
xfermode == SkXfermode::kSrcOut_Mode ||
|
||||||
// we use one as a smask for the other, so we have to make form xobjects
|
xfermode == SkXfermode::kDstOut_Mode) {
|
||||||
// out of both of them: SrcIn, DstIn, SrcOut, DstOut.
|
// For the following modes, we use both source and destination, but
|
||||||
if (xfermode == SkXfermode::kSrcIn_Mode ||
|
// we use one as a smask for the other, so we have to make form xobjects
|
||||||
xfermode == SkXfermode::kDstIn_Mode ||
|
// out of both of them: SrcIn, DstIn, SrcOut, DstOut.
|
||||||
xfermode == SkXfermode::kSrcOut_Mode ||
|
|
||||||
xfermode == SkXfermode::kDstOut_Mode) {
|
|
||||||
if (isContentEmpty()) {
|
if (isContentEmpty()) {
|
||||||
return false;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
SkASSERT(fDstFormXObject.get() == NULL);
|
createFormXObjectFromDevice(dst);
|
||||||
createFormXObjectFromDevice(&fDstFormXObject);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(vandebo) Figure out how/if we can handle the following modes:
|
// TODO(vandebo) Figure out how/if we can handle the following modes:
|
||||||
// SrcAtop, DestAtop, Xor, Plus.
|
// SrcAtop, DestAtop, Xor, Plus.
|
||||||
|
|
||||||
// These xfer modes don't draw source at all.
|
// These xfer modes don't draw source at all.
|
||||||
if (xfermode == SkXfermode::kClear_Mode ||
|
if (xfermode == SkXfermode::kClear_Mode ||
|
||||||
xfermode == SkXfermode::kDst_Mode) {
|
xfermode == SkXfermode::kDst_Mode) {
|
||||||
return false;
|
return NULL;
|
||||||
}
|
|
||||||
|
|
||||||
// If the previous content entry was for DstOver reset fCurrentContentEntry.
|
|
||||||
if (fCurrentContentEntry && xfermode != SkXfermode::kDstOver_Mode) {
|
|
||||||
while (fCurrentContentEntry->fNext.get()) {
|
|
||||||
fCurrentContentEntry = fCurrentContentEntry->fNext.get();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentEntry* entry;
|
ContentEntry* entry;
|
||||||
SkTScopedPtr<ContentEntry> newEntry;
|
SkTScopedPtr<ContentEntry> newEntry;
|
||||||
if (fCurrentContentEntry &&
|
if (fLastContentEntry && fLastContentEntry->fContent.getOffset() == 0) {
|
||||||
fCurrentContentEntry->fContent.getOffset() == 0) {
|
entry = fLastContentEntry;
|
||||||
entry = fCurrentContentEntry;
|
|
||||||
} else {
|
} else {
|
||||||
newEntry.reset(new ContentEntry);
|
newEntry.reset(new ContentEntry);
|
||||||
entry = newEntry.get();
|
entry = newEntry.get();
|
||||||
@ -1164,95 +1207,87 @@ bool SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
|
|||||||
|
|
||||||
populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint,
|
populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint,
|
||||||
hasText, &entry->fState);
|
hasText, &entry->fState);
|
||||||
if (fCurrentContentEntry && xfermode != SkXfermode::kDstOver_Mode &&
|
if (fLastContentEntry && xfermode != SkXfermode::kDstOver_Mode &&
|
||||||
entry->fState.compareInitialState(fCurrentContentEntry->fState)) {
|
entry->fState.compareInitialState(fLastContentEntry->fState)) {
|
||||||
return true;
|
return fLastContentEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fCurrentContentEntry) {
|
if (!fLastContentEntry) {
|
||||||
fContentEntries.reset(entry);
|
fContentEntries.reset(entry);
|
||||||
|
fLastContentEntry = entry;
|
||||||
} else if (xfermode == SkXfermode::kDstOver_Mode) {
|
} else if (xfermode == SkXfermode::kDstOver_Mode) {
|
||||||
entry->fNext.reset(fContentEntries.release());
|
entry->fNext.reset(fContentEntries.release());
|
||||||
fContentEntries.reset(entry);
|
fContentEntries.reset(entry);
|
||||||
} else {
|
} else {
|
||||||
fCurrentContentEntry->fNext.reset(entry);
|
fLastContentEntry->fNext.reset(entry);
|
||||||
|
fLastContentEntry = entry;
|
||||||
}
|
}
|
||||||
newEntry.release();
|
newEntry.release();
|
||||||
fCurrentContentEntry = entry;
|
return entry;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkPDFDevice::setUpContentEntryForText(const SkClipStack* clipStack,
|
void SkPDFDevice::finishContentEntry(const SkXfermode::Mode xfermode,
|
||||||
const SkRegion& clipRegion,
|
SkPDFFormXObject* dst) {
|
||||||
const SkMatrix& matrix,
|
|
||||||
const SkPaint& paint) {
|
|
||||||
return setUpContentEntry(clipStack, clipRegion, matrix, paint, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkPDFDevice::finishContentEntry(const SkPaint& paint) {
|
|
||||||
SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode;
|
|
||||||
if (paint.getXfermode()) {
|
|
||||||
paint.getXfermode()->asMode(&xfermode);
|
|
||||||
}
|
|
||||||
if (xfermode != SkXfermode::kSrcIn_Mode &&
|
if (xfermode != SkXfermode::kSrcIn_Mode &&
|
||||||
xfermode != SkXfermode::kDstIn_Mode &&
|
xfermode != SkXfermode::kDstIn_Mode &&
|
||||||
xfermode != SkXfermode::kSrcOut_Mode &&
|
xfermode != SkXfermode::kSrcOut_Mode &&
|
||||||
xfermode != SkXfermode::kDstOut_Mode) {
|
xfermode != SkXfermode::kDstOut_Mode) {
|
||||||
|
SkASSERT(!dst);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
SkASSERT(dst);
|
||||||
|
SkASSERT(!fContentEntries->fNext.get());
|
||||||
|
|
||||||
// We have to make a copy of these here because changing the current
|
// 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 = fCurrentContentEntry->fState.fClipStack;
|
SkClipStack clipStack = fContentEntries->fState.fClipStack;
|
||||||
SkRegion clipRegion = fCurrentContentEntry->fState.fClipRegion;
|
SkRegion clipRegion = fContentEntries->fState.fClipRegion;
|
||||||
|
|
||||||
SkRefPtr<SkPDFFormXObject> srcFormXObject;
|
SkRefPtr<SkPDFFormXObject> srcFormXObject;
|
||||||
if (!isContentEmpty()) {
|
if (!isContentEmpty()) {
|
||||||
createFormXObjectFromDevice(&srcFormXObject);
|
createFormXObjectFromDevice(&srcFormXObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawFormXObjectWithClip(fDstFormXObject.get(), &clipStack, clipRegion,
|
drawFormXObjectWithClip(dst, &clipStack, clipRegion, true);
|
||||||
true);
|
|
||||||
|
|
||||||
// We've redrawn dst minus the clip area, if there's no src, we're done.
|
// We've redrawn dst minus the clip area, if there's no src, we're done.
|
||||||
if (!srcFormXObject.get()) {
|
if (!srcFormXObject.get()) {
|
||||||
fDstFormXObject = NULL;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkMatrix identity;
|
SkMatrix identity;
|
||||||
identity.reset();
|
identity.reset();
|
||||||
SkPaint stockPaint;
|
SkPaint stockPaint;
|
||||||
setUpContentEntry(&fExistingClipStack, fExistingClipRegion, identity,
|
ContentEntryAccessor inClipContentEntry(this, &fExistingClipStack,
|
||||||
stockPaint);
|
fExistingClipRegion, identity,
|
||||||
|
stockPaint);
|
||||||
|
if (!inClipContentEntry.entry()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SkRefPtr<SkPDFGraphicState> sMaskGS;
|
SkRefPtr<SkPDFGraphicState> sMaskGS;
|
||||||
if (xfermode == SkXfermode::kSrcIn_Mode ||
|
if (xfermode == SkXfermode::kSrcIn_Mode ||
|
||||||
xfermode == SkXfermode::kSrcOut_Mode) {
|
xfermode == SkXfermode::kSrcOut_Mode) {
|
||||||
sMaskGS = SkPDFGraphicState::getSMaskGraphicState(
|
sMaskGS = SkPDFGraphicState::getSMaskGraphicState(
|
||||||
fDstFormXObject.get(), xfermode == SkXfermode::kSrcOut_Mode);
|
dst, xfermode == SkXfermode::kSrcOut_Mode);
|
||||||
fXObjectResources.push(srcFormXObject.get());
|
fXObjectResources.push(srcFormXObject.get());
|
||||||
srcFormXObject->ref();
|
srcFormXObject->ref();
|
||||||
} else {
|
} else {
|
||||||
sMaskGS = SkPDFGraphicState::getSMaskGraphicState(
|
sMaskGS = SkPDFGraphicState::getSMaskGraphicState(
|
||||||
srcFormXObject.get(), xfermode == SkXfermode::kDstOut_Mode);
|
srcFormXObject.get(), xfermode == SkXfermode::kDstOut_Mode);
|
||||||
// fDstFormXObject already added to fXObjectResources in
|
// dst already added to fXObjectResources in drawFormXObjectWithClip.
|
||||||
// drawFormXObjectWithClip.
|
|
||||||
}
|
}
|
||||||
sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref.
|
sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref.
|
||||||
SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
|
SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
|
||||||
&fCurrentContentEntry->fContent);
|
&inClipContentEntry.entry()->fContent);
|
||||||
|
|
||||||
SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
|
SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
|
||||||
&fCurrentContentEntry->fContent);
|
&inClipContentEntry.entry()->fContent);
|
||||||
|
|
||||||
sMaskGS = SkPDFGraphicState::getNoSMaskGraphicState();
|
sMaskGS = SkPDFGraphicState::getNoSMaskGraphicState();
|
||||||
sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref.
|
sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref.
|
||||||
SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
|
SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
|
||||||
&fCurrentContentEntry->fContent);
|
&inClipContentEntry.entry()->fContent);
|
||||||
|
|
||||||
fDstFormXObject = NULL;
|
|
||||||
finishContentEntry(stockPaint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkPDFDevice::isContentEmpty() {
|
bool SkPDFDevice::isContentEmpty() {
|
||||||
@ -1292,7 +1327,7 @@ void SkPDFDevice::populateGraphicStateEntryFromPaint(
|
|||||||
|
|
||||||
// PDF doesn't support kClamp_TileMode, so we simulate it by making
|
// PDF doesn't support kClamp_TileMode, so we simulate it by making
|
||||||
// a pattern the size of the current clip.
|
// a pattern the size of the current clip.
|
||||||
SkIRect bounds = fCurrentContentEntry->fState.fClipRegion.getBounds();
|
SkIRect bounds = clipRegion.getBounds();
|
||||||
pdfShader = SkPDFShader::getPDFShader(*shader, transform, bounds);
|
pdfShader = SkPDFShader::getPDFShader(*shader, transform, bounds);
|
||||||
SkSafeUnref(pdfShader.get()); // getShader and SkRefPtr both took a ref
|
SkSafeUnref(pdfShader.get()); // getShader and SkRefPtr both took a ref
|
||||||
|
|
||||||
@ -1364,19 +1399,19 @@ int SkPDFDevice::addGraphicStateResource(SkPDFGraphicState* gs) {
|
|||||||
return result;
|
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();
|
SkTypeface* typeface = paint.getTypeface();
|
||||||
if (fCurrentContentEntry->fState.fFont == NULL ||
|
if (contentEntry->fState.fFont == NULL ||
|
||||||
fCurrentContentEntry->fState.fTextSize != paint.getTextSize() ||
|
contentEntry->fState.fTextSize != paint.getTextSize() ||
|
||||||
!fCurrentContentEntry->fState.fFont->hasGlyph(glyphID)) {
|
!contentEntry->fState.fFont->hasGlyph(glyphID)) {
|
||||||
int fontIndex = getFontResourceIndex(typeface, glyphID);
|
int fontIndex = getFontResourceIndex(typeface, glyphID);
|
||||||
fCurrentContentEntry->fContent.writeText("/F");
|
contentEntry->fContent.writeText("/F");
|
||||||
fCurrentContentEntry->fContent.writeDecAsText(fontIndex);
|
contentEntry->fContent.writeDecAsText(fontIndex);
|
||||||
fCurrentContentEntry->fContent.writeText(" ");
|
contentEntry->fContent.writeText(" ");
|
||||||
SkPDFScalar::Append(paint.getTextSize(),
|
SkPDFScalar::Append(paint.getTextSize(), &contentEntry->fContent);
|
||||||
&fCurrentContentEntry->fContent);
|
contentEntry->fContent.writeText(" Tf\n");
|
||||||
fCurrentContentEntry->fContent.writeText(" Tf\n");
|
contentEntry->fState.fFont = fFontResources[fontIndex];
|
||||||
fCurrentContentEntry->fState.fFont = fFontResources[fontIndex];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1392,18 +1427,6 @@ int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) {
|
|||||||
return resourceIndex;
|
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,
|
void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix,
|
||||||
const SkClipStack* clipStack,
|
const SkClipStack* clipStack,
|
||||||
const SkRegion& clipRegion,
|
const SkRegion& clipRegion,
|
||||||
@ -1419,7 +1442,8 @@ void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix,
|
|||||||
scaled.postScale(SkIntToScalar(subset.width()),
|
scaled.postScale(SkIntToScalar(subset.width()),
|
||||||
SkIntToScalar(subset.height()));
|
SkIntToScalar(subset.height()));
|
||||||
scaled.postConcat(matrix);
|
scaled.postConcat(matrix);
|
||||||
if (!setUpContentEntry(clipStack, clipRegion, scaled, paint)) {
|
ContentEntryAccessor content(this, clipStack, clipRegion, scaled, paint);
|
||||||
|
if (!content.entry()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1434,6 +1458,5 @@ void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix,
|
|||||||
|
|
||||||
fXObjectResources.push(image); // Transfer reference.
|
fXObjectResources.push(image); // Transfer reference.
|
||||||
SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
|
SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
|
||||||
&fCurrentContentEntry->fContent);
|
&content.entry()->fContent);
|
||||||
finishContentEntry(paint);
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user