diff options
Diffstat (limited to 'gfx/skia/skia/src/pdf/SkPDFGraphicState.cpp')
-rw-r--r-- | gfx/skia/skia/src/pdf/SkPDFGraphicState.cpp | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/gfx/skia/skia/src/pdf/SkPDFGraphicState.cpp b/gfx/skia/skia/src/pdf/SkPDFGraphicState.cpp new file mode 100644 index 0000000000..6cab7441a6 --- /dev/null +++ b/gfx/skia/skia/src/pdf/SkPDFGraphicState.cpp @@ -0,0 +1,142 @@ +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "src/pdf/SkPDFGraphicState.h" + +#include "include/core/SkData.h" +#include "include/core/SkPaint.h" +#include "include/docs/SkPDFDocument.h" +#include "include/private/base/SkTo.h" +#include "src/pdf/SkPDFDocumentPriv.h" +#include "src/pdf/SkPDFFormXObject.h" +#include "src/pdf/SkPDFUtils.h" + +static const char* as_pdf_blend_mode_name(SkBlendMode mode) { + const char* name = SkPDFUtils::BlendModeName(mode); + SkASSERT(name); + return name; +} + +static int to_stroke_cap(uint8_t cap) { + // PDF32000.book section 8.4.3.3 "Line Cap Style" + switch ((SkPaint::Cap)cap) { + case SkPaint::kButt_Cap: return 0; + case SkPaint::kRound_Cap: return 1; + case SkPaint::kSquare_Cap: return 2; + default: SkASSERT(false); return 0; + } +} + +static int to_stroke_join(uint8_t join) { + // PDF32000.book section 8.4.3.4 "Line Join Style" + switch ((SkPaint::Join)join) { + case SkPaint::kMiter_Join: return 0; + case SkPaint::kRound_Join: return 1; + case SkPaint::kBevel_Join: return 2; + default: SkASSERT(false); return 0; + } +} + +// If a SkXfermode is unsupported in PDF, this function returns +// SrcOver, otherwise, it returns that Xfermode as a Mode. +static uint8_t pdf_blend_mode(SkBlendMode mode) { + if (!SkPDFUtils::BlendModeName(mode) + || SkBlendMode::kXor == mode + || SkBlendMode::kPlus == mode) + { + mode = SkBlendMode::kSrcOver; + } + return SkToU8((unsigned)mode); +} + +SkPDFIndirectReference SkPDFGraphicState::GetGraphicStateForPaint(SkPDFDocument* doc, + const SkPaint& p) { + SkASSERT(doc); + const SkBlendMode mode = p.getBlendMode_or(SkBlendMode::kSrcOver); + + if (SkPaint::kFill_Style == p.getStyle()) { + SkPDFFillGraphicState fillKey = {p.getColor4f().fA, pdf_blend_mode(mode)}; + auto& fillMap = doc->fFillGSMap; + if (SkPDFIndirectReference* statePtr = fillMap.find(fillKey)) { + return *statePtr; + } + SkPDFDict state; + state.reserve(2); + state.insertColorComponentF("ca", fillKey.fAlpha); + state.insertName("BM", as_pdf_blend_mode_name((SkBlendMode)fillKey.fBlendMode)); + SkPDFIndirectReference ref = doc->emit(state); + fillMap.set(fillKey, ref); + return ref; + } else { + SkPDFStrokeGraphicState strokeKey = { + p.getStrokeWidth(), + p.getStrokeMiter(), + p.getColor4f().fA, + SkToU8(p.getStrokeCap()), + SkToU8(p.getStrokeJoin()), + pdf_blend_mode(mode) + }; + auto& sMap = doc->fStrokeGSMap; + if (SkPDFIndirectReference* statePtr = sMap.find(strokeKey)) { + return *statePtr; + } + SkPDFDict state; + state.reserve(8); + state.insertColorComponentF("CA", strokeKey.fAlpha); + state.insertColorComponentF("ca", strokeKey.fAlpha); + 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)); + SkPDFIndirectReference ref = doc->emit(state); + sMap.set(strokeKey, ref); + return ref; + } +} + +//////////////////////////////////////////////////////////////////////////////// + +static SkPDFIndirectReference make_invert_function(SkPDFDocument* doc) { + // Acrobat crashes if we use a type 0 function, kpdf crashes if we use + // a type 2 function, so we use a type 4 function. + static const char psInvert[] = "{1 exch sub}"; + // Do not copy the trailing '\0' into the SkData. + auto invertFunction = SkData::MakeWithoutCopy(psInvert, strlen(psInvert)); + + std::unique_ptr<SkPDFDict> dict = SkPDFMakeDict(); + dict->insertInt("FunctionType", 4); + dict->insertObject("Domain", SkPDFMakeArray(0, 1)); + dict->insertObject("Range", SkPDFMakeArray(0, 1)); + return SkPDFStreamOut(std::move(dict), SkMemoryStream::Make(std::move(invertFunction)), doc); +} + +SkPDFIndirectReference SkPDFGraphicState::GetSMaskGraphicState(SkPDFIndirectReference sMask, + bool invert, + SkPDFSMaskMode sMaskMode, + SkPDFDocument* doc) { + // The practical chances of using the same mask more than once are unlikely + // enough that it's not worth canonicalizing. + auto sMaskDict = SkPDFMakeDict("Mask"); + if (sMaskMode == kAlpha_SMaskMode) { + sMaskDict->insertName("S", "Alpha"); + } else if (sMaskMode == kLuminosity_SMaskMode) { + sMaskDict->insertName("S", "Luminosity"); + } + sMaskDict->insertRef("G", sMask); + if (invert) { + // let the doc deduplicate this object. + if (doc->fInvertFunction == SkPDFIndirectReference()) { + doc->fInvertFunction = make_invert_function(doc); + } + sMaskDict->insertRef("TR", doc->fInvertFunction); + } + SkPDFDict result("ExtGState"); + result.insertObject("SMask", std::move(sMaskDict)); + return doc->emit(result); +} |