1 /* 2 * Copyright 2013 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkPDFResourceDict.h" 9 #include "SkPDFTypes.h" 10 #include "SkStream.h" 11 12 // Sanity check that the values of enum ResourceType correspond to the 13 // expected values as defined in the arrays below. 14 // If these are failing, you may need to update the kResourceTypePrefixes 15 // and kResourceTypeNames arrays below. 16 static_assert(0 == (int)SkPDFResourceType::kExtGState, "resource_type_mismatch"); 17 static_assert(1 == (int)SkPDFResourceType::kPattern, "resource_type_mismatch"); 18 static_assert(2 == (int)SkPDFResourceType::kXObject, "resource_type_mismatch"); 19 static_assert(3 == (int)SkPDFResourceType::kFont, "resource_type_mismatch"); 20 21 // One extra character for the Prefix. 22 constexpr size_t kMaxResourceNameLength = 1 + SkStrAppendS32_MaxSize; 23 24 // returns pointer just past end of what's written into `dst`. 25 static char* get_resource_name(char dst[kMaxResourceNameLength], SkPDFResourceType type, int key) { 26 static const char kResourceTypePrefixes[] = { 27 'G', // kExtGState 28 'P', // kPattern 29 'X', // kXObject 30 'F' // kFont 31 }; 32 SkASSERT((unsigned)type < SK_ARRAY_COUNT(kResourceTypePrefixes)); 33 dst[0] = kResourceTypePrefixes[(unsigned)type]; 34 return SkStrAppendS32(dst + 1, key); 35 } 36 37 void SkPDFWriteResourceName(SkWStream* dst, SkPDFResourceType type, int key) { 38 // One extra character for the leading '/'. 39 char buffer[1 + kMaxResourceNameLength]; 40 buffer[0] = '/'; 41 char* end = get_resource_name(buffer + 1, type, key); 42 dst->write(buffer, (size_t)(end - buffer)); 43 } 44 45 static const char* resource_name(SkPDFResourceType type) { 46 static const char* kResourceTypeNames[] = { 47 "ExtGState", 48 "Pattern", 49 "XObject", 50 "Font" 51 }; 52 SkASSERT((unsigned)type < SK_ARRAY_COUNT(kResourceTypeNames)); 53 return kResourceTypeNames[(unsigned)type]; 54 } 55 56 static SkString resource(SkPDFResourceType type, int index) { 57 char buffer[kMaxResourceNameLength]; 58 char* end = get_resource_name(buffer, type, index); 59 return SkString(buffer, (size_t)(end - buffer)); 60 } 61 62 static void add_subdict(const std::vector<SkPDFIndirectReference>& resourceList, 63 SkPDFResourceType type, 64 SkPDFDict* dst) { 65 if (!resourceList.empty()) { 66 auto resources = SkPDFMakeDict(); 67 for (SkPDFIndirectReference ref : resourceList) { 68 resources->insertRef(resource(type, ref.fValue), ref); 69 } 70 dst->insertObject(resource_name(type), std::move(resources)); 71 } 72 } 73 74 static std::unique_ptr<SkPDFArray> make_proc_set() { 75 auto procSets = SkPDFMakeArray(); 76 static const char kProcs[][7] = { "PDF", "Text", "ImageB", "ImageC", "ImageI"}; 77 procSets->reserve(SK_ARRAY_COUNT(kProcs)); 78 for (const char* proc : kProcs) { 79 procSets->appendName(proc); 80 } 81 return procSets; 82 } 83 84 std::unique_ptr<SkPDFDict> SkPDFMakeResourceDict( 85 const std::vector<SkPDFIndirectReference>& graphicStateResources, 86 const std::vector<SkPDFIndirectReference>& shaderResources, 87 const std::vector<SkPDFIndirectReference>& xObjectResources, 88 const std::vector<SkPDFIndirectReference>& fontResources) { 89 auto dict = SkPDFMakeDict(); 90 dict->insertObject("ProcSets", make_proc_set()); 91 add_subdict(graphicStateResources, SkPDFResourceType::kExtGState, dict.get()); 92 add_subdict(shaderResources, SkPDFResourceType::kPattern, dict.get()); 93 add_subdict(xObjectResources, SkPDFResourceType::kXObject, dict.get()); 94 add_subdict(fontResources, SkPDFResourceType::kFont, dict.get()); 95 return dict; 96 } 97