[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;
class SkPDFDeviceFactory : public SkDeviceFactory {
public:
virtual SkDevice* newDevice(SkCanvas*, SkBitmap::Config, int width,
int height, bool isOpaque, bool isForLayer);
};
@ -138,6 +139,8 @@ protected:
virtual SkDeviceFactory* onNewDeviceFactory();
private:
friend class SkPDFDeviceFactory;
SkISize fPageSize;
SkISize fContentSize;
SkMatrix fInitialTransform;
@ -153,10 +156,12 @@ private:
SkTScopedPtr<ContentEntry> fContentEntries;
ContentEntry* fCurrentContentEntry;
// For use by the DeviceFactory.
SkPDFDevice(const SkISize& layerSize, const SkClipStack& existingClipStack,
const SkRegion& existingClipRegion);
void init();
void cleanUp();
void setExistingClip(const SkClipStack& clipStack,
const SkRegion& clipRegion);
void setUpContentEntry(const SkClipStack& clipStack,
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,
bool isForLayer) {
SkMatrix initialTransform;
initialTransform.reset();
if (isForLayer) {
initialTransform.setTranslate(0, height);
initialTransform.preScale(1, -1);
}
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,
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();
const SkMatrix* initialTransform) {
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;
}
SkPDFDevice::SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize,
const SkMatrix& initialTransform)
: SkDevice(NULL, makeContentBitmap(contentSize, initialTransform), false),
: SkDevice(NULL, makeContentBitmap(contentSize, &initialTransform), false),
fPageSize(pageSize),
fContentSize(contentSize),
fCurrentContentEntry(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. When layering,
// we specify an inverse correction to cancel this out.
// 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.
fInitialTransform.setTranslate(0, pageSize.fHeight);
fInitialTransform.preScale(1, -1);
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();
}
@ -454,10 +478,6 @@ void SkPDFDevice::init() {
fResourceDict = NULL;
fContentEntries.reset();
fCurrentContentEntry = NULL;
SkIRect existingClip = SkIRect::MakeWH(this->width(), this->height());
fExistingClipStack.clipDevRect(existingClip);
fExistingClipRegion.setRect(existingClip);
}
SkDeviceFactory* SkPDFDevice::onNewDeviceFactory() {
@ -471,12 +491,6 @@ void SkPDFDevice::cleanUp() {
fShaderResources.unrefAll();
}
void SkPDFDevice::setExistingClip(const SkClipStack& clipStack,
const SkRegion& clipRegion) {
this->fExistingClipStack = clipStack;
this->fExistingClipRegion = clipRegion;
}
void SkPDFDevice::clear(SkColor color) {
this->cleanUp();
this->init();
@ -809,7 +823,6 @@ void SkPDFDevice::drawDevice(const SkDraw& d, SkDevice* device, int x, int y,
SkMatrix matrix;
matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
setUpContentEntry(*d.fClipStack, *d.fClip, matrix, paint);
pdfDevice->setExistingClip(*d.fClipStack, *d.fClip);
SkPDFFormXObject* xobject = new SkPDFFormXObject(pdfDevice);
fXObjectResources.push(xobject); // Transfer reference.