SkPDF: PDFShader code modernized.
Motivation: reduce code complexity. SkCanon stores SkPDFShader::State next to SkDFObject, not inside. many places use sk_sp<T> rather than T* to represent ownership. SkPDFShader::State no longer holds bitmap. SkPDFShader::State gets move constructor, no longer heap-allocated. Classes removed: SkPDFFunctionShader SkPDFAlphaFunctionShader SkPDFImageShader BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2193973002 Review-Url: https://codereview.chromium.org/2193973002
This commit is contained in:
parent
62e1a1a4ba
commit
dabd4f0b79
@ -17,12 +17,13 @@ void SkPDFCanon::reset() {
|
||||
fFontRecords[i].fFont->unref();
|
||||
}
|
||||
fFontRecords.reset();
|
||||
fFunctionShaderRecords.unrefAll();
|
||||
|
||||
fFunctionShaderRecords.reset();
|
||||
fAlphaShaderRecords.unrefAll();
|
||||
fAlphaShaderRecords.reset();
|
||||
fImageShaderRecords.unrefAll();
|
||||
fImageShaderRecords.reset();
|
||||
|
||||
// TODO(halcanary): make SkTHashSet work nicely with sk_sp<>,
|
||||
// or use std::unordered_set<>
|
||||
fGraphicStateRecords.foreach ([](WrapGS w) { w.fPtr->unref(); });
|
||||
fGraphicStateRecords.reset();
|
||||
|
||||
@ -32,21 +33,6 @@ void SkPDFCanon::reset() {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class T> T* assert_ptr(T* p) { SkASSERT(p); return p; }
|
||||
|
||||
// requires `bool T::equals(const U&) const`
|
||||
template <typename T, typename U>
|
||||
T* find_item(const SkTDArray<T*>& ptrArray, const U& object) {
|
||||
for (int i = 0; i < ptrArray.count(); ++i) {
|
||||
if (ptrArray[i]->equals(object)) {
|
||||
return ptrArray[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkPDFFont* SkPDFCanon::findFont(uint32_t fontID,
|
||||
uint16_t glyphID,
|
||||
SkPDFFont** relatedFontPtr) const {
|
||||
@ -76,33 +62,43 @@ void SkPDFCanon::addFont(SkPDFFont* font, uint32_t fontID, uint16_t fGlyphID) {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkPDFFunctionShader* SkPDFCanon::findFunctionShader(
|
||||
template <typename T>
|
||||
sk_sp<SkPDFObject> find_shader(const SkTArray<T>& records,
|
||||
const SkPDFShader::State& state) {
|
||||
for (const T& record : records) {
|
||||
if (record.fShaderState == state) {
|
||||
return record.fShaderObject;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sk_sp<SkPDFObject> SkPDFCanon::findFunctionShader(
|
||||
const SkPDFShader::State& state) const {
|
||||
return find_item(fFunctionShaderRecords, state);
|
||||
return find_shader(fFunctionShaderRecords, state);
|
||||
}
|
||||
void SkPDFCanon::addFunctionShader(SkPDFFunctionShader* pdfShader) {
|
||||
fFunctionShaderRecords.push(SkRef(pdfShader));
|
||||
void SkPDFCanon::addFunctionShader(sk_sp<SkPDFObject> pdfShader,
|
||||
SkPDFShader::State state) {
|
||||
fFunctionShaderRecords.emplace_back(std::move(state), std::move(pdfShader));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkPDFAlphaFunctionShader* SkPDFCanon::findAlphaShader(
|
||||
sk_sp<SkPDFObject> SkPDFCanon::findAlphaShader(
|
||||
const SkPDFShader::State& state) const {
|
||||
return find_item(fAlphaShaderRecords, state);
|
||||
return find_shader(fAlphaShaderRecords, state);
|
||||
}
|
||||
void SkPDFCanon::addAlphaShader(SkPDFAlphaFunctionShader* pdfShader) {
|
||||
fAlphaShaderRecords.push(SkRef(pdfShader));
|
||||
void SkPDFCanon::addAlphaShader(sk_sp<SkPDFObject> pdfShader,
|
||||
SkPDFShader::State state) {
|
||||
fAlphaShaderRecords.emplace_back(std::move(state), std::move(pdfShader));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkPDFImageShader* SkPDFCanon::findImageShader(
|
||||
sk_sp<SkPDFObject> SkPDFCanon::findImageShader(
|
||||
const SkPDFShader::State& state) const {
|
||||
return find_item(fImageShaderRecords, state);
|
||||
return find_shader(fImageShaderRecords, state);
|
||||
}
|
||||
|
||||
void SkPDFCanon::addImageShader(SkPDFImageShader* pdfShader) {
|
||||
fImageShaderRecords.push(SkRef(pdfShader));
|
||||
void SkPDFCanon::addImageShader(sk_sp<SkPDFObject> pdfShader,
|
||||
SkPDFShader::State state) {
|
||||
fImageShaderRecords.emplace_back(std::move(state), std::move(pdfShader));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -48,14 +48,14 @@ public:
|
||||
SkPDFFont** relatedFont) const;
|
||||
void addFont(SkPDFFont* font, uint32_t fontID, uint16_t fGlyphID);
|
||||
|
||||
SkPDFFunctionShader* findFunctionShader(const SkPDFShader::State&) const;
|
||||
void addFunctionShader(SkPDFFunctionShader*);
|
||||
sk_sp<SkPDFObject> findFunctionShader(const SkPDFShader::State&) const;
|
||||
void addFunctionShader(sk_sp<SkPDFObject>, SkPDFShader::State);
|
||||
|
||||
SkPDFAlphaFunctionShader* findAlphaShader(const SkPDFShader::State&) const;
|
||||
void addAlphaShader(SkPDFAlphaFunctionShader*);
|
||||
sk_sp<SkPDFObject> findAlphaShader(const SkPDFShader::State&) const;
|
||||
void addAlphaShader(sk_sp<SkPDFObject>, SkPDFShader::State);
|
||||
|
||||
SkPDFImageShader* findImageShader(const SkPDFShader::State&) const;
|
||||
void addImageShader(SkPDFImageShader*);
|
||||
sk_sp<SkPDFObject> findImageShader(const SkPDFShader::State&) const;
|
||||
void addImageShader(sk_sp<SkPDFObject>, SkPDFShader::State);
|
||||
|
||||
const SkPDFGraphicState* findGraphicState(const SkPDFGraphicState&) const;
|
||||
void addGraphicState(const SkPDFGraphicState*);
|
||||
@ -82,11 +82,15 @@ private:
|
||||
};
|
||||
SkTDArray<FontRec> fFontRecords;
|
||||
|
||||
SkTDArray<SkPDFFunctionShader*> fFunctionShaderRecords;
|
||||
|
||||
SkTDArray<SkPDFAlphaFunctionShader*> fAlphaShaderRecords;
|
||||
|
||||
SkTDArray<SkPDFImageShader*> fImageShaderRecords;
|
||||
struct ShaderRec {
|
||||
SkPDFShader::State fShaderState;
|
||||
sk_sp<SkPDFObject> fShaderObject;
|
||||
ShaderRec(SkPDFShader::State s, sk_sp<SkPDFObject> o)
|
||||
: fShaderState(std::move(s)), fShaderObject(std::move(o)) {}
|
||||
};
|
||||
SkTArray<ShaderRec> fFunctionShaderRecords;
|
||||
SkTArray<ShaderRec> fAlphaShaderRecords;
|
||||
SkTArray<ShaderRec> fImageShaderRecords;
|
||||
|
||||
struct WrapGS {
|
||||
explicit WrapGS(const SkPDFGraphicState* ptr = nullptr) : fPtr(ptr) {}
|
||||
|
@ -564,9 +564,8 @@ public:
|
||||
if (shape->isEmpty()) {
|
||||
shape = nullptr;
|
||||
}
|
||||
fDevice->finishContentEntry(fXfermode, fDstFormXObject, shape);
|
||||
fDevice->finishContentEntry(fXfermode, std::move(fDstFormXObject), shape);
|
||||
}
|
||||
SkSafeUnref(fDstFormXObject);
|
||||
}
|
||||
|
||||
SkPDFDevice::ContentEntry* entry() { return fContentEntry; }
|
||||
@ -609,7 +608,7 @@ private:
|
||||
SkPDFDevice* fDevice;
|
||||
SkPDFDevice::ContentEntry* fContentEntry;
|
||||
SkXfermode::Mode fXfermode;
|
||||
SkPDFObject* fDstFormXObject;
|
||||
sk_sp<SkPDFObject> fDstFormXObject;
|
||||
SkPath fShape;
|
||||
|
||||
void init(const SkClipStack* clipStack, const SkRegion& clipRegion,
|
||||
@ -1606,7 +1605,7 @@ sk_sp<SkPDFObject> SkPDFDevice::makeFormXObjectFromDevice() {
|
||||
}
|
||||
|
||||
void SkPDFDevice::drawFormXObjectWithMask(int xObjectIndex,
|
||||
SkPDFObject* mask,
|
||||
sk_sp<SkPDFObject> mask,
|
||||
const SkClipStack* clipStack,
|
||||
const SkRegion& clipRegion,
|
||||
SkXfermode::Mode mode,
|
||||
@ -1616,7 +1615,8 @@ void SkPDFDevice::drawFormXObjectWithMask(int xObjectIndex,
|
||||
}
|
||||
|
||||
sk_sp<SkPDFDict> sMaskGS = SkPDFGraphicState::GetSMaskGraphicState(
|
||||
mask, invertClip, SkPDFGraphicState::kAlpha_SMaskMode, fDocument->canon());
|
||||
std::move(mask), invertClip,
|
||||
SkPDFGraphicState::kAlpha_SMaskMode, fDocument->canon());
|
||||
|
||||
SkMatrix identity;
|
||||
identity.reset();
|
||||
@ -1643,7 +1643,7 @@ SkPDFDevice::ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* cli
|
||||
const SkMatrix& matrix,
|
||||
const SkPaint& paint,
|
||||
bool hasText,
|
||||
SkPDFObject** dst) {
|
||||
sk_sp<SkPDFObject>* dst) {
|
||||
*dst = nullptr;
|
||||
if (clipRegion.isEmpty()) {
|
||||
return nullptr;
|
||||
@ -1684,8 +1684,7 @@ SkPDFDevice::ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* cli
|
||||
xfermode == SkXfermode::kDstATop_Mode ||
|
||||
xfermode == SkXfermode::kModulate_Mode) {
|
||||
if (!isContentEmpty()) {
|
||||
// TODO(halcanary): make this safer.
|
||||
*dst = this->makeFormXObjectFromDevice().release();
|
||||
*dst = this->makeFormXObjectFromDevice();
|
||||
SkASSERT(isContentEmpty());
|
||||
} else if (xfermode != SkXfermode::kSrc_Mode &&
|
||||
xfermode != SkXfermode::kSrcOut_Mode) {
|
||||
@ -1716,7 +1715,7 @@ SkPDFDevice::ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* cli
|
||||
}
|
||||
|
||||
void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode,
|
||||
SkPDFObject* dst,
|
||||
sk_sp<SkPDFObject> dst,
|
||||
SkPath* shape) {
|
||||
if (xfermode != SkXfermode::kClear_Mode &&
|
||||
xfermode != SkXfermode::kSrc_Mode &&
|
||||
@ -1773,7 +1772,8 @@ void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode,
|
||||
ScopedContentEntry content(this, &fExistingClipStack,
|
||||
fExistingClipRegion, identity,
|
||||
stockPaint);
|
||||
SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst),
|
||||
// TODO: addXObjectResource take sk_sp
|
||||
SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst.get()),
|
||||
&content.entry()->fContent);
|
||||
return;
|
||||
} else {
|
||||
@ -1795,8 +1795,6 @@ void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode,
|
||||
&fExistingClipStack, fExistingClipRegion,
|
||||
SkXfermode::kSrcOver_Mode, true);
|
||||
} else {
|
||||
sk_sp<SkPDFObject> dstMaskStorage;
|
||||
SkPDFObject* dstMask = srcFormXObject.get();
|
||||
if (shape != nullptr) {
|
||||
// Draw shape into a form-xobject.
|
||||
SkRasterClip rc(clipRegion);
|
||||
@ -1808,13 +1806,16 @@ void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode,
|
||||
filledPaint.setColor(SK_ColorBLACK);
|
||||
filledPaint.setStyle(SkPaint::kFill_Style);
|
||||
this->drawPath(d, *shape, filledPaint, nullptr, true);
|
||||
drawFormXObjectWithMask(addXObjectResource(dst.get()),
|
||||
this->makeFormXObjectFromDevice(),
|
||||
&fExistingClipStack, fExistingClipRegion,
|
||||
SkXfermode::kSrcOver_Mode, true);
|
||||
|
||||
dstMaskStorage = this->makeFormXObjectFromDevice();
|
||||
dstMask = dstMaskStorage.get();
|
||||
} else {
|
||||
drawFormXObjectWithMask(addXObjectResource(dst.get()), srcFormXObject,
|
||||
&fExistingClipStack, fExistingClipRegion,
|
||||
SkXfermode::kSrcOver_Mode, true);
|
||||
}
|
||||
drawFormXObjectWithMask(addXObjectResource(dst), dstMask,
|
||||
&fExistingClipStack, fExistingClipRegion,
|
||||
SkXfermode::kSrcOver_Mode, true);
|
||||
}
|
||||
|
||||
if (xfermode == SkXfermode::kClear_Mode) {
|
||||
@ -1835,7 +1836,7 @@ void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode,
|
||||
ScopedContentEntry content(this, &fExistingClipStack,
|
||||
fExistingClipRegion, identity, stockPaint);
|
||||
if (content.entry()) {
|
||||
SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst),
|
||||
SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst.get()),
|
||||
&content.entry()->fContent);
|
||||
}
|
||||
}
|
||||
@ -1851,22 +1852,26 @@ void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode,
|
||||
if (xfermode == SkXfermode::kSrcIn_Mode ||
|
||||
xfermode == SkXfermode::kSrcOut_Mode ||
|
||||
xfermode == SkXfermode::kSrcATop_Mode) {
|
||||
drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), dst,
|
||||
drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()),
|
||||
std::move(dst),
|
||||
&fExistingClipStack, fExistingClipRegion,
|
||||
SkXfermode::kSrcOver_Mode,
|
||||
xfermode == SkXfermode::kSrcOut_Mode);
|
||||
return;
|
||||
} else {
|
||||
SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode;
|
||||
int resourceID = addXObjectResource(dst.get());
|
||||
if (xfermode == SkXfermode::kModulate_Mode) {
|
||||
drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()),
|
||||
dst, &fExistingClipStack,
|
||||
std::move(dst), &fExistingClipStack,
|
||||
fExistingClipRegion,
|
||||
SkXfermode::kSrcOver_Mode, false);
|
||||
mode = SkXfermode::kMultiply_Mode;
|
||||
}
|
||||
drawFormXObjectWithMask(addXObjectResource(dst), srcFormXObject.get(),
|
||||
drawFormXObjectWithMask(resourceID, std::move(srcFormXObject),
|
||||
&fExistingClipStack, fExistingClipRegion, mode,
|
||||
xfermode == SkXfermode::kDstOut_Mode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1918,8 +1923,8 @@ void SkPDFDevice::populateGraphicStateEntryFromPaint(
|
||||
|
||||
SkScalar rasterScale =
|
||||
SkIntToScalar(fRasterDpi) / DPI_FOR_RASTER_SCALE_ONE;
|
||||
pdfShader.reset(SkPDFShader::GetPDFShader(
|
||||
fDocument, fRasterDpi, shader, transform, bounds, rasterScale));
|
||||
pdfShader = SkPDFShader::GetPDFShader(
|
||||
fDocument, fRasterDpi, shader, transform, bounds, rasterScale);
|
||||
|
||||
if (pdfShader.get()) {
|
||||
// pdfShader has been canonicalized so we can directly compare
|
||||
@ -1981,13 +1986,13 @@ int SkPDFDevice::addGraphicStateResource(SkPDFObject* gs) {
|
||||
}
|
||||
|
||||
int SkPDFDevice::addXObjectResource(SkPDFObject* xObject) {
|
||||
// TODO(halcanary): make this take a sk_sp<SkPDFObject>
|
||||
// Assumes that xobject has been canonicalized (so we can directly compare
|
||||
// pointers).
|
||||
int result = fXObjectResources.find(xObject);
|
||||
if (result < 0) {
|
||||
result = fXObjectResources.count();
|
||||
fXObjectResources.push(xObject);
|
||||
xObject->ref();
|
||||
fXObjectResources.push(SkRef(xObject));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -271,7 +271,7 @@ private:
|
||||
sk_sp<SkPDFObject> makeFormXObjectFromDevice();
|
||||
|
||||
void drawFormXObjectWithMask(int xObjectIndex,
|
||||
SkPDFObject* mask,
|
||||
sk_sp<SkPDFObject> mask,
|
||||
const SkClipStack* clipStack,
|
||||
const SkRegion& clipRegion,
|
||||
SkXfermode::Mode mode,
|
||||
@ -286,9 +286,9 @@ private:
|
||||
const SkMatrix& matrix,
|
||||
const SkPaint& paint,
|
||||
bool hasText,
|
||||
SkPDFObject** dst);
|
||||
sk_sp<SkPDFObject>* dst);
|
||||
void finishContentEntry(SkXfermode::Mode xfermode,
|
||||
SkPDFObject* dst,
|
||||
sk_sp<SkPDFObject> dst,
|
||||
SkPath* shape);
|
||||
bool isContentEmpty();
|
||||
|
||||
|
@ -144,7 +144,7 @@ sk_sp<SkPDFStream> SkPDFGraphicState::MakeInvertFunction() {
|
||||
}
|
||||
|
||||
sk_sp<SkPDFDict> SkPDFGraphicState::GetSMaskGraphicState(
|
||||
SkPDFObject* sMask,
|
||||
sk_sp<SkPDFObject> sMask,
|
||||
bool invert,
|
||||
SkPDFSMaskMode sMaskMode,
|
||||
SkPDFCanon* canon) {
|
||||
@ -156,7 +156,7 @@ sk_sp<SkPDFDict> SkPDFGraphicState::GetSMaskGraphicState(
|
||||
} else if (sMaskMode == kLuminosity_SMaskMode) {
|
||||
sMaskDict->insertName("S", "Luminosity");
|
||||
}
|
||||
sMaskDict->insertObjRef("G", sk_ref_sp(sMask));
|
||||
sMaskDict->insertObjRef("G", std::move(sMask));
|
||||
if (invert) {
|
||||
// Instead of calling SkPDFGraphicState::MakeInvertFunction,
|
||||
// let the canon deduplicate this object.
|
||||
|
@ -51,7 +51,7 @@ public:
|
||||
*
|
||||
* These are not de-duped.
|
||||
*/
|
||||
static sk_sp<SkPDFDict> GetSMaskGraphicState(SkPDFObject* sMask,
|
||||
static sk_sp<SkPDFDict> GetSMaskGraphicState(sk_sp<SkPDFObject> sMask,
|
||||
bool invert,
|
||||
SkPDFSMaskMode sMaskMode,
|
||||
SkPDFCanon* canon);
|
||||
|
@ -523,112 +523,65 @@ static void drawBitmapMatrix(SkCanvas* canvas, const SkBitmap& bm, const SkMatri
|
||||
canvas->drawBitmap(bm, 0, 0);
|
||||
}
|
||||
|
||||
class SkPDFShader::State {
|
||||
public:
|
||||
SkShader::GradientType fType;
|
||||
SkShader::GradientInfo fInfo;
|
||||
SkAutoFree fColorData; // This provides storage for arrays in fInfo.
|
||||
SkMatrix fCanvasTransform;
|
||||
SkMatrix fShaderTransform;
|
||||
SkIRect fBBox;
|
||||
|
||||
SkBitmap fImage;
|
||||
SkBitmapKey fBitmapKey;
|
||||
SkShader::TileMode fImageTileModes[2];
|
||||
|
||||
State(SkShader* shader, const SkMatrix& canvasTransform,
|
||||
const SkIRect& bbox, SkScalar rasterScale);
|
||||
|
||||
bool operator==(const State& b) const;
|
||||
|
||||
SkPDFShader::State* CreateAlphaToLuminosityState() const;
|
||||
SkPDFShader::State* CreateOpaqueState() const;
|
||||
|
||||
bool GradientHasAlpha() const;
|
||||
|
||||
private:
|
||||
State(const State& other);
|
||||
State operator=(const State& rhs);
|
||||
void AllocateGradientInfoStorage();
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state)
|
||||
: SkPDFDict("Pattern"), fShaderState(state) {
|
||||
state->fImage.reset();
|
||||
}
|
||||
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);
|
||||
|
||||
SkPDFFunctionShader::~SkPDFFunctionShader() {}
|
||||
static sk_sp<SkPDFStream> make_image_shader(SkPDFDocument* doc,
|
||||
SkScalar dpi,
|
||||
const SkPDFShader::State& state,
|
||||
SkBitmap image);
|
||||
|
||||
bool SkPDFFunctionShader::equals(const SkPDFShader::State& state) const {
|
||||
return state == *fShaderState;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkPDFAlphaFunctionShader::SkPDFAlphaFunctionShader(SkPDFShader::State* state)
|
||||
: fShaderState(state) {
|
||||
state->fImage.reset();
|
||||
}
|
||||
|
||||
bool SkPDFAlphaFunctionShader::equals(const SkPDFShader::State& state) const {
|
||||
return state == *fShaderState;
|
||||
}
|
||||
|
||||
SkPDFAlphaFunctionShader::~SkPDFAlphaFunctionShader() {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state)
|
||||
: fShaderState(state) {
|
||||
state->fImage.reset();
|
||||
}
|
||||
|
||||
bool SkPDFImageShader::equals(const SkPDFShader::State& state) const {
|
||||
return state == *fShaderState;
|
||||
}
|
||||
|
||||
SkPDFImageShader::~SkPDFImageShader() {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static SkPDFObject* get_pdf_shader_by_state(
|
||||
static sk_sp<SkPDFObject> get_pdf_shader_by_state(
|
||||
SkPDFDocument* doc,
|
||||
SkScalar dpi,
|
||||
std::unique_ptr<SkPDFShader::State>* autoState) {
|
||||
const SkPDFShader::State& state = **autoState;
|
||||
SkPDFShader::State state,
|
||||
SkBitmap image) {
|
||||
SkPDFCanon* canon = doc->canon();
|
||||
if (state.fType == SkShader::kNone_GradientType && state.fImage.isNull()) {
|
||||
if (state.fType == SkShader::kNone_GradientType && image.isNull()) {
|
||||
// TODO(vandebo) This drops SKComposeShader on the floor. We could
|
||||
// handle compose shader by pulling things up to a layer, drawing with
|
||||
// the first shader, applying the xfer mode and drawing again with the
|
||||
// second shader, then applying the layer to the original drawing.
|
||||
return nullptr;
|
||||
} else if (state.fType == SkShader::kNone_GradientType) {
|
||||
SkPDFObject* shader = canon->findImageShader(state);
|
||||
return shader ? SkRef(shader)
|
||||
: SkPDFImageShader::Create(doc, dpi, autoState);
|
||||
sk_sp<SkPDFObject> shader = canon->findImageShader(state);
|
||||
if (!shader) {
|
||||
shader = make_image_shader(doc, dpi, state, std::move(image));
|
||||
canon->addImageShader(shader, std::move(state));
|
||||
}
|
||||
return shader;
|
||||
} else if (state.GradientHasAlpha()) {
|
||||
SkPDFObject* shader = canon->findAlphaShader(state);
|
||||
return shader ? SkRef(shader)
|
||||
: SkPDFAlphaFunctionShader::Create(doc, dpi, autoState);
|
||||
sk_sp<SkPDFObject> shader = canon->findAlphaShader(state);
|
||||
if (!shader) {
|
||||
shader = make_alpha_function_shader(doc, dpi, state);
|
||||
canon->addAlphaShader(shader, std::move(state));
|
||||
}
|
||||
return shader;
|
||||
} else {
|
||||
SkPDFObject* shader = canon->findFunctionShader(state);
|
||||
return shader ? SkRef(shader)
|
||||
: SkPDFFunctionShader::Create(canon, autoState);
|
||||
sk_sp<SkPDFObject> shader = canon->findFunctionShader(state);
|
||||
if (!shader) {
|
||||
shader = make_function_shader(canon, state);
|
||||
canon->addFunctionShader(shader, std::move(state));
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
SkPDFObject* SkPDFShader::GetPDFShader(SkPDFDocument* doc,
|
||||
SkScalar dpi,
|
||||
SkShader* shader,
|
||||
const SkMatrix& matrix,
|
||||
const SkIRect& surfaceBBox,
|
||||
SkScalar rasterScale) {
|
||||
std::unique_ptr<SkPDFShader::State> state(new State(shader, matrix, surfaceBBox, rasterScale));
|
||||
return get_pdf_shader_by_state(doc, dpi, &state);
|
||||
sk_sp<SkPDFObject> SkPDFShader::GetPDFShader(SkPDFDocument* doc,
|
||||
SkScalar dpi,
|
||||
SkShader* shader,
|
||||
const SkMatrix& matrix,
|
||||
const SkIRect& surfaceBBox,
|
||||
SkScalar rasterScale) {
|
||||
SkBitmap image;
|
||||
State state(shader, matrix, surfaceBBox, rasterScale, &image);
|
||||
return get_pdf_shader_by_state(
|
||||
doc, dpi, std::move(state), std::move(image));
|
||||
}
|
||||
|
||||
static sk_sp<SkPDFDict> get_gradient_resource_dict(
|
||||
@ -647,7 +600,7 @@ static sk_sp<SkPDFDict> get_gradient_resource_dict(
|
||||
|
||||
static void populate_tiling_pattern_dict(SkPDFDict* pattern,
|
||||
SkRect& bbox,
|
||||
SkPDFDict* resources,
|
||||
sk_sp<SkPDFDict> resources,
|
||||
const SkMatrix& matrix) {
|
||||
const int kTiling_PatternType = 1;
|
||||
const int kColoredTilingPattern_PaintType = 1;
|
||||
@ -660,7 +613,7 @@ static void populate_tiling_pattern_dict(SkPDFDict* pattern,
|
||||
pattern->insertObject("BBox", SkPDFUtils::RectToArray(bbox));
|
||||
pattern->insertScalar("XStep", bbox.width());
|
||||
pattern->insertScalar("YStep", bbox.height());
|
||||
pattern->insertObject("Resources", sk_ref_sp(resources));
|
||||
pattern->insertObject("Resources", std::move(resources));
|
||||
if (!matrix.isIdentity()) {
|
||||
pattern->insertObject("Matrix", SkPDFUtils::MatrixToArray(matrix));
|
||||
}
|
||||
@ -671,7 +624,8 @@ static void populate_tiling_pattern_dict(SkPDFDict* pattern,
|
||||
* @param gsIndex A graphics state resource index to apply, or <0 if no
|
||||
* graphics state to apply.
|
||||
*/
|
||||
static SkStreamAsset* create_pattern_fill_content(int gsIndex, SkRect& bounds) {
|
||||
static std::unique_ptr<SkStreamAsset> create_pattern_fill_content(
|
||||
int gsIndex, SkRect& bounds) {
|
||||
SkDynamicMemoryWStream content;
|
||||
if (gsIndex >= 0) {
|
||||
SkPDFUtils::ApplyGraphicState(gsIndex, &content);
|
||||
@ -681,7 +635,7 @@ static SkStreamAsset* create_pattern_fill_content(int gsIndex, SkRect& bounds) {
|
||||
SkPDFUtils::PaintPath(SkPaint::kFill_Style, SkPath::kEvenOdd_FillType,
|
||||
&content);
|
||||
|
||||
return content.detachAsStream();
|
||||
return std::unique_ptr<SkStreamAsset>(content.detachAsStream());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -693,10 +647,9 @@ static sk_sp<SkPDFObject> create_smask_graphic_state(
|
||||
SkRect bbox;
|
||||
bbox.set(state.fBBox);
|
||||
|
||||
std::unique_ptr<SkPDFShader::State> alphaToLuminosityState(
|
||||
state.CreateAlphaToLuminosityState());
|
||||
sk_sp<SkPDFObject> luminosityShader(
|
||||
get_pdf_shader_by_state(doc, dpi, &alphaToLuminosityState));
|
||||
get_pdf_shader_by_state(doc, dpi, state.MakeAlphaToLuminosityState(),
|
||||
SkBitmap()));
|
||||
|
||||
std::unique_ptr<SkStreamAsset> alphaStream(create_pattern_fill_content(-1, bbox));
|
||||
|
||||
@ -709,22 +662,20 @@ static sk_sp<SkPDFObject> create_smask_graphic_state(
|
||||
SkMatrix::I(),
|
||||
"DeviceRGB");
|
||||
return SkPDFGraphicState::GetSMaskGraphicState(
|
||||
alphaMask.get(), false,
|
||||
std::move(alphaMask), false,
|
||||
SkPDFGraphicState::kLuminosity_SMaskMode, doc->canon());
|
||||
}
|
||||
|
||||
SkPDFAlphaFunctionShader* SkPDFAlphaFunctionShader::Create(
|
||||
SkPDFDocument* doc,
|
||||
SkScalar dpi,
|
||||
std::unique_ptr<SkPDFShader::State>* autoState) {
|
||||
const SkPDFShader::State& state = **autoState;
|
||||
static sk_sp<SkPDFStream> make_alpha_function_shader(SkPDFDocument* doc,
|
||||
SkScalar dpi,
|
||||
const SkPDFShader::State& state) {
|
||||
SkRect bbox;
|
||||
bbox.set(state.fBBox);
|
||||
|
||||
std::unique_ptr<SkPDFShader::State> opaqueState(state.CreateOpaqueState());
|
||||
SkPDFShader::State opaqueState(state.MakeOpaqueState());
|
||||
|
||||
sk_sp<SkPDFObject> colorShader(
|
||||
get_pdf_shader_by_state(doc, dpi, &opaqueState));
|
||||
get_pdf_shader_by_state(doc, dpi, std::move(opaqueState), SkBitmap()));
|
||||
if (!colorShader) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -733,20 +684,15 @@ SkPDFAlphaFunctionShader* SkPDFAlphaFunctionShader::Create(
|
||||
// pattern shader as P0, then write content stream.
|
||||
auto alphaGs = create_smask_graphic_state(doc, dpi, state);
|
||||
|
||||
SkPDFAlphaFunctionShader* alphaFunctionShader =
|
||||
new SkPDFAlphaFunctionShader(autoState->release());
|
||||
|
||||
auto resourceDict =
|
||||
get_gradient_resource_dict(colorShader.get(), alphaGs.get());
|
||||
|
||||
std::unique_ptr<SkStreamAsset> colorStream(
|
||||
create_pattern_fill_content(0, bbox));
|
||||
alphaFunctionShader->setData(std::move(colorStream));
|
||||
auto alphaFunctionShader = sk_make_sp<SkPDFStream>(std::move(colorStream));
|
||||
|
||||
populate_tiling_pattern_dict(
|
||||
alphaFunctionShader->dict(), bbox, resourceDict.get(),
|
||||
SkMatrix::I());
|
||||
doc->canon()->addAlphaShader(alphaFunctionShader);
|
||||
populate_tiling_pattern_dict(alphaFunctionShader->dict(), bbox,
|
||||
std::move(resourceDict), SkMatrix::I());
|
||||
return alphaFunctionShader;
|
||||
}
|
||||
|
||||
@ -802,11 +748,11 @@ sk_sp<SkPDFArray> SkPDFShader::MakeRangeObject() {
|
||||
|
||||
static sk_sp<SkPDFStream> make_ps_function(
|
||||
std::unique_ptr<SkStreamAsset> psCode,
|
||||
SkPDFArray* domain,
|
||||
sk_sp<SkPDFArray> domain,
|
||||
sk_sp<SkPDFObject> range) {
|
||||
auto result = sk_make_sp<SkPDFStream>(std::move(psCode));
|
||||
result->dict()->insertInt("FunctionType", 4);
|
||||
result->dict()->insertObject("Domain", sk_ref_sp(domain));
|
||||
result->dict()->insertObject("Domain", std::move(domain));
|
||||
result->dict()->insertObject("Range", std::move(range));
|
||||
return result;
|
||||
}
|
||||
@ -826,10 +772,8 @@ static void FixUpRadius(const SkPoint& p1, SkScalar& r1, const SkPoint& p2, SkSc
|
||||
}
|
||||
}
|
||||
|
||||
SkPDFFunctionShader* SkPDFFunctionShader::Create(
|
||||
SkPDFCanon* canon, std::unique_ptr<SkPDFShader::State>* autoState) {
|
||||
const SkPDFShader::State& state = **autoState;
|
||||
|
||||
static sk_sp<SkPDFDict> make_function_shader(SkPDFCanon* canon,
|
||||
const SkPDFShader::State& state) {
|
||||
void (*codeFunction)(const SkShader::GradientInfo& info,
|
||||
const SkMatrix& perspectiveRemover,
|
||||
SkDynamicMemoryWStream* function) = nullptr;
|
||||
@ -839,10 +783,10 @@ SkPDFFunctionShader* SkPDFFunctionShader::Create(
|
||||
finalMatrix.preConcat(state.fShaderTransform);
|
||||
|
||||
bool doStitchFunctions = (state.fType == SkShader::kLinear_GradientType ||
|
||||
state.fType == SkShader::kRadial_GradientType ||
|
||||
state.fType == SkShader::kConical_GradientType) &&
|
||||
info->fTileMode == SkShader::kClamp_TileMode &&
|
||||
!finalMatrix.hasPerspective();
|
||||
state.fType == SkShader::kRadial_GradientType ||
|
||||
state.fType == SkShader::kConical_GradientType) &&
|
||||
info->fTileMode == SkShader::kClamp_TileMode &&
|
||||
!finalMatrix.hasPerspective();
|
||||
|
||||
auto domain = sk_make_sp<SkPDFArray>();
|
||||
|
||||
@ -984,39 +928,37 @@ SkPDFFunctionShader* SkPDFFunctionShader::Create(
|
||||
codeFunction(*info, perspectiveInverseOnly, &functionCode);
|
||||
}
|
||||
|
||||
pdfShader->insertObject("Domain", sk_ref_sp(domain.get()));
|
||||
pdfShader->insertObject("Domain", domain);
|
||||
|
||||
// Call canon->makeRangeObject() instead of
|
||||
// SkPDFShader::MakeRangeObject() so that the canon can
|
||||
// deduplicate.
|
||||
std::unique_ptr<SkStreamAsset> functionStream(
|
||||
functionCode.detachAsStream());
|
||||
auto function = make_ps_function(std::move(functionStream), domain.get(),
|
||||
canon->makeRangeObject());
|
||||
sk_sp<SkPDFStream> function = make_ps_function(std::move(functionStream),
|
||||
std::move(domain),
|
||||
canon->makeRangeObject());
|
||||
pdfShader->insertObjRef("Function", std::move(function));
|
||||
}
|
||||
|
||||
pdfShader->insertInt("ShadingType", shadingType);
|
||||
pdfShader->insertName("ColorSpace", "DeviceRGB");
|
||||
|
||||
sk_sp<SkPDFFunctionShader> pdfFunctionShader(
|
||||
new SkPDFFunctionShader(autoState->release()));
|
||||
auto pdfFunctionShader = sk_make_sp<SkPDFDict>("Pattern");
|
||||
pdfFunctionShader->insertInt("PatternType", 2);
|
||||
pdfFunctionShader->insertObject("Matrix",
|
||||
SkPDFUtils::MatrixToArray(finalMatrix));
|
||||
pdfFunctionShader->insertObject("Shading", std::move(pdfShader));
|
||||
|
||||
canon->addFunctionShader(pdfFunctionShader.get());
|
||||
return pdfFunctionShader.release();
|
||||
return pdfFunctionShader;
|
||||
}
|
||||
|
||||
SkPDFImageShader* SkPDFImageShader::Create(
|
||||
SkPDFDocument* doc,
|
||||
SkScalar dpi,
|
||||
std::unique_ptr<SkPDFShader::State>* autoState) {
|
||||
const SkPDFShader::State& state = **autoState;
|
||||
|
||||
state.fImage.lockPixels();
|
||||
static sk_sp<SkPDFStream> make_image_shader(SkPDFDocument* doc,
|
||||
SkScalar dpi,
|
||||
const SkPDFShader::State& state,
|
||||
SkBitmap image) {
|
||||
SkASSERT(state.fBitmapKey == SkBitmapKey(image));
|
||||
SkAutoLockPixels SkAutoLockPixels(image);
|
||||
|
||||
// The image shader pattern cell will be drawn into a separate device
|
||||
// in pattern cell space (no scaling on the bitmap, though there may be
|
||||
@ -1032,9 +974,8 @@ SkPDFImageShader* SkPDFImageShader::Create(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const SkBitmap* image = &state.fImage;
|
||||
SkRect bitmapBounds;
|
||||
image->getBounds(&bitmapBounds);
|
||||
image.getBounds(&bitmapBounds);
|
||||
|
||||
// For tiling modes, the bounds should be extended to include the bitmap,
|
||||
// otherwise the bitmap gets clipped out and the shader is empty and awful.
|
||||
@ -1055,7 +996,7 @@ SkPDFImageShader* SkPDFImageShader::Create(
|
||||
SkCanvas canvas(patternDevice.get());
|
||||
|
||||
SkRect patternBBox;
|
||||
image->getBounds(&patternBBox);
|
||||
image.getBounds(&patternBBox);
|
||||
|
||||
// Translate the canvas so that the bitmap origin is at (0, 0).
|
||||
canvas.translate(-deviceBounds.left(), -deviceBounds.top());
|
||||
@ -1066,24 +1007,24 @@ SkPDFImageShader* SkPDFImageShader::Create(
|
||||
// If the bitmap is out of bounds (i.e. clamp mode where we only see the
|
||||
// stretched sides), canvas will clip this out and the extraneous data
|
||||
// won't be saved to the PDF.
|
||||
canvas.drawBitmap(*image, 0, 0);
|
||||
canvas.drawBitmap(image, 0, 0);
|
||||
|
||||
SkScalar width = SkIntToScalar(image->width());
|
||||
SkScalar height = SkIntToScalar(image->height());
|
||||
SkScalar width = SkIntToScalar(image.width());
|
||||
SkScalar height = SkIntToScalar(image.height());
|
||||
|
||||
// Tiling is implied. First we handle mirroring.
|
||||
if (tileModes[0] == SkShader::kMirror_TileMode) {
|
||||
SkMatrix xMirror;
|
||||
xMirror.setScale(-1, 1);
|
||||
xMirror.postTranslate(2 * width, 0);
|
||||
drawBitmapMatrix(&canvas, *image, xMirror);
|
||||
drawBitmapMatrix(&canvas, image, xMirror);
|
||||
patternBBox.fRight += width;
|
||||
}
|
||||
if (tileModes[1] == SkShader::kMirror_TileMode) {
|
||||
SkMatrix yMirror;
|
||||
yMirror.setScale(SK_Scalar1, -SK_Scalar1);
|
||||
yMirror.postTranslate(0, 2 * height);
|
||||
drawBitmapMatrix(&canvas, *image, yMirror);
|
||||
drawBitmapMatrix(&canvas, image, yMirror);
|
||||
patternBBox.fBottom += height;
|
||||
}
|
||||
if (tileModes[0] == SkShader::kMirror_TileMode &&
|
||||
@ -1091,7 +1032,7 @@ SkPDFImageShader* SkPDFImageShader::Create(
|
||||
SkMatrix mirror;
|
||||
mirror.setScale(-1, -1);
|
||||
mirror.postTranslate(2 * width, 2 * height);
|
||||
drawBitmapMatrix(&canvas, *image, mirror);
|
||||
drawBitmapMatrix(&canvas, image, mirror);
|
||||
}
|
||||
|
||||
// Then handle Clamping, which requires expanding the pattern canvas to
|
||||
@ -1105,39 +1046,39 @@ SkPDFImageShader* SkPDFImageShader::Create(
|
||||
SkRect rect;
|
||||
rect = SkRect::MakeLTRB(deviceBounds.left(), deviceBounds.top(), 0, 0);
|
||||
if (!rect.isEmpty()) {
|
||||
paint.setColor(image->getColor(0, 0));
|
||||
paint.setColor(image.getColor(0, 0));
|
||||
canvas.drawRect(rect, paint);
|
||||
}
|
||||
|
||||
rect = SkRect::MakeLTRB(width, deviceBounds.top(),
|
||||
deviceBounds.right(), 0);
|
||||
if (!rect.isEmpty()) {
|
||||
paint.setColor(image->getColor(image->width() - 1, 0));
|
||||
paint.setColor(image.getColor(image.width() - 1, 0));
|
||||
canvas.drawRect(rect, paint);
|
||||
}
|
||||
|
||||
rect = SkRect::MakeLTRB(width, height,
|
||||
deviceBounds.right(), deviceBounds.bottom());
|
||||
if (!rect.isEmpty()) {
|
||||
paint.setColor(image->getColor(image->width() - 1,
|
||||
image->height() - 1));
|
||||
paint.setColor(image.getColor(image.width() - 1,
|
||||
image.height() - 1));
|
||||
canvas.drawRect(rect, paint);
|
||||
}
|
||||
|
||||
rect = SkRect::MakeLTRB(deviceBounds.left(), height,
|
||||
0, deviceBounds.bottom());
|
||||
if (!rect.isEmpty()) {
|
||||
paint.setColor(image->getColor(0, image->height() - 1));
|
||||
paint.setColor(image.getColor(0, image.height() - 1));
|
||||
canvas.drawRect(rect, paint);
|
||||
}
|
||||
}
|
||||
|
||||
// Then expand the left, right, top, then bottom.
|
||||
if (tileModes[0] == SkShader::kClamp_TileMode) {
|
||||
SkIRect subset = SkIRect::MakeXYWH(0, 0, 1, image->height());
|
||||
SkIRect subset = SkIRect::MakeXYWH(0, 0, 1, image.height());
|
||||
if (deviceBounds.left() < 0) {
|
||||
SkBitmap left;
|
||||
SkAssertResult(image->extractSubset(&left, subset));
|
||||
SkAssertResult(image.extractSubset(&left, subset));
|
||||
|
||||
SkMatrix leftMatrix;
|
||||
leftMatrix.setScale(-deviceBounds.left(), 1);
|
||||
@ -1154,8 +1095,8 @@ SkPDFImageShader* SkPDFImageShader::Create(
|
||||
|
||||
if (deviceBounds.right() > width) {
|
||||
SkBitmap right;
|
||||
subset.offset(image->width() - 1, 0);
|
||||
SkAssertResult(image->extractSubset(&right, subset));
|
||||
subset.offset(image.width() - 1, 0);
|
||||
SkAssertResult(image.extractSubset(&right, subset));
|
||||
|
||||
SkMatrix rightMatrix;
|
||||
rightMatrix.setScale(deviceBounds.right() - width, 1);
|
||||
@ -1172,10 +1113,10 @@ SkPDFImageShader* SkPDFImageShader::Create(
|
||||
}
|
||||
|
||||
if (tileModes[1] == SkShader::kClamp_TileMode) {
|
||||
SkIRect subset = SkIRect::MakeXYWH(0, 0, image->width(), 1);
|
||||
SkIRect subset = SkIRect::MakeXYWH(0, 0, image.width(), 1);
|
||||
if (deviceBounds.top() < 0) {
|
||||
SkBitmap top;
|
||||
SkAssertResult(image->extractSubset(&top, subset));
|
||||
SkAssertResult(image.extractSubset(&top, subset));
|
||||
|
||||
SkMatrix topMatrix;
|
||||
topMatrix.setScale(SK_Scalar1, -deviceBounds.top());
|
||||
@ -1192,8 +1133,8 @@ SkPDFImageShader* SkPDFImageShader::Create(
|
||||
|
||||
if (deviceBounds.bottom() > height) {
|
||||
SkBitmap bottom;
|
||||
subset.offset(0, image->height() - 1);
|
||||
SkAssertResult(image->extractSubset(&bottom, subset));
|
||||
subset.offset(0, image.height() - 1);
|
||||
SkAssertResult(image.extractSubset(&bottom, subset));
|
||||
|
||||
SkMatrix bottomMatrix;
|
||||
bottomMatrix.setScale(SK_Scalar1, deviceBounds.bottom() - height);
|
||||
@ -1209,17 +1150,9 @@ SkPDFImageShader* SkPDFImageShader::Create(
|
||||
}
|
||||
}
|
||||
|
||||
// Put the canvas into the pattern stream (fContent).
|
||||
SkPDFImageShader* imageShader = new SkPDFImageShader(autoState->release());
|
||||
imageShader->setData(patternDevice->content());
|
||||
|
||||
auto resourceDict = patternDevice->makeResourceDict();
|
||||
auto imageShader = sk_make_sp<SkPDFStream>(patternDevice->content());
|
||||
populate_tiling_pattern_dict(imageShader->dict(), patternBBox,
|
||||
resourceDict.get(), finalMatrix);
|
||||
|
||||
imageShader->fShaderState->fImage.unlockPixels();
|
||||
|
||||
doc->canon()->addImageShader(imageShader);
|
||||
patternDevice->makeResourceDict(), finalMatrix);
|
||||
return imageShader;
|
||||
}
|
||||
|
||||
@ -1277,9 +1210,11 @@ bool SkPDFShader::State::operator==(const SkPDFShader::State& b) const {
|
||||
}
|
||||
|
||||
SkPDFShader::State::State(SkShader* shader, const SkMatrix& canvasTransform,
|
||||
const SkIRect& bbox, SkScalar rasterScale)
|
||||
const SkIRect& bbox, SkScalar rasterScale,
|
||||
SkBitmap* imageDst)
|
||||
: fCanvasTransform(canvasTransform),
|
||||
fBBox(bbox) {
|
||||
SkASSERT(imageDst);
|
||||
fInfo.fColorCount = 0;
|
||||
fInfo.fColors = nullptr;
|
||||
fInfo.fColorOffsets = nullptr;
|
||||
@ -1289,18 +1224,19 @@ SkPDFShader::State::State(SkShader* shader, const SkMatrix& canvasTransform,
|
||||
fType = shader->asAGradient(&fInfo);
|
||||
|
||||
if (fType == SkShader::kNone_GradientType) {
|
||||
if (!shader->isABitmap(&fImage, nullptr, fImageTileModes)) {
|
||||
if (!shader->isABitmap(imageDst, nullptr, fImageTileModes)) {
|
||||
// Generic fallback for unsupported shaders:
|
||||
// * allocate a bbox-sized bitmap
|
||||
// * shade the whole area
|
||||
// * use the result as a bitmap shader
|
||||
|
||||
// bbox is in device space. While that's exactly what we want for sizing our bitmap,
|
||||
// we need to map it into shader space for adjustments (to match
|
||||
// SkPDFImageShader::Create's behavior).
|
||||
// bbox is in device space. While that's exactly what we
|
||||
// want for sizing our bitmap, we need to map it into
|
||||
// shader space for adjustments (to match
|
||||
// MakeImageShader's behavior).
|
||||
SkRect shaderRect = SkRect::Make(bbox);
|
||||
if (!inverse_transform_bbox(canvasTransform, &shaderRect)) {
|
||||
fImage.reset();
|
||||
imageDst->reset();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1316,13 +1252,13 @@ SkPDFShader::State::State(SkShader* shader, const SkMatrix& canvasTransform,
|
||||
SkSize scale = SkSize::Make(SkIntToScalar(size.width()) / shaderRect.width(),
|
||||
SkIntToScalar(size.height()) / shaderRect.height());
|
||||
|
||||
fImage.allocN32Pixels(size.width(), size.height());
|
||||
fImage.eraseColor(SK_ColorTRANSPARENT);
|
||||
imageDst->allocN32Pixels(size.width(), size.height());
|
||||
imageDst->eraseColor(SK_ColorTRANSPARENT);
|
||||
|
||||
SkPaint p;
|
||||
p.setShader(sk_ref_sp(shader));
|
||||
|
||||
SkCanvas canvas(fImage);
|
||||
SkCanvas canvas(*imageDst);
|
||||
canvas.scale(scale.width(), scale.height());
|
||||
canvas.translate(-shaderRect.x(), -shaderRect.y());
|
||||
canvas.drawPaint(p);
|
||||
@ -1330,9 +1266,9 @@ SkPDFShader::State::State(SkShader* shader, const SkMatrix& canvasTransform,
|
||||
fShaderTransform.setTranslate(shaderRect.x(), shaderRect.y());
|
||||
fShaderTransform.preScale(1 / scale.width(), 1 / scale.height());
|
||||
}
|
||||
fBitmapKey = SkBitmapKey(fImage);
|
||||
fBitmapKey = SkBitmapKey(*imageDst);
|
||||
} else {
|
||||
AllocateGradientInfoStorage();
|
||||
this->allocateGradientInfoStorage();
|
||||
shader->asAGradient(&fInfo);
|
||||
}
|
||||
}
|
||||
@ -1350,7 +1286,7 @@ SkPDFShader::State::State(const SkPDFShader::State& other)
|
||||
if (fType != SkShader::kNone_GradientType) {
|
||||
fInfo = other.fInfo;
|
||||
|
||||
AllocateGradientInfoStorage();
|
||||
this->allocateGradientInfoStorage();
|
||||
for (int i = 0; i < fInfo.fColorCount; i++) {
|
||||
fInfo.fColors[i] = other.fInfo.fColors[i];
|
||||
fInfo.fColorOffsets[i] = other.fInfo.fColorOffsets[i];
|
||||
@ -1362,14 +1298,15 @@ SkPDFShader::State::State(const SkPDFShader::State& other)
|
||||
* Create a copy of this gradient state with alpha assigned to RGB luminousity.
|
||||
* Only valid for gradient states.
|
||||
*/
|
||||
SkPDFShader::State* SkPDFShader::State::CreateAlphaToLuminosityState() const {
|
||||
SkPDFShader::State SkPDFShader::State::MakeAlphaToLuminosityState() const {
|
||||
SkASSERT(fBitmapKey == SkBitmapKey());
|
||||
SkASSERT(fType != SkShader::kNone_GradientType);
|
||||
|
||||
SkPDFShader::State* newState = new SkPDFShader::State(*this);
|
||||
SkPDFShader::State newState(*this);
|
||||
|
||||
for (int i = 0; i < fInfo.fColorCount; i++) {
|
||||
SkAlpha alpha = SkColorGetA(fInfo.fColors[i]);
|
||||
newState->fInfo.fColors[i] = SkColorSetARGB(255, alpha, alpha, alpha);
|
||||
newState.fInfo.fColors[i] = SkColorSetARGB(255, alpha, alpha, alpha);
|
||||
}
|
||||
|
||||
return newState;
|
||||
@ -1379,12 +1316,13 @@ SkPDFShader::State* SkPDFShader::State::CreateAlphaToLuminosityState() const {
|
||||
* Create a copy of this gradient state with alpha set to fully opaque
|
||||
* Only valid for gradient states.
|
||||
*/
|
||||
SkPDFShader::State* SkPDFShader::State::CreateOpaqueState() const {
|
||||
SkPDFShader::State SkPDFShader::State::MakeOpaqueState() const {
|
||||
SkASSERT(fBitmapKey == SkBitmapKey());
|
||||
SkASSERT(fType != SkShader::kNone_GradientType);
|
||||
|
||||
SkPDFShader::State* newState = new SkPDFShader::State(*this);
|
||||
SkPDFShader::State newState(*this);
|
||||
for (int i = 0; i < fInfo.fColorCount; i++) {
|
||||
newState->fInfo.fColors[i] = SkColorSetA(fInfo.fColors[i],
|
||||
newState.fInfo.fColors[i] = SkColorSetA(fInfo.fColors[i],
|
||||
SK_AlphaOPAQUE);
|
||||
}
|
||||
|
||||
@ -1408,10 +1346,9 @@ bool SkPDFShader::State::GradientHasAlpha() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void SkPDFShader::State::AllocateGradientInfoStorage() {
|
||||
fColorData.set(sk_malloc_throw(
|
||||
fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar))));
|
||||
fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get());
|
||||
fInfo.fColorOffsets =
|
||||
reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount);
|
||||
void SkPDFShader::State::allocateGradientInfoStorage() {
|
||||
fColors.reset(new SkColor[fInfo.fColorCount]);
|
||||
fStops.reset(new SkScalar[fInfo.fColorCount]);
|
||||
fInfo.fColors = fColors.get();
|
||||
fInfo.fColorOffsets = fStops.get();
|
||||
}
|
||||
|
@ -9,12 +9,13 @@
|
||||
#ifndef SkPDFShader_DEFINED
|
||||
#define SkPDFShader_DEFINED
|
||||
|
||||
#include "SkBitmapKey.h"
|
||||
#include "SkPDFTypes.h"
|
||||
#include "SkShader.h"
|
||||
|
||||
class SkPDFCanon;
|
||||
class SkPDFDocument;
|
||||
class SkMatrix;
|
||||
class SkShader;
|
||||
struct SkIRect;
|
||||
|
||||
/** \class SkPDFShader
|
||||
@ -25,8 +26,6 @@ struct SkIRect;
|
||||
|
||||
class SkPDFShader {
|
||||
public:
|
||||
class State;
|
||||
|
||||
/** Get the PDF shader for the passed SkShader. If the SkShader is
|
||||
* invalid in some way, returns nullptr. The reference count of
|
||||
* the object is incremented and it is the caller's responsibility to
|
||||
@ -41,60 +40,47 @@ public:
|
||||
* @param rasterScale Additional scale to be applied for early
|
||||
* rasterization.
|
||||
*/
|
||||
static SkPDFObject* GetPDFShader(SkPDFDocument* doc,
|
||||
SkScalar dpi,
|
||||
SkShader* shader,
|
||||
const SkMatrix& matrix,
|
||||
const SkIRect& surfaceBBox,
|
||||
SkScalar rasterScale);
|
||||
static sk_sp<SkPDFObject> GetPDFShader(SkPDFDocument* doc,
|
||||
SkScalar dpi,
|
||||
SkShader* shader,
|
||||
const SkMatrix& matrix,
|
||||
const SkIRect& surfaceBBox,
|
||||
SkScalar rasterScale);
|
||||
|
||||
static sk_sp<SkPDFArray> MakeRangeObject();
|
||||
};
|
||||
|
||||
class SkPDFFunctionShader final : public SkPDFDict {
|
||||
public:
|
||||
static SkPDFFunctionShader* Create(SkPDFCanon*,
|
||||
std::unique_ptr<SkPDFShader::State>*);
|
||||
virtual ~SkPDFFunctionShader();
|
||||
bool equals(const SkPDFShader::State&) const;
|
||||
class State {
|
||||
public:
|
||||
SkShader::GradientType fType;
|
||||
SkShader::GradientInfo fInfo;
|
||||
std::unique_ptr<SkColor[]> fColors;
|
||||
std::unique_ptr<SkScalar[]> fStops;
|
||||
SkMatrix fCanvasTransform;
|
||||
SkMatrix fShaderTransform;
|
||||
SkIRect fBBox;
|
||||
|
||||
private:
|
||||
std::unique_ptr<const SkPDFShader::State> fShaderState;
|
||||
SkPDFFunctionShader(SkPDFShader::State*);
|
||||
typedef SkPDFDict INHERITED;
|
||||
};
|
||||
SkBitmapKey fBitmapKey;
|
||||
SkShader::TileMode fImageTileModes[2];
|
||||
|
||||
/**
|
||||
* A shader for PDF gradients. This encapsulates the function shader
|
||||
* inside a tiling pattern while providing a common pattern interface.
|
||||
* The encapsulation allows the use of a SMask for transparency gradients.
|
||||
*/
|
||||
class SkPDFAlphaFunctionShader final : public SkPDFStream {
|
||||
public:
|
||||
static SkPDFAlphaFunctionShader* Create(SkPDFDocument*,
|
||||
SkScalar dpi,
|
||||
std::unique_ptr<SkPDFShader::State>*);
|
||||
virtual ~SkPDFAlphaFunctionShader();
|
||||
bool equals(const SkPDFShader::State&) const;
|
||||
State(SkShader* shader, const SkMatrix& canvasTransform,
|
||||
const SkIRect& bbox, SkScalar rasterScale,
|
||||
SkBitmap* dstImage);
|
||||
|
||||
private:
|
||||
std::unique_ptr<const SkPDFShader::State> fShaderState;
|
||||
SkPDFAlphaFunctionShader(SkPDFShader::State*);
|
||||
typedef SkPDFStream INHERITED;
|
||||
};
|
||||
bool operator==(const State& b) const;
|
||||
|
||||
class SkPDFImageShader final : public SkPDFStream {
|
||||
public:
|
||||
static SkPDFImageShader* Create(SkPDFDocument*,
|
||||
SkScalar dpi,
|
||||
std::unique_ptr<SkPDFShader::State>*);
|
||||
virtual ~SkPDFImageShader();
|
||||
bool equals(const SkPDFShader::State&) const;
|
||||
State MakeAlphaToLuminosityState() const;
|
||||
State MakeOpaqueState() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<const SkPDFShader::State> fShaderState;
|
||||
SkPDFImageShader(SkPDFShader::State*);
|
||||
typedef SkPDFStream INHERITED;
|
||||
bool GradientHasAlpha() const;
|
||||
|
||||
State(State&&) = default;
|
||||
State& operator=(State&&) = default;
|
||||
|
||||
private:
|
||||
State(const State& other);
|
||||
State& operator=(const State& rhs);
|
||||
void allocateGradientInfoStorage();
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -331,7 +331,7 @@ private:
|
||||
memory.
|
||||
*/
|
||||
|
||||
class SkPDFStream : public SkPDFObject {
|
||||
class SkPDFStream final : public SkPDFObject {
|
||||
|
||||
public:
|
||||
/** Create a PDF stream. A Length entry is automatically added to the
|
||||
|
@ -35,3 +35,23 @@ DEF_TEST(CPlusPlusEleven_constexpr, r) {
|
||||
static constexpr int y = SkTPin<int>(100, 0, 10);
|
||||
REPORTER_ASSERT(r, y == 10);
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct MoveableCopyable {
|
||||
bool fCopied;
|
||||
MoveableCopyable() : fCopied(false) {}
|
||||
MoveableCopyable(const MoveableCopyable &o) : fCopied(true) {}
|
||||
MoveableCopyable(MoveableCopyable &&o) : fCopied(o.fCopied) {}
|
||||
};
|
||||
struct TestClass {
|
||||
MoveableCopyable fFoo;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
DEF_TEST(CPlusPlusEleven_default_move, r) {
|
||||
TestClass a;
|
||||
TestClass b(a);
|
||||
TestClass c(std::move(a));
|
||||
REPORTER_ASSERT(r, b.fFoo.fCopied);
|
||||
REPORTER_ASSERT(r, !c.fFoo.fCopied);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user