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);
}
Exemple #2
0
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);
}
Exemple #3
0
/**
 * 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;
    }
}