Home | History | Annotate | Download | only in pdf
      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