Generalize the flip origin argument to the PDF device constructor.
The argument still has a default value that does what most users will want, but provides more flexibility. Chrome will use this change to support an initial translation of the origin to simulate a margin and to scale the entire content (needed on Windows). When landing to Chrome, this will need http://codereview.chromium.org/6820038 Review URL: http://codereview.appspot.com/4373052 git-svn-id: http://skia.googlecode.com/svn/trunk@1111 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
7aaee005fa
commit
75f97e452e
@ -261,7 +261,10 @@ int main (int argc, char * const argv[]) {
|
||||
if (gRec[i].fBackend == kPDF_Backend && writePath) {
|
||||
#ifdef SK_SUPPORT_PDF
|
||||
SkISize size = gm->getISize();
|
||||
SkPDFDevice* dev = new SkPDFDevice(size.width(), size.height());
|
||||
SkMatrix identity;
|
||||
identity.reset();
|
||||
SkPDFDevice* dev = new SkPDFDevice(size.width(), size.height(),
|
||||
identity);
|
||||
SkAutoUnref aur(dev);
|
||||
|
||||
SkCanvas c(dev);
|
||||
|
@ -33,8 +33,8 @@ class SkPDFShader;
|
||||
class SkPDFStream;
|
||||
|
||||
class SkPDFDeviceFactory : public SkDeviceFactory {
|
||||
virtual SkDevice* newDevice(SkCanvas*, SkBitmap::Config, int width, int height,
|
||||
bool isOpaque, bool isForLayer);
|
||||
virtual SkDevice* newDevice(SkCanvas*, SkBitmap::Config, int width,
|
||||
int height, bool isOpaque, bool isForLayer);
|
||||
};
|
||||
|
||||
/** \class SkPDFDevice
|
||||
@ -43,24 +43,22 @@ class SkPDFDeviceFactory : public SkDeviceFactory {
|
||||
*/
|
||||
class SkPDFDevice : public SkDevice {
|
||||
public:
|
||||
/** Skia generally uses the top left as the origin and PDFs natively use
|
||||
the bottom left. We can move the origin to the top left in the PDF
|
||||
with a transform, but we have to be careful to apply the transform
|
||||
only once.
|
||||
*/
|
||||
enum OriginTransform {
|
||||
kFlip_OriginTransform,
|
||||
kNoFlip_OriginTransform,
|
||||
};
|
||||
|
||||
/** Create a PDF drawing context with the given width and height.
|
||||
* 72 points/in means letter paper is 612x792.
|
||||
* @param width Page width in points.
|
||||
* @param height Page height in points.
|
||||
* @param flipOrigin Flip the origin from lower left to upper left.
|
||||
* @param initialTransform The initial transform to apply to the page.
|
||||
* This may be useful to, for example, move the origin in and
|
||||
* over a bit to account for a margin, scale the canvas,
|
||||
* or apply a rotation. Note1: the SkPDFDevice also applies
|
||||
* a scale+translate transform to move the origin from the
|
||||
* bottom left (PDF default) to the top left. Note2: drawDevice
|
||||
* (used by layer restore) draws the device after this initial
|
||||
* transform is applied, so the PDF device factory does an
|
||||
* inverse scale+translate to accommodate the one that SkPDFDevice
|
||||
* always does.
|
||||
*/
|
||||
SkPDFDevice(int width, int height,
|
||||
OriginTransform flipOrigin = kFlip_OriginTransform);
|
||||
SkPDFDevice(int width, int height, const SkMatrix& initialTransform);
|
||||
virtual ~SkPDFDevice();
|
||||
|
||||
virtual SkDeviceFactory* getDeviceFactory() {
|
||||
@ -141,7 +139,7 @@ public:
|
||||
private:
|
||||
int fWidth;
|
||||
int fHeight;
|
||||
OriginTransform fFlipOrigin;
|
||||
SkMatrix fInitialTransform;
|
||||
SkRefPtr<SkPDFDict> fResourceDict;
|
||||
|
||||
SkTDArray<SkPDFGraphicState*> fGraphicStateResources;
|
||||
|
@ -40,6 +40,7 @@ class SkPDFArray;
|
||||
class SkPDFUtils {
|
||||
public:
|
||||
static SkPDFArray* MatrixToArray(const SkMatrix& matrix);
|
||||
static void AppendTransform(const SkMatrix& matrix, SkWStream* content);
|
||||
|
||||
static void MoveTo(SkScalar x, SkScalar y, SkWStream* content);
|
||||
static void AppendLine(SkScalar x, SkScalar y, SkWStream* content);
|
||||
|
@ -113,11 +113,13 @@ void alignText(SkDrawCacheProc glyphCacheProc, const SkPaint& paint,
|
||||
SkDevice* SkPDFDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
|
||||
int width, int height, bool isOpaque,
|
||||
bool isForLayer) {
|
||||
SkPDFDevice::OriginTransform flip = SkPDFDevice::kFlip_OriginTransform;
|
||||
SkMatrix initialTransform;
|
||||
initialTransform.reset();
|
||||
if (isForLayer) {
|
||||
flip = SkPDFDevice::kNoFlip_OriginTransform;
|
||||
initialTransform.setTranslate(0, height);
|
||||
initialTransform.preScale(1, -1);
|
||||
}
|
||||
return SkNEW_ARGS(SkPDFDevice, (width, height, flip));
|
||||
return SkNEW_ARGS(SkPDFDevice, (width, height, initialTransform));
|
||||
}
|
||||
|
||||
static inline SkBitmap makeABitmap(int width, int height) {
|
||||
@ -126,11 +128,11 @@ static inline SkBitmap makeABitmap(int width, int height) {
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
SkPDFDevice::SkPDFDevice(int width, int height, OriginTransform flipOrigin)
|
||||
SkPDFDevice::SkPDFDevice(int width, int height,
|
||||
const SkMatrix& initialTransform)
|
||||
: SkDevice(NULL, makeABitmap(width, height), false),
|
||||
fWidth(width),
|
||||
fHeight(height),
|
||||
fFlipOrigin(flipOrigin),
|
||||
fGraphicStackIndex(0) {
|
||||
fGraphicStack[0].fColor = SK_ColorBLACK;
|
||||
fGraphicStack[0].fTextSize = SK_ScalarNaN; // This has no default value.
|
||||
@ -142,10 +144,14 @@ SkPDFDevice::SkPDFDevice(int width, int height, OriginTransform flipOrigin)
|
||||
fGraphicStack[0].fClip.setRect(0,0, width, height);
|
||||
fGraphicStack[0].fTransform.reset();
|
||||
|
||||
if (flipOrigin == kFlip_OriginTransform) {
|
||||
fContent.writeText("1 0 0 -1 0 ");
|
||||
fContent.writeDecAsText(fHeight);
|
||||
fContent.writeText(" cm\n");
|
||||
// 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.
|
||||
fInitialTransform.setTranslate(0, height);
|
||||
fInitialTransform.preScale(1, -1);
|
||||
fInitialTransform.preConcat(initialTransform);
|
||||
if (fInitialTransform.getType() != SkMatrix::kIdentity_Mask) {
|
||||
SkPDFUtils::AppendTransform(fInitialTransform, &fContent);
|
||||
}
|
||||
}
|
||||
|
||||
@ -601,13 +607,10 @@ void SkPDFDevice::updateGSFromPaint(const SkPaint& paint, bool forText) {
|
||||
// PDF positions patterns relative to the initial transform, so
|
||||
// we need to apply the current transform to the shader parameters.
|
||||
SkMatrix transform = fGraphicStack[fGraphicStackIndex].fTransform;
|
||||
if (fFlipOrigin == kFlip_OriginTransform) {
|
||||
transform.postScale(1, -1);
|
||||
transform.postTranslate(0, fHeight);
|
||||
}
|
||||
transform.postConcat(fInitialTransform);
|
||||
|
||||
// PDF doesn't support kClamp_TileMode, so we simulate it by making
|
||||
// a pattern the size of the drawing service.
|
||||
// a pattern the size of the drawing surface.
|
||||
SkIRect bounds = fGraphicStack[fGraphicStackIndex].fClip.getBounds();
|
||||
pdfShader = SkPDFShader::getPDFShader(*shader, transform, bounds);
|
||||
SkSafeUnref(pdfShader.get()); // getShader and SkRefPtr both took a ref
|
||||
@ -808,13 +811,7 @@ SkMatrix SkPDFDevice::setTransform(const SkMatrix& m) {
|
||||
fGraphicStack[fGraphicStackIndex - 1].fClip)
|
||||
pushGS();
|
||||
|
||||
SkScalar transform[6];
|
||||
SkAssertResult(m.pdfTransform(transform));
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(transform); i++) {
|
||||
SkPDFScalar::Append(transform[i], &fContent);
|
||||
fContent.writeText(" ");
|
||||
}
|
||||
fContent.writeText("cm\n");
|
||||
SkPDFUtils::AppendTransform(m, &fContent);
|
||||
fGraphicStack[fGraphicStackIndex].fTransform = m;
|
||||
|
||||
return old;
|
||||
|
@ -251,15 +251,7 @@ void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
|
||||
content->writeText(" d1\n");
|
||||
}
|
||||
|
||||
SkPDFArray* makeFontBBox(
|
||||
SkIRect glyphBBox, uint16_t emSize,
|
||||
SkPDFDevice::OriginTransform flipOrigin =
|
||||
SkPDFDevice::kNoFlip_OriginTransform) {
|
||||
if (flipOrigin == SkPDFDevice::kFlip_OriginTransform) {
|
||||
int32_t temp = -glyphBBox.fTop;
|
||||
glyphBBox.fTop = -glyphBBox.fBottom;
|
||||
glyphBBox.fBottom = temp;
|
||||
}
|
||||
SkPDFArray* makeFontBBox(SkIRect glyphBBox, uint16_t emSize) {
|
||||
SkPDFArray* bbox = new SkPDFArray;
|
||||
bbox->reserve(4);
|
||||
bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fLeft,
|
||||
|
@ -495,8 +495,10 @@ void SkPDFShader::doImageShader() {
|
||||
surfaceBBox.set(fState.get()->fBBox);
|
||||
transformBBox(finalMatrix, &surfaceBBox);
|
||||
|
||||
SkPDFDevice pattern(surfaceBBox.fRight, surfaceBBox.fBottom,
|
||||
SkPDFDevice::kNoFlip_OriginTransform);
|
||||
SkMatrix unflip;
|
||||
unflip.setTranslate(0, surfaceBBox.fBottom);
|
||||
unflip.preScale(1, -1);
|
||||
SkPDFDevice pattern(surfaceBBox.fRight, surfaceBBox.fBottom, unflip);
|
||||
SkCanvas canvas(&pattern);
|
||||
canvas.clipRect(surfaceBBox, SkRegion::kReplace_Op);
|
||||
|
||||
|
@ -34,6 +34,17 @@ SkPDFArray* SkPDFUtils::MatrixToArray(const SkMatrix& matrix) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
void SkPDFUtils::AppendTransform(const SkMatrix& matrix, SkWStream* content) {
|
||||
SkScalar values[6];
|
||||
SkAssertResult(matrix.pdfTransform(values));
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(values); i++) {
|
||||
SkPDFScalar::Append(values[i], content);
|
||||
content->writeText(" ");
|
||||
}
|
||||
content->writeText("cm\n");
|
||||
}
|
||||
|
||||
// static
|
||||
void SkPDFUtils::MoveTo(SkScalar x, SkScalar y, SkWStream* content) {
|
||||
SkPDFScalar::Append(x, content);
|
||||
|
Loading…
Reference in New Issue
Block a user