aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/pdf
diff options
context:
space:
mode:
Diffstat (limited to 'src/pdf')
-rw-r--r--src/pdf/SkPDFDevice.cpp48
-rw-r--r--src/pdf/SkPDFDevice.h61
-rw-r--r--src/pdf/SkPDFDocument.cpp6
-rw-r--r--src/pdf/SkPDFDocument.h11
-rw-r--r--src/pdf/SkPDFShader.cpp41
-rw-r--r--src/pdf/SkPDFShader.h6
-rw-r--r--src/pdf/SkPDFUtils.h2
7 files changed, 77 insertions, 98 deletions
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index c81bd9b8b0..5fc914d3ab 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -58,8 +58,6 @@
// encoding.
#endif
-#define DPI_FOR_RASTER_SCALE_ONE 72
-
// Utility functions
// This function destroys the mask and either frees or takes the pixels.
@@ -460,13 +458,11 @@ SkBaseDevice* SkPDFDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint
return SkBitmapDevice::Create(cinfo.fInfo, SkSurfaceProps(0, kUnknown_SkPixelGeometry));
}
SkISize size = SkISize::Make(cinfo.fInfo.width(), cinfo.fInfo.height());
- return SkPDFDevice::Make(size, fRasterDpi, fDocument).release();
+ return new SkPDFDevice(size, fDocument);
}
SkPDFCanon* SkPDFDevice::getCanon() const { return fDocument->canon(); }
-
-
// 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 ScopedContentEntry {
@@ -549,25 +545,24 @@ private:
////////////////////////////////////////////////////////////////////////////////
-SkPDFDevice::SkPDFDevice(SkISize pageSize, SkScalar rasterDpi, SkPDFDocument* doc, bool flip)
+SkPDFDevice::SkPDFDevice(SkISize pageSize, SkPDFDocument* doc)
: INHERITED(SkImageInfo::MakeUnknown(pageSize.width(), pageSize.height()),
SkSurfaceProps(0, kUnknown_SkPixelGeometry))
, fPageSize(pageSize)
- , fRasterDpi(rasterDpi)
- , fDocument(doc) {
+ , fInitialTransform(SkMatrix::I())
+ , fDocument(doc)
+{
SkASSERT(pageSize.width() > 0);
SkASSERT(pageSize.height() > 0);
+}
- if (flip) {
- // 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.
- fInitialTransform.setTranslate(0, SkIntToScalar(pageSize.fHeight));
- fInitialTransform.preScale(SK_Scalar1, -SK_Scalar1);
- } else {
- fInitialTransform.setIdentity();
- }
+void SkPDFDevice::setFlip() {
+ // 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.
+ fInitialTransform.setTranslate(0, SkIntToScalar(fPageSize.fHeight));
+ fInitialTransform.preScale(SK_Scalar1, -SK_Scalar1);
}
SkPDFDevice::~SkPDFDevice() {
@@ -845,8 +840,8 @@ void SkPDFDevice::internalDrawPathWithFilter(const SkClipStack& clipStack,
: SkStrokeRec::kHairline_InitStyle;
path.transform(ctm, &path);
- // TODO(halcanary): respect fRasterDpi.
- // SkScalar rasterScale = (float)fRasterDpi / DPI_FOR_RASTER_SCALE_ONE;
+ // TODO(halcanary): respect fDocument->rasterDpi().
+ // SkScalar rasterScale = (float)rasterDpi / SkPDFUtils::kDpiForRasterScaleOne;
// Would it be easier to just change the device size (and pre-scale the canvas)?
SkIRect bounds = clipStack.bounds(size(*this)).roundOut();
SkMask sourceMask;
@@ -2177,10 +2172,7 @@ void SkPDFDevice::populateGraphicStateEntryFromPaint(
SkIRect bounds;
clipStackBounds.roundOut(&bounds);
- SkScalar rasterScale =
- SkIntToScalar(fRasterDpi) / DPI_FOR_RASTER_SCALE_ONE;
- pdfShader = SkPDFShader::GetPDFShader(
- fDocument, fRasterDpi, shader, transform, bounds, rasterScale);
+ pdfShader = SkPDFShader::GetPDFShader(fDocument, shader, transform, bounds);
if (pdfShader.get()) {
// pdfShader has been canonicalized so we can directly compare
@@ -2284,9 +2276,7 @@ void SkPDFDevice::internalDrawImage(const SkMatrix& origMatrix,
// Rasterize the bitmap using perspective in a new bitmap.
if (origMatrix.hasPerspective()) {
- if (fRasterDpi == 0) {
- return;
- }
+ SkASSERT(fDocument->rasterDpi() > 0);
// Transform the bitmap in the new space, without taking into
// account the initial transform.
SkPath perspectiveOutline;
@@ -2302,8 +2292,8 @@ void SkPDFDevice::internalDrawImage(const SkMatrix& origMatrix,
// account the initial transform.
SkMatrix total = origMatrix;
total.postConcat(fInitialTransform);
- SkScalar dpiScale = SkIntToScalar(fRasterDpi) /
- SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE);
+ SkScalar dpiScale = SkIntToScalar(fDocument->rasterDpi()) /
+ SkIntToScalar(SkPDFUtils::kDpiForRasterScaleOne);
total.postScale(dpiScale, dpiScale);
SkPath physicalPerspectiveOutline;
diff --git a/src/pdf/SkPDFDevice.h b/src/pdf/SkPDFDevice.h
index ad44bcd12d..8d2c511be0 100644
--- a/src/pdf/SkPDFDevice.h
+++ b/src/pdf/SkPDFDevice.h
@@ -33,53 +33,42 @@ class SkPDFObject;
class SkPDFStream;
class SkRRect;
-/** \class SkPDFDevice
-
- The drawing context for the PDF backend.
-*/
+/**
+ * \class SkPDFDevice
+ *
+ * An SkPDFDevice is the drawing context for a page or layer of PDF
+ * content.
+ */
class SkPDFDevice final : public SkClipStackDevice {
public:
- /** Create a PDF drawing context. SkPDFDevice applies a
- * scale-and-translate transform to move the origin from the
- * bottom left (PDF default) to the top left (Skia default).
+ /**
* @param pageSize Page size in point units.
* 1 point == 127/360 mm == 1/72 inch
- * @param rasterDpi the DPI at which features without native PDF
- * support will be rasterized (e.g. draw image with
- * perspective, draw text with perspective, ...). A
- * larger DPI would create a PDF that reflects the
- * original intent with better fidelity, but it can make
- * for larger PDF files too, which would use more memory
- * while rendering, and it would be slower to be processed
- * or sent online or to printer. A good choice is
- * SK_ScalarDefaultRasterDPI(72.0f).
- * @param SkPDFDocument. A non-null pointer back to the
- * document. The document is repsonsible for
+ * @param document A non-null pointer back to the
+ * PDFDocument object. The document is repsonsible for
* de-duplicating across pages (via the SkPDFCanon) and
* for early serializing of large immutable objects, such
* as images (via SkPDFDocument::serialize()).
*/
- static sk_sp<SkPDFDevice> Make(SkISize pageSize, SkScalar rasterDpi, SkPDFDocument* doc) {
- return sk_sp<SkPDFDevice>(new SkPDFDevice(pageSize, rasterDpi, doc, true));
- }
+ SkPDFDevice(SkISize pageSize, SkPDFDocument* document);
- /** Create a PDF drawing context without fipping the y-axis. */
- static sk_sp<SkPDFDevice> MakeUnflipped(SkISize pageSize,
- SkScalar rasterDpi,
- SkPDFDocument* doc) {
- return sk_sp<SkPDFDevice>(new SkPDFDevice(pageSize, rasterDpi, doc, false));
- }
+ /**
+ * Apply a scale-and-translate transform to move the origin from the
+ * bottom left (PDF default) to the top left (Skia default).
+ */
+ void setFlip();
sk_sp<SkPDFDevice> makeCongruentDevice() {
- return sk_sp<SkPDFDevice>(new SkPDFDevice(fPageSize, fRasterDpi, fDocument, false));
+ return sk_make_sp<SkPDFDevice>(fPageSize, fDocument);
}
~SkPDFDevice() override;
- /** These are called inside the per-device-layer loop for each draw call.
- When these are called, we have already applied any saveLayer operations,
- and are handling any looping from the paint, and any effects from the
- DrawFilter.
+ /**
+ * These are called inside the per-device-layer loop for each draw call.
+ * When these are called, we have already applied any saveLayer
+ * operations, and are handling any looping from the paint, and any
+ * effects from the DrawFilter.
*/
void drawPaint(const SkPaint& paint) override;
void drawPoints(SkCanvas::PointMode mode,
@@ -212,15 +201,9 @@ private:
};
SkSinglyLinkedList<ContentEntry> fContentEntries;
- SkScalar fRasterDpi;
-
SkPDFDocument* fDocument;
- ////////////////////////////////////////////////////////////////////////////
- SkPDFDevice(SkISize pageSize,
- SkScalar rasterDpi,
- SkPDFDocument* doc,
- bool flip);
+ ////////////////////////////////////////////////////////////////////////////
SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp
index 774d023db6..96a79aedb8 100644
--- a/src/pdf/SkPDFDocument.cpp
+++ b/src/pdf/SkPDFDocument.cpp
@@ -215,7 +215,8 @@ SkCanvas* SkPDFDocument::onBeginPage(SkScalar width, SkScalar height,
}
SkISize pageSize = SkISize::Make(
SkScalarRoundToInt(width), SkScalarRoundToInt(height));
- fPageDevice = SkPDFDevice::Make(pageSize, fRasterDpi, this);
+ fPageDevice = sk_make_sp<SkPDFDevice>(pageSize, this);
+ fPageDevice->setFlip(); // Only the top-level device needs to be flipped.
fCanvas.reset(new SkPDFCanvas(fPageDevice));
if (SkRect::MakeWH(width, height) != trimBox) {
fCanvas->clipRect(trimBox);
@@ -439,6 +440,9 @@ sk_sp<SkDocument> SkPDFMakeDocument(SkWStream* stream,
const SkDocument::PDFMetadata& metadata,
sk_sp<SkPixelSerializer> jpeg,
bool pdfa) {
+ if (dpi <= 0) {
+ dpi = 72.0f;
+ }
return stream ? sk_make_sp<SkPDFDocument>(stream, proc, dpi, metadata,
std::move(jpeg), pdfa)
: nullptr;
diff --git a/src/pdf/SkPDFDocument.h b/src/pdf/SkPDFDocument.h
index aa6dcb286f..7f8b6c84a3 100644
--- a/src/pdf/SkPDFDocument.h
+++ b/src/pdf/SkPDFDocument.h
@@ -14,6 +14,16 @@
class SkPDFDevice;
+/* @param rasterDpi the DPI at which features without native PDF
+ * support will be rasterized (e.g. draw image with
+ * perspective, draw text with perspective, ...). A
+ * larger DPI would create a PDF that reflects the
+ * original intent with better fidelity, but it can make
+ * for larger PDF files too, which would use more memory
+ * while rendering, and it would be slower to be processed
+ * or sent online or to printer. A good choice is
+ * SK_ScalarDefaultRasterDPI(72.0f).
+ */
sk_sp<SkDocument> SkPDFMakeDocument(SkWStream* stream,
void (*doneProc)(SkWStream*, bool),
SkScalar rasterDpi,
@@ -67,6 +77,7 @@ public:
*/
void serialize(const sk_sp<SkPDFObject>&);
SkPDFCanon* canon() { return &fCanon; }
+ SkScalar rasterDpi() const { return fRasterDpi; }
void registerFont(SkPDFFont* f) { fFonts.add(f); }
private:
diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp
index 235d66341b..7369abf8ac 100644
--- a/src/pdf/SkPDFShader.cpp
+++ b/src/pdf/SkPDFShader.cpp
@@ -275,7 +275,7 @@ static sk_sp<SkPDFDict> gradientStitchCode(const SkShader::GradientInfo& info) {
encode->appendScalar(0);
encode->appendScalar(1.0f);
-
+
functions->appendObject(createInterpolationFunction(colorData[i-1], colorData[i]));
}
@@ -525,19 +525,16 @@ static void drawBitmapMatrix(SkCanvas* canvas, const SkBitmap& bm, const SkMatri
////////////////////////////////////////////////////////////////////////////////
static sk_sp<SkPDFStream> make_alpha_function_shader(SkPDFDocument* doc,
- SkScalar dpi,
const SkPDFShader::State& state);
static sk_sp<SkPDFDict> make_function_shader(SkPDFCanon* canon,
const SkPDFShader::State& state);
static sk_sp<SkPDFStream> make_image_shader(SkPDFDocument* doc,
- SkScalar dpi,
const SkPDFShader::State& state,
SkBitmap image);
static sk_sp<SkPDFObject> get_pdf_shader_by_state(
SkPDFDocument* doc,
- SkScalar dpi,
SkPDFShader::State state,
SkBitmap image) {
SkPDFCanon* canon = doc->canon();
@@ -550,14 +547,14 @@ static sk_sp<SkPDFObject> get_pdf_shader_by_state(
} else if (state.fType == SkShader::kNone_GradientType) {
sk_sp<SkPDFObject> shader = canon->findImageShader(state);
if (!shader) {
- shader = make_image_shader(doc, dpi, state, std::move(image));
+ shader = make_image_shader(doc, state, std::move(image));
canon->addImageShader(shader, std::move(state));
}
return shader;
} else if (state.GradientHasAlpha()) {
sk_sp<SkPDFObject> shader = canon->findAlphaShader(state);
if (!shader) {
- shader = make_alpha_function_shader(doc, dpi, state);
+ shader = make_alpha_function_shader(doc, state);
canon->addAlphaShader(shader, std::move(state));
}
return shader;
@@ -572,18 +569,17 @@ static sk_sp<SkPDFObject> get_pdf_shader_by_state(
}
sk_sp<SkPDFObject> SkPDFShader::GetPDFShader(SkPDFDocument* doc,
- SkScalar dpi,
SkShader* shader,
const SkMatrix& matrix,
- const SkIRect& surfaceBBox,
- SkScalar rasterScale) {
+ const SkIRect& surfaceBBox) {
if (surfaceBBox.isEmpty()) {
return nullptr;
}
+ SkScalar rasterDpi = doc->rasterDpi();
+ SkScalar rasterScale = SkIntToScalar(rasterDpi) / SkPDFUtils::kDpiForRasterScaleOne;
SkBitmap image;
State state(shader, matrix, surfaceBBox, rasterScale, &image);
- return get_pdf_shader_by_state(
- doc, dpi, std::move(state), std::move(image));
+ return get_pdf_shader_by_state(doc, std::move(state), std::move(image));
}
static sk_sp<SkPDFDict> get_gradient_resource_dict(
@@ -644,14 +640,13 @@ static std::unique_ptr<SkStreamAsset> create_pattern_fill_content(
* Creates a ExtGState with the SMask set to the luminosityShader in
* luminosity mode. The shader pattern extends to the bbox.
*/
-static sk_sp<SkPDFObject> create_smask_graphic_state(
- SkPDFDocument* doc, SkScalar dpi, const SkPDFShader::State& state) {
+static sk_sp<SkPDFObject> create_smask_graphic_state(SkPDFDocument* doc,
+ const SkPDFShader::State& state) {
SkRect bbox;
bbox.set(state.fBBox);
sk_sp<SkPDFObject> luminosityShader(
- get_pdf_shader_by_state(doc, dpi, state.MakeAlphaToLuminosityState(),
- SkBitmap()));
+ get_pdf_shader_by_state(doc, state.MakeAlphaToLuminosityState(), SkBitmap()));
std::unique_ptr<SkStreamAsset> alphaStream(create_pattern_fill_content(-1, bbox));
@@ -670,7 +665,6 @@ static sk_sp<SkPDFObject> create_smask_graphic_state(
}
static sk_sp<SkPDFStream> make_alpha_function_shader(SkPDFDocument* doc,
- SkScalar dpi,
const SkPDFShader::State& state) {
SkRect bbox;
bbox.set(state.fBBox);
@@ -678,14 +672,14 @@ static sk_sp<SkPDFStream> make_alpha_function_shader(SkPDFDocument* doc,
SkPDFShader::State opaqueState(state.MakeOpaqueState());
sk_sp<SkPDFObject> colorShader(
- get_pdf_shader_by_state(doc, dpi, std::move(opaqueState), SkBitmap()));
+ get_pdf_shader_by_state(doc, std::move(opaqueState), SkBitmap()));
if (!colorShader) {
return nullptr;
}
// Create resource dict with alpha graphics state as G0 and
// pattern shader as P0, then write content stream.
- sk_sp<SkPDFObject> alphaGs = create_smask_graphic_state(doc, dpi, state);
+ sk_sp<SkPDFObject> alphaGs = create_smask_graphic_state(doc, state);
sk_sp<SkPDFDict> resourceDict =
get_gradient_resource_dict(colorShader.get(), alphaGs.get());
@@ -695,7 +689,7 @@ static sk_sp<SkPDFStream> make_alpha_function_shader(SkPDFDocument* doc,
auto alphaFunctionShader = sk_make_sp<SkPDFStream>(std::move(colorStream));
populate_tiling_pattern_dict(alphaFunctionShader->dict(), bbox,
- std::move(resourceDict), SkMatrix::I());
+ std::move(resourceDict), SkMatrix::I());
return alphaFunctionShader;
}
@@ -912,9 +906,9 @@ static sk_sp<SkPDFDict> make_function_shader(SkPDFCanon* canon,
domain->appendScalar(bbox.fRight);
domain->appendScalar(bbox.fTop);
domain->appendScalar(bbox.fBottom);
-
+
SkDynamicMemoryWStream functionCode;
-
+
if (state.fType == SkShader::kConical_GradientType) {
SkShader::GradientInfo twoPointRadialInfo = *info;
SkMatrix inverseMapperMatrix;
@@ -930,7 +924,7 @@ static sk_sp<SkPDFDict> make_function_shader(SkPDFCanon* canon,
} else {
codeFunction(*info, perspectiveInverseOnly, &functionCode);
}
-
+
pdfShader->insertObject("Domain", domain);
std::unique_ptr<SkStreamAsset> functionStream(functionCode.detachAsStream());
@@ -957,7 +951,6 @@ static sk_sp<SkPDFDict> make_function_shader(SkPDFCanon* canon,
}
static sk_sp<SkPDFStream> make_image_shader(SkPDFDocument* doc,
- SkScalar dpi,
const SkPDFShader::State& state,
SkBitmap image) {
SkASSERT(state.fBitmapKey ==
@@ -994,7 +987,7 @@ static sk_sp<SkPDFStream> make_image_shader(SkPDFDocument* doc,
SkISize size = SkISize::Make(SkScalarRoundToInt(deviceBounds.width()),
SkScalarRoundToInt(deviceBounds.height()));
- sk_sp<SkPDFDevice> patternDevice = SkPDFDevice::MakeUnflipped(size, dpi, doc);
+ auto patternDevice = sk_make_sp<SkPDFDevice>(size, doc);
SkCanvas canvas(patternDevice.get());
SkRect patternBBox;
diff --git a/src/pdf/SkPDFShader.h b/src/pdf/SkPDFShader.h
index db13cd50b3..fe561b6d43 100644
--- a/src/pdf/SkPDFShader.h
+++ b/src/pdf/SkPDFShader.h
@@ -37,15 +37,11 @@ public:
* positioned, relative to where the page is drawn.)
* @param surfceBBox The bounding box of the drawing surface (with matrix
* already applied).
- * @param rasterScale Additional scale to be applied for early
- * rasterization.
*/
static sk_sp<SkPDFObject> GetPDFShader(SkPDFDocument* doc,
- SkScalar dpi,
SkShader* shader,
const SkMatrix& matrix,
- const SkIRect& surfaceBBox,
- SkScalar rasterScale);
+ const SkIRect& surfaceBBox);
static sk_sp<SkPDFArray> MakeRangeObject();
diff --git a/src/pdf/SkPDFUtils.h b/src/pdf/SkPDFUtils.h
index 4d0447c194..dfc10b3463 100644
--- a/src/pdf/SkPDFUtils.h
+++ b/src/pdf/SkPDFUtils.h
@@ -35,6 +35,8 @@ struct SkRect;
namespace SkPDFUtils {
+constexpr float kDpiForRasterScaleOne = 72.0f;
+
sk_sp<SkPDFArray> RectToArray(const SkRect& rect);
sk_sp<SkPDFArray> MatrixToArray(const SkMatrix& matrix);
void AppendTransform(const SkMatrix& matrix, SkWStream* content);