[PDF] Fix setting of existing clip for layers.

The current approach of setting the existing clip just before drawing a layer into a device doesn't work.  SkDevice::clear() uses existing clip before that and if we need to put the content in a transparency group (i.e. for SrcIn xfermode), we need a valid existing clip.  Instead, change the factory to use a special constructor when creating a layer device.

Review URL: http://codereview.appspot.com/4495041

git-svn-id: http://skia.googlecode.com/svn/trunk@1270 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
vandebo@chromium.org 2011-05-09 07:58:08 +00:00
Родитель 9fbdf87518
Коммит a0c7edbb08
2 изменённых файлов: 50 добавлений и 32 удалений

Просмотреть файл

@ -38,6 +38,7 @@ struct ContentEntry;
struct GraphicStateEntry; struct GraphicStateEntry;
class SkPDFDeviceFactory : public SkDeviceFactory { class SkPDFDeviceFactory : public SkDeviceFactory {
public:
virtual SkDevice* newDevice(SkCanvas*, SkBitmap::Config, int width, virtual SkDevice* newDevice(SkCanvas*, SkBitmap::Config, int width,
int height, bool isOpaque, bool isForLayer); int height, bool isOpaque, bool isForLayer);
}; };
@ -138,6 +139,8 @@ protected:
virtual SkDeviceFactory* onNewDeviceFactory(); virtual SkDeviceFactory* onNewDeviceFactory();
private: private:
friend class SkPDFDeviceFactory;
SkISize fPageSize; SkISize fPageSize;
SkISize fContentSize; SkISize fContentSize;
SkMatrix fInitialTransform; SkMatrix fInitialTransform;
@ -153,10 +156,12 @@ private:
SkTScopedPtr<ContentEntry> fContentEntries; SkTScopedPtr<ContentEntry> fContentEntries;
ContentEntry* fCurrentContentEntry; ContentEntry* fCurrentContentEntry;
// For use by the DeviceFactory.
SkPDFDevice(const SkISize& layerSize, const SkClipStack& existingClipStack,
const SkRegion& existingClipRegion);
void init(); void init();
void cleanUp(); void cleanUp();
void setExistingClip(const SkClipStack& clipStack,
const SkRegion& clipRegion);
void setUpContentEntry(const SkClipStack& clipStack, void setUpContentEntry(const SkClipStack& clipStack,
const SkRegion& clipRegion, const SkRegion& clipRegion,

Просмотреть файл

@ -402,47 +402,71 @@ void GraphicStackState::updateDrawingState(const GraphicStateEntry& state) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
SkDevice* SkPDFDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config, SkDevice* SkPDFDeviceFactory::newDevice(SkCanvas* c, SkBitmap::Config config,
int width, int height, bool isOpaque, int width, int height, bool isOpaque,
bool isForLayer) { bool isForLayer) {
SkMatrix initialTransform; SkMatrix initialTransform;
initialTransform.reset(); initialTransform.reset();
if (isForLayer) {
initialTransform.setTranslate(0, height);
initialTransform.preScale(1, -1);
}
SkISize size = SkISize::Make(width, height); SkISize size = SkISize::Make(width, height);
return SkNEW_ARGS(SkPDFDevice, (size, size, initialTransform)); if (isForLayer) {
return SkNEW_ARGS(SkPDFDevice, (size, c->getTotalClipStack(),
c->getTotalClip()));
} else {
return SkNEW_ARGS(SkPDFDevice, (size, size, initialTransform));
}
} }
static inline SkBitmap makeContentBitmap(const SkISize& contentSize, static inline SkBitmap makeContentBitmap(const SkISize& contentSize,
const SkMatrix& initialTransform) { const SkMatrix* initialTransform) {
// Compute the size of the drawing area.
SkVector drawingSize;
SkMatrix inverse;
drawingSize.set(contentSize.fWidth, contentSize.fHeight);
initialTransform.invert(&inverse);
inverse.mapVectors(&drawingSize, 1);
SkISize size = SkSize::Make(drawingSize.fX, drawingSize.fY).toRound();
SkBitmap bitmap; SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kNo_Config, abs(size.fWidth), abs(size.fHeight)); if (initialTransform) {
// Compute the size of the drawing area.
SkVector drawingSize;
SkMatrix inverse;
drawingSize.set(contentSize.fWidth, contentSize.fHeight);
initialTransform->invert(&inverse);
inverse.mapVectors(&drawingSize, 1);
SkISize size = SkSize::Make(drawingSize.fX, drawingSize.fY).toRound();
bitmap.setConfig(SkBitmap::kNo_Config, abs(size.fWidth),
abs(size.fHeight));
} else {
bitmap.setConfig(SkBitmap::kNo_Config, abs(contentSize.fWidth),
abs(contentSize.fHeight));
}
return bitmap; return bitmap;
} }
SkPDFDevice::SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize, SkPDFDevice::SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize,
const SkMatrix& initialTransform) const SkMatrix& initialTransform)
: SkDevice(NULL, makeContentBitmap(contentSize, initialTransform), false), : SkDevice(NULL, makeContentBitmap(contentSize, &initialTransform), false),
fPageSize(pageSize), fPageSize(pageSize),
fContentSize(contentSize), fContentSize(contentSize),
fCurrentContentEntry(NULL) { fCurrentContentEntry(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. When layering, // origin at the bottom left. This matrix corrects for that. But that only
// we specify an inverse correction to cancel this out. // needs to be done once, we don't do it when layering.
fInitialTransform.setTranslate(0, pageSize.fHeight); fInitialTransform.setTranslate(0, pageSize.fHeight);
fInitialTransform.preScale(1, -1); fInitialTransform.preScale(1, -1);
fInitialTransform.preConcat(initialTransform); fInitialTransform.preConcat(initialTransform);
SkIRect existingClip = SkIRect::MakeWH(this->width(), this->height());
fExistingClipStack.clipDevRect(existingClip);
fExistingClipRegion.setRect(existingClip);
this->init();
}
SkPDFDevice::SkPDFDevice(const SkISize& layerSize,
const SkClipStack& existingClipStack,
const SkRegion& existingClipRegion)
: SkDevice(NULL, makeContentBitmap(layerSize, NULL), false),
fPageSize(layerSize),
fContentSize(layerSize),
fExistingClipStack(existingClipStack),
fExistingClipRegion(existingClipRegion),
fCurrentContentEntry(NULL) {
fInitialTransform.reset();
this->init(); this->init();
} }
@ -454,10 +478,6 @@ void SkPDFDevice::init() {
fResourceDict = NULL; fResourceDict = NULL;
fContentEntries.reset(); fContentEntries.reset();
fCurrentContentEntry = NULL; fCurrentContentEntry = NULL;
SkIRect existingClip = SkIRect::MakeWH(this->width(), this->height());
fExistingClipStack.clipDevRect(existingClip);
fExistingClipRegion.setRect(existingClip);
} }
SkDeviceFactory* SkPDFDevice::onNewDeviceFactory() { SkDeviceFactory* SkPDFDevice::onNewDeviceFactory() {
@ -471,12 +491,6 @@ void SkPDFDevice::cleanUp() {
fShaderResources.unrefAll(); fShaderResources.unrefAll();
} }
void SkPDFDevice::setExistingClip(const SkClipStack& clipStack,
const SkRegion& clipRegion) {
this->fExistingClipStack = clipStack;
this->fExistingClipRegion = clipRegion;
}
void SkPDFDevice::clear(SkColor color) { void SkPDFDevice::clear(SkColor color) {
this->cleanUp(); this->cleanUp();
this->init(); this->init();
@ -809,7 +823,6 @@ 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));
setUpContentEntry(*d.fClipStack, *d.fClip, matrix, paint); setUpContentEntry(*d.fClipStack, *d.fClip, matrix, paint);
pdfDevice->setExistingClip(*d.fClipStack, *d.fClip);
SkPDFFormXObject* xobject = new SkPDFFormXObject(pdfDevice); SkPDFFormXObject* xobject = new SkPDFFormXObject(pdfDevice);
fXObjectResources.push(xobject); // Transfer reference. fXObjectResources.push(xobject); // Transfer reference.