SkPDF: clean up fRasterDpi

- PDFDevice no longer has a fRasterDpi; simply queries document.
  - #define DPI_FOR_RASTER_SCALE_ONE becomes constexpr float.
  - PDFShader::GetPDFShader no longer takes rasterScale or dpi
  - Remove un-needed factory functions.  We're all adults here.

Change-Id: Id2ce75d4e61af385763ccfb1db210465a1600067
Reviewed-on: https://skia-review.googlesource.com/21348
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Hal Canary <halcanary@google.com>
This commit is contained in:
Hal Canary 2017-06-29 18:51:35 -04:00 committed by Skia Commit-Bot
parent 1c9686bfa5
commit a062258e76
8 changed files with 80 additions and 102 deletions

View File

@ -216,10 +216,9 @@ struct PDFShaderBench : public Benchmark {
SkNullWStream nullStream;
SkPDFDocument doc(&nullStream, nullptr, 72,
SkDocument::PDFMetadata(), nullptr, false);
sk_sp<SkPDFObject> shader(
SkPDFShader::GetPDFShader(
&doc, 72, fShader.get(), SkMatrix::I(),
SkIRect::MakeWH(400,400), 72));
sk_sp<SkPDFObject> shader =
SkPDFShader::GetPDFShader(&doc, fShader.get(), SkMatrix::I(),
SkIRect::MakeWH(400,400));
}
}
};

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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:

View File

@ -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;

View File

@ -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();

View File

@ -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);