SkPdf: SkPDFFormXObject de-class-ified.
We don't need an object, just a few standard fields on the base class; the change lets us get rid of a bunch of boilerplate code. I think this also reduces the cognitive load of the SkPDF internals. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2185803003 Review-Url: https://codereview.chromium.org/2185803003
This commit is contained in:
parent
4b9ebab04d
commit
4b1e17edc7
@ -627,7 +627,7 @@ private:
|
||||
SkPDFDevice* fDevice;
|
||||
SkPDFDevice::ContentEntry* fContentEntry;
|
||||
SkXfermode::Mode fXfermode;
|
||||
SkPDFFormXObject* fDstFormXObject;
|
||||
SkPDFObject* fDstFormXObject;
|
||||
SkPath fShape;
|
||||
|
||||
void init(const SkClipStack* clipStack, const SkRegion& clipRegion,
|
||||
@ -835,7 +835,7 @@ static sk_sp<SkPDFDict> create_link_annotation(const SkRect& translatedRect) {
|
||||
}
|
||||
|
||||
static sk_sp<SkPDFDict> create_link_to_url(const SkData* urlData, const SkRect& r) {
|
||||
auto annotation = create_link_annotation(r);
|
||||
sk_sp<SkPDFDict> annotation = create_link_annotation(r);
|
||||
SkString url(static_cast<const char *>(urlData->data()),
|
||||
urlData->size() - 1);
|
||||
auto action = sk_make_sp<SkPDFDict>("Action");
|
||||
@ -847,7 +847,7 @@ static sk_sp<SkPDFDict> create_link_to_url(const SkData* urlData, const SkRect&
|
||||
|
||||
static sk_sp<SkPDFDict> create_link_named_dest(const SkData* nameData,
|
||||
const SkRect& r) {
|
||||
auto annotation = create_link_annotation(r);
|
||||
sk_sp<SkPDFDict> annotation = create_link_annotation(r);
|
||||
SkString name(static_cast<const char *>(nameData->data()),
|
||||
nameData->size() - 1);
|
||||
annotation->insertName("Dest", name);
|
||||
@ -1394,7 +1394,7 @@ void SkPDFDevice::drawDevice(const SkDraw& d, SkBaseDevice* device,
|
||||
return;
|
||||
}
|
||||
|
||||
auto xObject = sk_make_sp<SkPDFFormXObject>(pdfDevice);
|
||||
sk_sp<SkPDFObject> xObject = pdfDevice->makeFormXObjectFromDevice();
|
||||
SkPDFUtils::DrawFormXObject(this->addXObjectResource(xObject.get()),
|
||||
&content.entry()->fContent);
|
||||
}
|
||||
@ -1610,18 +1610,20 @@ void SkPDFDevice::appendDestinations(SkPDFDict* dict, SkPDFObject* page) const {
|
||||
}
|
||||
}
|
||||
|
||||
SkPDFFormXObject* SkPDFDevice::createFormXObjectFromDevice() {
|
||||
SkPDFFormXObject* xobject = new SkPDFFormXObject(this);
|
||||
sk_sp<SkPDFObject> SkPDFDevice::makeFormXObjectFromDevice() {
|
||||
sk_sp<SkPDFObject> xobject =
|
||||
SkPDFMakeFormXObject(this->content(), this->copyMediaBox(),
|
||||
this->makeResourceDict(), nullptr);
|
||||
// We always draw the form xobjects that we create back into the device, so
|
||||
// we simply preserve the font usage instead of pulling it out and merging
|
||||
// it back in later.
|
||||
cleanUp(); // Reset this device to have no content.
|
||||
init();
|
||||
this->cleanUp(); // Reset this device to have no content.
|
||||
this->init();
|
||||
return xobject;
|
||||
}
|
||||
|
||||
void SkPDFDevice::drawFormXObjectWithMask(int xObjectIndex,
|
||||
SkPDFFormXObject* mask,
|
||||
SkPDFObject* mask,
|
||||
const SkClipStack* clipStack,
|
||||
const SkRegion& clipRegion,
|
||||
SkXfermode::Mode mode,
|
||||
@ -1630,7 +1632,7 @@ void SkPDFDevice::drawFormXObjectWithMask(int xObjectIndex,
|
||||
return;
|
||||
}
|
||||
|
||||
auto sMaskGS = SkPDFGraphicState::GetSMaskGraphicState(
|
||||
sk_sp<SkPDFDict> sMaskGS = SkPDFGraphicState::GetSMaskGraphicState(
|
||||
mask, invertClip, SkPDFGraphicState::kAlpha_SMaskMode, fDocument->canon());
|
||||
|
||||
SkMatrix identity;
|
||||
@ -1658,7 +1660,7 @@ SkPDFDevice::ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* cli
|
||||
const SkMatrix& matrix,
|
||||
const SkPaint& paint,
|
||||
bool hasText,
|
||||
SkPDFFormXObject** dst) {
|
||||
SkPDFObject** dst) {
|
||||
*dst = nullptr;
|
||||
if (clipRegion.isEmpty()) {
|
||||
return nullptr;
|
||||
@ -1699,7 +1701,8 @@ SkPDFDevice::ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* cli
|
||||
xfermode == SkXfermode::kDstATop_Mode ||
|
||||
xfermode == SkXfermode::kModulate_Mode) {
|
||||
if (!isContentEmpty()) {
|
||||
*dst = createFormXObjectFromDevice();
|
||||
// TODO(halcanary): make this safer.
|
||||
*dst = this->makeFormXObjectFromDevice().release();
|
||||
SkASSERT(isContentEmpty());
|
||||
} else if (xfermode != SkXfermode::kSrc_Mode &&
|
||||
xfermode != SkXfermode::kSrcOut_Mode) {
|
||||
@ -1730,7 +1733,7 @@ SkPDFDevice::ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* cli
|
||||
}
|
||||
|
||||
void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode,
|
||||
SkPDFFormXObject* dst,
|
||||
SkPDFObject* dst,
|
||||
SkPath* shape) {
|
||||
if (xfermode != SkXfermode::kClear_Mode &&
|
||||
xfermode != SkXfermode::kSrc_Mode &&
|
||||
@ -1775,7 +1778,7 @@ void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode,
|
||||
identity.reset();
|
||||
SkPaint stockPaint;
|
||||
|
||||
sk_sp<SkPDFFormXObject> srcFormXObject;
|
||||
sk_sp<SkPDFObject> srcFormXObject;
|
||||
if (isContentEmpty()) {
|
||||
// If nothing was drawn and there's no shape, then the draw was a
|
||||
// no-op, but dst needs to be restored for that to be true.
|
||||
@ -1795,7 +1798,7 @@ void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode,
|
||||
}
|
||||
} else {
|
||||
SkASSERT(fContentEntries.count() == 1);
|
||||
srcFormXObject.reset(createFormXObjectFromDevice());
|
||||
srcFormXObject = this->makeFormXObjectFromDevice();
|
||||
}
|
||||
|
||||
// TODO(vandebo) srcFormXObject may contain alpha, but here we want it
|
||||
@ -1809,8 +1812,8 @@ void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode,
|
||||
&fExistingClipStack, fExistingClipRegion,
|
||||
SkXfermode::kSrcOver_Mode, true);
|
||||
} else {
|
||||
sk_sp<SkPDFFormXObject> dstMaskStorage;
|
||||
SkPDFFormXObject* dstMask = srcFormXObject.get();
|
||||
sk_sp<SkPDFObject> dstMaskStorage;
|
||||
SkPDFObject* dstMask = srcFormXObject.get();
|
||||
if (shape != nullptr) {
|
||||
// Draw shape into a form-xobject.
|
||||
SkRasterClip rc(clipRegion);
|
||||
@ -1823,7 +1826,7 @@ void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode,
|
||||
filledPaint.setStyle(SkPaint::kFill_Style);
|
||||
this->drawPath(d, *shape, filledPaint, nullptr, true);
|
||||
|
||||
dstMaskStorage.reset(createFormXObjectFromDevice());
|
||||
dstMaskStorage = this->makeFormXObjectFromDevice();
|
||||
dstMask = dstMaskStorage.get();
|
||||
}
|
||||
drawFormXObjectWithMask(addXObjectResource(dst), dstMask,
|
||||
@ -2184,7 +2187,7 @@ void SkPDFDevice::internalDrawImage(const SkMatrix& origMatrix,
|
||||
SkBitmapKey key = imageBitmap.getKey();
|
||||
sk_sp<SkPDFObject> pdfimage = fDocument->canon()->findPDFBitmap(key);
|
||||
if (!pdfimage) {
|
||||
auto img = imageBitmap.makeImage();
|
||||
sk_sp<SkImage> img = imageBitmap.makeImage();
|
||||
if (!img) {
|
||||
return;
|
||||
}
|
||||
|
@ -29,8 +29,8 @@ class SkPDFDevice;
|
||||
class SkPDFDocument;
|
||||
class SkPDFDict;
|
||||
class SkPDFFont;
|
||||
class SkPDFFormXObject;
|
||||
class SkPDFObject;
|
||||
class SkPDFStream;
|
||||
class SkRRect;
|
||||
|
||||
/** \class SkPDFDevice
|
||||
@ -268,10 +268,10 @@ private:
|
||||
|
||||
void init();
|
||||
void cleanUp();
|
||||
SkPDFFormXObject* createFormXObjectFromDevice();
|
||||
sk_sp<SkPDFObject> makeFormXObjectFromDevice();
|
||||
|
||||
void drawFormXObjectWithMask(int xObjectIndex,
|
||||
SkPDFFormXObject* mask,
|
||||
SkPDFObject* mask,
|
||||
const SkClipStack* clipStack,
|
||||
const SkRegion& clipRegion,
|
||||
SkXfermode::Mode mode,
|
||||
@ -286,9 +286,9 @@ private:
|
||||
const SkMatrix& matrix,
|
||||
const SkPaint& paint,
|
||||
bool hasText,
|
||||
SkPDFFormXObject** dst);
|
||||
SkPDFObject** dst);
|
||||
void finishContentEntry(SkXfermode::Mode xfermode,
|
||||
SkPDFFormXObject* dst,
|
||||
SkPDFObject* dst,
|
||||
SkPath* shape);
|
||||
bool isContentEmpty();
|
||||
|
||||
|
@ -8,69 +8,26 @@
|
||||
|
||||
#include "SkPDFFormXObject.h"
|
||||
|
||||
#include "SkMatrix.h"
|
||||
#include "SkPDFDevice.h"
|
||||
#include "SkPDFUtils.h"
|
||||
#include "SkStream.h"
|
||||
#include "SkTypes.h"
|
||||
sk_sp<SkPDFObject> SkPDFMakeFormXObject(std::unique_ptr<SkStreamAsset> content,
|
||||
sk_sp<SkPDFArray> mediaBox,
|
||||
sk_sp<SkPDFDict> resourceDict,
|
||||
const char* colorSpace) {
|
||||
auto form = sk_make_sp<SkPDFStream>(std::move(content));
|
||||
form->insertName("Type", "XObject");
|
||||
form->insertName("Subtype", "Form");
|
||||
form->insertObject("Resources", std::move(resourceDict));
|
||||
form->insertObject("BBox", std::move(mediaBox));
|
||||
|
||||
SkPDFFormXObject::SkPDFFormXObject(SkPDFDevice* device) {
|
||||
// We don't want to keep around device because we'd have two copies
|
||||
// of content, so reference or copy everything we need (content and
|
||||
// resources).
|
||||
auto resourceDict = device->makeResourceDict();
|
||||
|
||||
this->setData(device->content());
|
||||
|
||||
sk_sp<SkPDFArray> bboxArray(device->copyMediaBox());
|
||||
this->init(nullptr, resourceDict.get(), bboxArray.get());
|
||||
|
||||
// We invert the initial transform and apply that to the xobject so that
|
||||
// it doesn't get applied twice. We can't just undo it because it's
|
||||
// embedded in things like shaders and images.
|
||||
if (!device->initialTransform().isIdentity()) {
|
||||
SkMatrix inverse;
|
||||
if (!device->initialTransform().invert(&inverse)) {
|
||||
// The initial transform should be invertible.
|
||||
SkASSERT(false);
|
||||
inverse.reset();
|
||||
}
|
||||
this->insertObject("Matrix", SkPDFUtils::MatrixToArray(inverse));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a FormXObject from a content stream and associated resources.
|
||||
*/
|
||||
SkPDFFormXObject::SkPDFFormXObject(std::unique_ptr<SkStreamAsset> content,
|
||||
SkRect bbox,
|
||||
SkPDFDict* resourceDict) {
|
||||
this->setData(std::move(content));
|
||||
sk_sp<SkPDFArray> bboxArray(SkPDFUtils::RectToArray(bbox));
|
||||
this->init("DeviceRGB", resourceDict, bboxArray.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Common initialization code.
|
||||
* Note that bbox is unreferenced here, so calling code does not need worry.
|
||||
*/
|
||||
void SkPDFFormXObject::init(const char* colorSpace,
|
||||
SkPDFDict* resourceDict, SkPDFArray* bbox) {
|
||||
this->insertName("Type", "XObject");
|
||||
this->insertName("Subtype", "Form");
|
||||
this->insertObject("Resources", sk_ref_sp(resourceDict));
|
||||
this->insertObject("BBox", sk_ref_sp(bbox));
|
||||
|
||||
// Right now SkPDFFormXObject is only used for saveLayer, which implies
|
||||
// Right now FormXObject is only used for saveLayer, which implies
|
||||
// isolated blending. Do this conditionally if that changes.
|
||||
// TODO(halcanary): Is this comment obsolete, since we use it for
|
||||
// alpha masks?
|
||||
auto group = sk_make_sp<SkPDFDict>("Group");
|
||||
group->insertName("S", "Transparency");
|
||||
|
||||
if (colorSpace != nullptr) {
|
||||
group->insertName("CS", colorSpace);
|
||||
}
|
||||
group->insertBool("I", true); // Isolated.
|
||||
this->insertObject("Group", std::move(group));
|
||||
form->insertObject("Group", std::move(group));
|
||||
return form;
|
||||
}
|
||||
|
||||
SkPDFFormXObject::~SkPDFFormXObject() {}
|
||||
|
@ -10,41 +10,15 @@
|
||||
#define SkPDFFormXObject_DEFINED
|
||||
|
||||
#include "SkPDFStream.h"
|
||||
#include "SkPDFDevice.h"
|
||||
|
||||
class SkPDFArray;
|
||||
class SkPDFDevice;
|
||||
class SkPDFDict;
|
||||
struct SkRect;
|
||||
|
||||
/** \class SkPDFFormXObject
|
||||
|
||||
A form XObject; a self contained description of graphics objects. A form
|
||||
XObject is basically a page object with slightly different syntax, that
|
||||
can be drawn onto a page.
|
||||
/** A form XObject is a self contained description of a graphics
|
||||
object. A form XObject is a page object with slightly different
|
||||
syntax, that can be drawn into a page content stream, just like a
|
||||
bitmap XObject can be drawn into a page content stream.
|
||||
*/
|
||||
|
||||
// The caller could keep track of the form XObjects it creates and
|
||||
// canonicalize them, but the Skia API doesn't provide enough context to
|
||||
// automatically do it (trivially).
|
||||
class SkPDFFormXObject final : public SkPDFStream {
|
||||
public:
|
||||
/** Create a PDF form XObject. Entries for the dictionary entries are
|
||||
* automatically added.
|
||||
* @param device The set of graphical elements on this form.
|
||||
*/
|
||||
explicit SkPDFFormXObject(SkPDFDevice* device);
|
||||
/**
|
||||
* Create a PDF form XObject from a raw content stream and associated
|
||||
* resources.
|
||||
*/
|
||||
explicit SkPDFFormXObject(std::unique_ptr<SkStreamAsset> content,
|
||||
SkRect bbox,
|
||||
SkPDFDict* resourceDict);
|
||||
virtual ~SkPDFFormXObject();
|
||||
|
||||
private:
|
||||
void init(const char* colorSpace,
|
||||
SkPDFDict* resourceDict, SkPDFArray* bbox);
|
||||
};
|
||||
|
||||
sk_sp<SkPDFObject> SkPDFMakeFormXObject(std::unique_ptr<SkStreamAsset> content,
|
||||
sk_sp<SkPDFArray> mediaBox,
|
||||
sk_sp<SkPDFDict> resourceDict,
|
||||
const char* colorSpace);
|
||||
#endif
|
||||
|
@ -144,7 +144,7 @@ sk_sp<SkPDFStream> SkPDFGraphicState::MakeInvertFunction() {
|
||||
}
|
||||
|
||||
sk_sp<SkPDFDict> SkPDFGraphicState::GetSMaskGraphicState(
|
||||
SkPDFFormXObject* sMask,
|
||||
SkPDFObject* sMask,
|
||||
bool invert,
|
||||
SkPDFSMaskMode sMaskMode,
|
||||
SkPDFCanon* canon) {
|
||||
|
@ -14,7 +14,6 @@
|
||||
|
||||
class SkPaint;
|
||||
class SkPDFCanon;
|
||||
class SkPDFFormXObject;
|
||||
|
||||
/** \class SkPDFGraphicState
|
||||
SkPaint objects roughly correspond to graphic state dictionaries that can
|
||||
@ -52,7 +51,7 @@ public:
|
||||
*
|
||||
* These are not de-duped.
|
||||
*/
|
||||
static sk_sp<SkPDFDict> GetSMaskGraphicState(SkPDFFormXObject* sMask,
|
||||
static sk_sp<SkPDFDict> GetSMaskGraphicState(SkPDFObject* sMask,
|
||||
bool invert,
|
||||
SkPDFSMaskMode sMaskMode,
|
||||
SkPDFCanon* canon);
|
||||
|
@ -703,9 +703,10 @@ static sk_sp<SkPDFObject> create_smask_graphic_state(
|
||||
auto resources =
|
||||
get_gradient_resource_dict(luminosityShader.get(), nullptr);
|
||||
|
||||
sk_sp<SkPDFFormXObject> alphaMask(
|
||||
new SkPDFFormXObject(std::move(alphaStream), bbox, resources.get()));
|
||||
|
||||
auto alphaMask = SkPDFMakeFormXObject(std::move(alphaStream),
|
||||
SkPDFUtils::RectToArray(bbox),
|
||||
std::move(resources),
|
||||
"DeviceRGB");
|
||||
return SkPDFGraphicState::GetSMaskGraphicState(
|
||||
alphaMask.get(), false,
|
||||
SkPDFGraphicState::kLuminosity_SMaskMode, doc->canon());
|
||||
|
Loading…
Reference in New Issue
Block a user