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 "SkPostConfig.h"
10
11SK_DEFINE_INST_COUNT(SkPDFResourceDict)
12
13// Sanity check that the values of enum SkPDFResourceType correspond to the
14// expected values as defined in the arrays below.
15// If these are failing, you may need to update the resource_type_prefixes
16// and resource_type_names arrays below.
17SK_COMPILE_ASSERT(SkPDFResourceDict::kExtGState_ResourceType == 0,
18                  resource_type_mismatch);
19SK_COMPILE_ASSERT(SkPDFResourceDict::kPattern_ResourceType == 1,
20                  resource_type_mismatch);
21SK_COMPILE_ASSERT(SkPDFResourceDict::kXObject_ResourceType == 2,
22                  resource_type_mismatch);
23SK_COMPILE_ASSERT(SkPDFResourceDict::kFont_ResourceType == 3,
24                  resource_type_mismatch);
25
26static const char resource_type_prefixes[] = {
27        'G',
28        'P',
29        'X',
30        'F'
31};
32
33static const char* resource_type_names[] = {
34        "ExtGState",
35        "Pattern",
36        "XObject",
37        "Font"
38};
39
40static char get_resource_type_prefix(
41        SkPDFResourceDict::SkPDFResourceType type) {
42    SkASSERT(type >= 0);
43    SkASSERT(type < SkPDFResourceDict::kResourceTypeCount);
44
45    return resource_type_prefixes[type];
46}
47
48static const char* get_resource_type_name(
49        SkPDFResourceDict::SkPDFResourceType type) {
50    SkASSERT(type >= 0);
51    SkASSERT(type < SkPDFResourceDict::kResourceTypeCount);
52
53    return resource_type_names[type];
54}
55
56SkPDFResourceDict::SkPDFResourceDict() : SkPDFDict() {
57    const char procs[][7] = {"PDF", "Text", "ImageB", "ImageC", "ImageI"};
58    SkPDFArray* procSets = SkNEW(SkPDFArray());
59
60    procSets->reserve(SK_ARRAY_COUNT(procs));
61    for (size_t i = 0; i < SK_ARRAY_COUNT(procs); i++) {
62        procSets->appendName(procs[i]);
63    }
64    insert("ProcSets", procSets)->unref();
65
66    // Actual sub-dicts will be lazily added later
67    fTypes.setCount(kResourceTypeCount);
68    for (size_t i=0; i < kResourceTypeCount; i++) {
69        fTypes[i] = NULL;
70    }
71}
72
73SkPDFObject* SkPDFResourceDict::insertResourceAsReference(
74        SkPDFResourceType type, int key, SkPDFObject* value) {
75    SkAutoTUnref<SkPDFObjRef> ref(SkNEW_ARGS(SkPDFObjRef, (value)));
76    insertResource(type, key, ref);
77    fResources.add(value);
78
79    return value;
80}
81
82void SkPDFResourceDict::getReferencedResources(
83        const SkTSet<SkPDFObject*>& knownResourceObjects,
84        SkTSet<SkPDFObject*>* newResourceObjects,
85        bool recursive) const {
86    // TODO: reserve not correct if we need to recursively explore.
87    newResourceObjects->setReserve(newResourceObjects->count() +
88                                   fResources.count());
89
90    for (int i = 0; i < fResources.count(); i++) {
91        if (!knownResourceObjects.contains(fResources[i]) &&
92                !newResourceObjects->contains(fResources[i])) {
93            newResourceObjects->add(fResources[i]);
94            fResources[i]->ref();
95            if (recursive) {
96                fResources[i]->getResources(knownResourceObjects,
97                                            newResourceObjects);
98            }
99        }
100    }
101}
102
103SkString SkPDFResourceDict::getResourceName(
104        SkPDFResourceType type, int key) {
105    SkString keyString;
106    keyString.printf("%c%d", get_resource_type_prefix(type), key);
107    return keyString;
108}
109
110SkPDFObject* SkPDFResourceDict::insertResource(
111        SkPDFResourceType type, int key, SkPDFObject* value) {
112    SkPDFDict* typeDict = fTypes[type];
113    if (NULL == typeDict) {
114        SkAutoTUnref<SkPDFDict> newDict(SkNEW(SkPDFDict()));
115        SkAutoTUnref<SkPDFName> typeName(
116                SkNEW_ARGS(SkPDFName, (get_resource_type_name(type))));
117        insert(typeName, newDict);  // ref counting handled here
118        fTypes[type] = newDict;
119        typeDict = newDict.get();
120    }
121
122    SkAutoTUnref<SkPDFName> keyName(
123            SkNEW_ARGS(SkPDFName, (getResourceName(type, key))));
124    typeDict->insert(keyName, value);
125    return value;
126}
127