1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2011 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/pdf/SkPDFGraphicState.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/core/SkData.h"
11cb93a386Sopenharmony_ci#include "include/core/SkPaint.h"
12cb93a386Sopenharmony_ci#include "include/docs/SkPDFDocument.h"
13cb93a386Sopenharmony_ci#include "include/private/SkTo.h"
14cb93a386Sopenharmony_ci#include "src/pdf/SkPDFDocumentPriv.h"
15cb93a386Sopenharmony_ci#include "src/pdf/SkPDFFormXObject.h"
16cb93a386Sopenharmony_ci#include "src/pdf/SkPDFUtils.h"
17cb93a386Sopenharmony_ci
18cb93a386Sopenharmony_cistatic const char* as_pdf_blend_mode_name(SkBlendMode mode) {
19cb93a386Sopenharmony_ci    const char* name = SkPDFUtils::BlendModeName(mode);
20cb93a386Sopenharmony_ci    SkASSERT(name);
21cb93a386Sopenharmony_ci    return name;
22cb93a386Sopenharmony_ci}
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_cistatic int to_stroke_cap(uint8_t cap) {
25cb93a386Sopenharmony_ci    // PDF32000.book section 8.4.3.3 "Line Cap Style"
26cb93a386Sopenharmony_ci    switch ((SkPaint::Cap)cap) {
27cb93a386Sopenharmony_ci        case SkPaint::kButt_Cap:   return 0;
28cb93a386Sopenharmony_ci        case SkPaint::kRound_Cap:  return 1;
29cb93a386Sopenharmony_ci        case SkPaint::kSquare_Cap: return 2;
30cb93a386Sopenharmony_ci        default: SkASSERT(false);  return 0;
31cb93a386Sopenharmony_ci    }
32cb93a386Sopenharmony_ci}
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_cistatic int to_stroke_join(uint8_t join) {
35cb93a386Sopenharmony_ci    // PDF32000.book section 8.4.3.4 "Line Join Style"
36cb93a386Sopenharmony_ci    switch ((SkPaint::Join)join) {
37cb93a386Sopenharmony_ci        case SkPaint::kMiter_Join: return 0;
38cb93a386Sopenharmony_ci        case SkPaint::kRound_Join: return 1;
39cb93a386Sopenharmony_ci        case SkPaint::kBevel_Join: return 2;
40cb93a386Sopenharmony_ci        default: SkASSERT(false);  return 0;
41cb93a386Sopenharmony_ci    }
42cb93a386Sopenharmony_ci}
43cb93a386Sopenharmony_ci
44cb93a386Sopenharmony_ci// If a SkXfermode is unsupported in PDF, this function returns
45cb93a386Sopenharmony_ci// SrcOver, otherwise, it returns that Xfermode as a Mode.
46cb93a386Sopenharmony_cistatic uint8_t pdf_blend_mode(SkBlendMode mode) {
47cb93a386Sopenharmony_ci    if (!SkPDFUtils::BlendModeName(mode)
48cb93a386Sopenharmony_ci        || SkBlendMode::kXor  == mode
49cb93a386Sopenharmony_ci        || SkBlendMode::kPlus == mode)
50cb93a386Sopenharmony_ci    {
51cb93a386Sopenharmony_ci        mode = SkBlendMode::kSrcOver;
52cb93a386Sopenharmony_ci    }
53cb93a386Sopenharmony_ci    return SkToU8((unsigned)mode);
54cb93a386Sopenharmony_ci}
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_ciSkPDFIndirectReference SkPDFGraphicState::GetGraphicStateForPaint(SkPDFDocument* doc,
57cb93a386Sopenharmony_ci                                                                  const SkPaint& p) {
58cb93a386Sopenharmony_ci    SkASSERT(doc);
59cb93a386Sopenharmony_ci    const SkBlendMode mode = p.getBlendMode_or(SkBlendMode::kSrcOver);
60cb93a386Sopenharmony_ci
61cb93a386Sopenharmony_ci    if (SkPaint::kFill_Style == p.getStyle()) {
62cb93a386Sopenharmony_ci        SkPDFFillGraphicState fillKey = {p.getColor4f().fA, pdf_blend_mode(mode)};
63cb93a386Sopenharmony_ci        auto& fillMap = doc->fFillGSMap;
64cb93a386Sopenharmony_ci        if (SkPDFIndirectReference* statePtr = fillMap.find(fillKey)) {
65cb93a386Sopenharmony_ci            return *statePtr;
66cb93a386Sopenharmony_ci        }
67cb93a386Sopenharmony_ci        SkPDFDict state;
68cb93a386Sopenharmony_ci        state.reserve(2);
69cb93a386Sopenharmony_ci        state.insertColorComponentF("ca", fillKey.fAlpha);
70cb93a386Sopenharmony_ci        state.insertName("BM", as_pdf_blend_mode_name((SkBlendMode)fillKey.fBlendMode));
71cb93a386Sopenharmony_ci        SkPDFIndirectReference ref = doc->emit(state);
72cb93a386Sopenharmony_ci        fillMap.set(fillKey, ref);
73cb93a386Sopenharmony_ci        return ref;
74cb93a386Sopenharmony_ci    } else {
75cb93a386Sopenharmony_ci        SkPDFStrokeGraphicState strokeKey = {
76cb93a386Sopenharmony_ci            p.getStrokeWidth(),
77cb93a386Sopenharmony_ci            p.getStrokeMiter(),
78cb93a386Sopenharmony_ci            p.getColor4f().fA,
79cb93a386Sopenharmony_ci            SkToU8(p.getStrokeCap()),
80cb93a386Sopenharmony_ci            SkToU8(p.getStrokeJoin()),
81cb93a386Sopenharmony_ci            pdf_blend_mode(mode)
82cb93a386Sopenharmony_ci        };
83cb93a386Sopenharmony_ci        auto& sMap = doc->fStrokeGSMap;
84cb93a386Sopenharmony_ci        if (SkPDFIndirectReference* statePtr = sMap.find(strokeKey)) {
85cb93a386Sopenharmony_ci            return *statePtr;
86cb93a386Sopenharmony_ci        }
87cb93a386Sopenharmony_ci        SkPDFDict state;
88cb93a386Sopenharmony_ci        state.reserve(8);
89cb93a386Sopenharmony_ci        state.insertColorComponentF("CA", strokeKey.fAlpha);
90cb93a386Sopenharmony_ci        state.insertColorComponentF("ca", strokeKey.fAlpha);
91cb93a386Sopenharmony_ci        state.insertInt("LC", to_stroke_cap(strokeKey.fStrokeCap));
92cb93a386Sopenharmony_ci        state.insertInt("LJ", to_stroke_join(strokeKey.fStrokeJoin));
93cb93a386Sopenharmony_ci        state.insertScalar("LW", strokeKey.fStrokeWidth);
94cb93a386Sopenharmony_ci        state.insertScalar("ML", strokeKey.fStrokeMiter);
95cb93a386Sopenharmony_ci        state.insertBool("SA", true);  // SA = Auto stroke adjustment.
96cb93a386Sopenharmony_ci        state.insertName("BM", as_pdf_blend_mode_name((SkBlendMode)strokeKey.fBlendMode));
97cb93a386Sopenharmony_ci        SkPDFIndirectReference ref = doc->emit(state);
98cb93a386Sopenharmony_ci        sMap.set(strokeKey, ref);
99cb93a386Sopenharmony_ci        return ref;
100cb93a386Sopenharmony_ci    }
101cb93a386Sopenharmony_ci}
102cb93a386Sopenharmony_ci
103cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////
104cb93a386Sopenharmony_ci
105cb93a386Sopenharmony_cistatic SkPDFIndirectReference make_invert_function(SkPDFDocument* doc) {
106cb93a386Sopenharmony_ci    // Acrobat crashes if we use a type 0 function, kpdf crashes if we use
107cb93a386Sopenharmony_ci    // a type 2 function, so we use a type 4 function.
108cb93a386Sopenharmony_ci    static const char psInvert[] = "{1 exch sub}";
109cb93a386Sopenharmony_ci    // Do not copy the trailing '\0' into the SkData.
110cb93a386Sopenharmony_ci    auto invertFunction = SkData::MakeWithoutCopy(psInvert, strlen(psInvert));
111cb93a386Sopenharmony_ci
112cb93a386Sopenharmony_ci    std::unique_ptr<SkPDFDict> dict = SkPDFMakeDict();
113cb93a386Sopenharmony_ci    dict->insertInt("FunctionType", 4);
114cb93a386Sopenharmony_ci    dict->insertObject("Domain", SkPDFMakeArray(0, 1));
115cb93a386Sopenharmony_ci    dict->insertObject("Range", SkPDFMakeArray(0, 1));
116cb93a386Sopenharmony_ci    return SkPDFStreamOut(std::move(dict), SkMemoryStream::Make(std::move(invertFunction)), doc);
117cb93a386Sopenharmony_ci}
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_ciSkPDFIndirectReference SkPDFGraphicState::GetSMaskGraphicState(SkPDFIndirectReference sMask,
120cb93a386Sopenharmony_ci                                                               bool invert,
121cb93a386Sopenharmony_ci                                                               SkPDFSMaskMode sMaskMode,
122cb93a386Sopenharmony_ci                                                               SkPDFDocument* doc) {
123cb93a386Sopenharmony_ci    // The practical chances of using the same mask more than once are unlikely
124cb93a386Sopenharmony_ci    // enough that it's not worth canonicalizing.
125cb93a386Sopenharmony_ci    auto sMaskDict = SkPDFMakeDict("Mask");
126cb93a386Sopenharmony_ci    if (sMaskMode == kAlpha_SMaskMode) {
127cb93a386Sopenharmony_ci        sMaskDict->insertName("S", "Alpha");
128cb93a386Sopenharmony_ci    } else if (sMaskMode == kLuminosity_SMaskMode) {
129cb93a386Sopenharmony_ci        sMaskDict->insertName("S", "Luminosity");
130cb93a386Sopenharmony_ci    }
131cb93a386Sopenharmony_ci    sMaskDict->insertRef("G", sMask);
132cb93a386Sopenharmony_ci    if (invert) {
133cb93a386Sopenharmony_ci        // let the doc deduplicate this object.
134cb93a386Sopenharmony_ci        if (doc->fInvertFunction == SkPDFIndirectReference()) {
135cb93a386Sopenharmony_ci            doc->fInvertFunction = make_invert_function(doc);
136cb93a386Sopenharmony_ci        }
137cb93a386Sopenharmony_ci        sMaskDict->insertRef("TR", doc->fInvertFunction);
138cb93a386Sopenharmony_ci    }
139cb93a386Sopenharmony_ci    SkPDFDict result("ExtGState");
140cb93a386Sopenharmony_ci    result.insertObject("SMask", std::move(sMaskDict));
141cb93a386Sopenharmony_ci    return doc->emit(result);
142cb93a386Sopenharmony_ci}
143