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 "include/core/SkStream.h"
9 #include "src/pdf/SkPDFResourceDict.h"
10 #include "src/pdf/SkPDFTypes.h"
11 
12 // Verify that the values of enum ResourceType correspond to the expected values
13 // 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 + kSkStrAppendS32_MaxSize;
23 
24 // returns pointer just past end of what's written into `dst`.
get_resource_name(char dst[kMaxResourceNameLength],SkPDFResourceType type,int key)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 
SkPDFWriteResourceName(SkWStream * dst,SkPDFResourceType type,int key)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 
resource_name(SkPDFResourceType type)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 
resource(SkPDFResourceType type,int index)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 
add_subdict(const std::vector<SkPDFIndirectReference> & resourceList,SkPDFResourceType type,SkPDFDict * dst)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 
make_proc_set()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 
SkPDFMakeResourceDict(const std::vector<SkPDFIndirectReference> & graphicStateResources,const std::vector<SkPDFIndirectReference> & shaderResources,const std::vector<SkPDFIndirectReference> & xObjectResources,const std::vector<SkPDFIndirectReference> & fontResources)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("ProcSet", 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