sk_sp<SkPDFObject> SkPDFMakeFormXObject(std::unique_ptr<SkStreamAsset> content, sk_sp<SkPDFArray> mediaBox, sk_sp<SkPDFDict> resourceDict, const SkMatrix& inverseTransform, const char* colorSpace) { auto form = sk_make_sp<SkPDFStream>(std::move(content)); form->dict()->insertName("Type", "XObject"); form->dict()->insertName("Subtype", "Form"); if (!inverseTransform.isIdentity()) { sk_sp<SkPDFObject> mat(SkPDFUtils::MatrixToArray(inverseTransform)); form->dict()->insertObject("Matrix", std::move(mat)); } form->dict()->insertObject("Resources", std::move(resourceDict)); form->dict()->insertObject("BBox", std::move(mediaBox)); // 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. form->dict()->insertObject("Group", std::move(group)); return std::move(form); }
void SkPDFGraphicState::emitObject( SkWStream* stream, const SkPDFObjNumMap& objNumMap, const SkPDFSubstituteMap& substitutes) const { auto dict = sk_make_sp<SkPDFDict>("ExtGState"); dict->insertName("Type", "ExtGState"); SkScalar alpha = SkIntToScalar(fAlpha) / 0xFF; dict->insertScalar("CA", alpha); dict->insertScalar("ca", alpha); SkPaint::Cap strokeCap = (SkPaint::Cap)fStrokeCap; SkPaint::Join strokeJoin = (SkPaint::Join)fStrokeJoin; SkXfermode::Mode xferMode = (SkXfermode::Mode)fMode; static_assert(SkPaint::kButt_Cap == 0, "paint_cap_mismatch"); static_assert(SkPaint::kRound_Cap == 1, "paint_cap_mismatch"); static_assert(SkPaint::kSquare_Cap == 2, "paint_cap_mismatch"); static_assert(SkPaint::kCapCount == 3, "paint_cap_mismatch"); SkASSERT(strokeCap >= 0 && strokeCap <= 2); dict->insertInt("LC", strokeCap); static_assert(SkPaint::kMiter_Join == 0, "paint_join_mismatch"); static_assert(SkPaint::kRound_Join == 1, "paint_join_mismatch"); static_assert(SkPaint::kBevel_Join == 2, "paint_join_mismatch"); static_assert(SkPaint::kJoinCount == 3, "paint_join_mismatch"); SkASSERT(strokeJoin >= 0 && strokeJoin <= 2); dict->insertInt("LJ", strokeJoin); dict->insertScalar("LW", fStrokeWidth); dict->insertScalar("ML", fStrokeMiter); dict->insertBool("SA", true); // SA = Auto stroke adjustment. dict->insertName("BM", as_blend_mode(xferMode)); dict->emitObject(stream, objNumMap, substitutes); }
/** * 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 // isolated blending. Do this conditionally if that changes. 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)); }
sk_sp<SkPDFDict> SkPDFGraphicState::GetGraphicStateForPaint(SkPDFCanon* canon, const SkPaint& p) { SkASSERT(canon); if (SkPaint::kFill_Style == p.getStyle()) { SkPDFFillGraphicState fillKey = {p.getAlpha(), pdf_blend_mode(p.getBlendMode())}; auto& fillMap = canon->fFillGSMap; if (sk_sp<SkPDFDict>* statePtr = fillMap.find(fillKey)) { return *statePtr; } auto state = sk_make_sp<SkPDFDict>(); state->reserve(2); state->insertScalar("ca", fillKey.fAlpha / 255.0f); state->insertName("BM", as_pdf_blend_mode_name((SkBlendMode)fillKey.fBlendMode)); fillMap.set(fillKey, state); return state; } else { SkPDFStrokeGraphicState strokeKey = { p.getStrokeWidth(), p.getStrokeMiter(), SkToU8(p.getStrokeCap()), SkToU8(p.getStrokeJoin()), p.getAlpha(), pdf_blend_mode(p.getBlendMode())}; auto& sMap = canon->fStrokeGSMap; if (sk_sp<SkPDFDict>* statePtr = sMap.find(strokeKey)) { return *statePtr; } auto state = sk_make_sp<SkPDFDict>(); state->reserve(8); state->insertScalar("CA", strokeKey.fAlpha / 255.0f); state->insertScalar("ca", strokeKey.fAlpha / 255.0f); state->insertInt("LC", to_stroke_cap(strokeKey.fStrokeCap)); state->insertInt("LJ", to_stroke_join(strokeKey.fStrokeJoin)); state->insertScalar("LW", strokeKey.fStrokeWidth); state->insertScalar("ML", strokeKey.fStrokeMiter); state->insertBool("SA", true); // SA = Auto stroke adjustment. state->insertName("BM", as_pdf_blend_mode_name((SkBlendMode)strokeKey.fBlendMode)); sMap.set(strokeKey, state); return state; } }