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