/* * Copyright 2013 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkPDFResourceDict.h" #include "SkPDFTypes.h" #include "SkStream.h" // Sanity check that the values of enum ResourceType correspond to the // expected values as defined in the arrays below. // If these are failing, you may need to update the kResourceTypePrefixes // and kResourceTypeNames arrays below. static_assert(0 == (int)SkPDFResourceType::kExtGState, "resource_type_mismatch"); static_assert(1 == (int)SkPDFResourceType::kPattern, "resource_type_mismatch"); static_assert(2 == (int)SkPDFResourceType::kXObject, "resource_type_mismatch"); static_assert(3 == (int)SkPDFResourceType::kFont, "resource_type_mismatch"); // One extra character for the Prefix. constexpr size_t kMaxResourceNameLength = 1 + SkStrAppendS32_MaxSize; // returns pointer just past end of what's written into `dst`. static char* get_resource_name(char dst[kMaxResourceNameLength], SkPDFResourceType type, int key) { static const char kResourceTypePrefixes[] = { 'G', // kExtGState 'P', // kPattern 'X', // kXObject 'F' // kFont }; SkASSERT((unsigned)type < SK_ARRAY_COUNT(kResourceTypePrefixes)); dst[0] = kResourceTypePrefixes[(unsigned)type]; return SkStrAppendS32(dst + 1, key); } void SkPDFWriteResourceName(SkWStream* dst, SkPDFResourceType type, int key) { // One extra character for the leading '/'. char buffer[1 + kMaxResourceNameLength]; buffer[0] = '/'; char* end = get_resource_name(buffer + 1, type, key); dst->write(buffer, (size_t)(end - buffer)); } static const char* resource_name(SkPDFResourceType type) { static const char* kResourceTypeNames[] = { "ExtGState", "Pattern", "XObject", "Font" }; SkASSERT((unsigned)type < SK_ARRAY_COUNT(kResourceTypeNames)); return kResourceTypeNames[(unsigned)type]; } static SkString resource(SkPDFResourceType type, int index) { char buffer[kMaxResourceNameLength]; char* end = get_resource_name(buffer, type, index); return SkString(buffer, (size_t)(end - buffer)); } static void add_subdict(const std::vector& resourceList, SkPDFResourceType type, SkPDFDict* dst) { if (!resourceList.empty()) { auto resources = SkPDFMakeDict(); for (SkPDFIndirectReference ref : resourceList) { resources->insertRef(resource(type, ref.fValue), ref); } dst->insertObject(resource_name(type), std::move(resources)); } } static std::unique_ptr make_proc_set() { auto procSets = SkPDFMakeArray(); static const char kProcs[][7] = { "PDF", "Text", "ImageB", "ImageC", "ImageI"}; procSets->reserve(SK_ARRAY_COUNT(kProcs)); for (const char* proc : kProcs) { procSets->appendName(proc); } return procSets; } std::unique_ptr SkPDFMakeResourceDict( const std::vector& graphicStateResources, const std::vector& shaderResources, const std::vector& xObjectResources, const std::vector& fontResources) { auto dict = SkPDFMakeDict(); dict->insertObject("ProcSets", make_proc_set()); add_subdict(graphicStateResources, SkPDFResourceType::kExtGState, dict.get()); add_subdict(shaderResources, SkPDFResourceType::kPattern, dict.get()); add_subdict(xObjectResources, SkPDFResourceType::kXObject, dict.get()); add_subdict(fontResources, SkPDFResourceType::kFont, dict.get()); return dict; }