Adds SkPDFResourceDict class, refactor existing code to use it.
authorcommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 22 Jul 2013 18:20:52 +0000 (18:20 +0000)
committercommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 22 Jul 2013 18:20:52 +0000 (18:20 +0000)
Committed: http://code.google.com/p/skia/source/detail?r=10202

R=vandebo@chromium.org, edisonn@google.com

Author: richardlin@chromium.org

Review URL: https://chromiumcodereview.appspot.com/18977002

git-svn-id: http://skia.googlecode.com/svn/trunk@10245 2bbb7eff-a529-9590-31e7-b0007b416f81

gyp/pdf.gyp
include/pdf/SkPDFDevice.h
src/pdf/SkPDFDevice.cpp
src/pdf/SkPDFFormXObject.cpp
src/pdf/SkPDFPage.cpp
src/pdf/SkPDFResourceDict.cpp [new file with mode: 0644]
src/pdf/SkPDFResourceDict.h [new file with mode: 0644]
src/pdf/SkPDFShader.cpp
src/pdf/SkPDFUtils.cpp

index 1efb984..afababe 100644 (file)
@@ -35,6 +35,8 @@
         '../src/pdf/SkPDFImageStream.h',
         '../src/pdf/SkPDFPage.cpp',
         '../src/pdf/SkPDFPage.h',
+        '../src/pdf/SkPDFResourceDict.cpp',
+        '../src/pdf/SkPDFResourceDict.h',
         '../src/pdf/SkPDFShader.cpp',
         '../src/pdf/SkPDFShader.h',
         '../src/pdf/SkPDFStream.cpp',
index d10f330..6c5e457 100644 (file)
@@ -28,6 +28,7 @@ class SkPDFFormXObject;
 class SkPDFGlyphSetMap;
 class SkPDFGraphicState;
 class SkPDFObject;
+class SkPDFResourceDict;
 class SkPDFShader;
 class SkPDFStream;
 template <typename T> class SkTSet;
@@ -147,23 +148,7 @@ public:
 
     /** Returns the resource dictionary for this device.
      */
-    SK_API SkPDFDict* getResourceDict();
-
-    /** Get the list of resources (PDF objects) used on this page.
-     *  This method will add to newResourceObjects any objects that this method
-     *  depends on, but not already in knownResourceObjects. This might operate
-     *  recursively so if this object depends on another object and that object
-     *  depends on two more, all three objects will be added.
-     *
-     *  @param knownResourceObjects  The set of resources to be ignored.
-     *  @param newResourceObjects  The set to append dependant resources to.
-     *  @param recursive    If recursive is true, get the resources of the
-     *                      device's resources recursively. (Useful for adding
-     *                      objects to the catalog.)
-     */
-    SK_API void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
-                             SkTSet<SkPDFObject*>* newResourceObjects,
-                             bool recursive) const;
+    SK_API SkPDFResourceDict* getResourceDict();
 
     /** Get the fonts used on this device.
      */
@@ -223,7 +208,7 @@ private:
     SkClipStack fExistingClipStack;
     SkRegion fExistingClipRegion;
     SkPDFArray* fAnnotations;
-    SkPDFDict* fResourceDict;
+    SkPDFResourceDict* fResourceDict;
     SkTDArray<NamedDestination*> fNamedDestinations;
 
     SkTDArray<SkPDFGraphicState*> fGraphicStateResources;
index a8fc399..f925980 100644 (file)
@@ -20,6 +20,7 @@
 #include "SkPDFFormXObject.h"
 #include "SkPDFGraphicState.h"
 #include "SkPDFImage.h"
+#include "SkPDFResourceDict.h"
 #include "SkPDFShader.h"
 #include "SkPDFStream.h"
 #include "SkPDFTypes.h"
@@ -424,10 +425,13 @@ void GraphicStackState::updateDrawingState(const GraphicStateEntry& state) {
     // PDF treats a shader as a color, so we only set one or the other.
     if (state.fShaderIndex >= 0) {
         if (state.fShaderIndex != currentEntry()->fShaderIndex) {
-            fContentStream->writeText("/Pattern CS /Pattern cs /P");
-            fContentStream->writeDecAsText(state.fShaderIndex);
-            fContentStream->writeText(" SCN /P");
-            fContentStream->writeDecAsText(state.fShaderIndex);
+            SkString resourceName = SkPDFResourceDict::getResourceName(
+                    SkPDFResourceDict::kPattern_ResourceType,
+                    state.fShaderIndex);
+            fContentStream->writeText("/Pattern CS /Pattern cs /");
+            fContentStream->writeText(resourceName.c_str());
+            fContentStream->writeText(" SCN /");
+            fContentStream->writeText(resourceName.c_str());
             fContentStream->writeText(" scn\n");
             currentEntry()->fShaderIndex = state.fShaderIndex;
         }
@@ -1123,123 +1127,46 @@ void SkPDFDevice::setDrawingArea(DrawingArea drawingArea) {
     fDrawingArea = drawingArea;
 }
 
-SkPDFDict* SkPDFDevice::getResourceDict() {
+SkPDFResourceDict* SkPDFDevice::getResourceDict() {
     if (NULL == fResourceDict) {
-        fResourceDict = SkNEW(SkPDFDict);
+        fResourceDict = SkNEW(SkPDFResourceDict);
 
         if (fGraphicStateResources.count()) {
-            SkAutoTUnref<SkPDFDict> extGState(new SkPDFDict());
             for (int i = 0; i < fGraphicStateResources.count(); i++) {
-                SkString nameString("G");
-                nameString.appendS32(i);
-                extGState->insert(
-                        nameString.c_str(),
-                        new SkPDFObjRef(fGraphicStateResources[i]))->unref();
+                fResourceDict->insertResourceAsRef(
+                        SkPDFResourceDict::kExtGState_ResourceType,
+                        i, fGraphicStateResources[i]);
             }
-            fResourceDict->insert("ExtGState", extGState.get());
         }
 
         if (fXObjectResources.count()) {
-            SkAutoTUnref<SkPDFDict> xObjects(new SkPDFDict());
             for (int i = 0; i < fXObjectResources.count(); i++) {
-                SkString nameString("X");
-                nameString.appendS32(i);
-                xObjects->insert(
-                        nameString.c_str(),
-                        new SkPDFObjRef(fXObjectResources[i]))->unref();
+                fResourceDict->insertResourceAsRef(
+                        SkPDFResourceDict::kXObject_ResourceType,
+                        i, fXObjectResources[i]);
             }
-            fResourceDict->insert("XObject", xObjects.get());
         }
 
         if (fFontResources.count()) {
-            SkAutoTUnref<SkPDFDict> fonts(new SkPDFDict());
             for (int i = 0; i < fFontResources.count(); i++) {
-                SkString nameString("F");
-                nameString.appendS32(i);
-                fonts->insert(nameString.c_str(),
-                              new SkPDFObjRef(fFontResources[i]))->unref();
+                fResourceDict->insertResourceAsRef(
+                        SkPDFResourceDict::kFont_ResourceType,
+                        i, fFontResources[i]);
             }
-            fResourceDict->insert("Font", fonts.get());
         }
 
         if (fShaderResources.count()) {
             SkAutoTUnref<SkPDFDict> patterns(new SkPDFDict());
             for (int i = 0; i < fShaderResources.count(); i++) {
-                SkString nameString("P");
-                nameString.appendS32(i);
-                patterns->insert(nameString.c_str(),
-                                 new SkPDFObjRef(fShaderResources[i]))->unref();
+                fResourceDict->insertResourceAsRef(
+                        SkPDFResourceDict::kPattern_ResourceType,
+                        i, fShaderResources[i]);
             }
-            fResourceDict->insert("Pattern", patterns.get());
         }
-
-        // For compatibility, add all proc sets (only used for output to PS
-        // devices).
-        const char procs[][7] = {"PDF", "Text", "ImageB", "ImageC", "ImageI"};
-        SkAutoTUnref<SkPDFArray> procSets(new SkPDFArray());
-        procSets->reserve(SK_ARRAY_COUNT(procs));
-        for (size_t i = 0; i < SK_ARRAY_COUNT(procs); i++)
-            procSets->appendName(procs[i]);
-        fResourceDict->insert("ProcSet", procSets.get());
     }
     return fResourceDict;
 }
 
-void SkPDFDevice::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
-                               SkTSet<SkPDFObject*>* newResourceObjects,
-                               bool recursive) const {
-    // TODO: reserve not correct if we need to recursively explore.
-    newResourceObjects->setReserve(newResourceObjects->count() +
-                                   fGraphicStateResources.count() +
-                                   fXObjectResources.count() +
-                                   fFontResources.count() +
-                                   fShaderResources.count());
-    for (int i = 0; i < fGraphicStateResources.count(); i++) {
-        if (!knownResourceObjects.contains(fGraphicStateResources[i]) &&
-                !newResourceObjects->contains(fGraphicStateResources[i])) {
-            newResourceObjects->add(fGraphicStateResources[i]);
-            fGraphicStateResources[i]->ref();
-            if (recursive) {
-                fGraphicStateResources[i]->getResources(knownResourceObjects,
-                                                        newResourceObjects);
-            }
-        }
-    }
-    for (int i = 0; i < fXObjectResources.count(); i++) {
-        if (!knownResourceObjects.contains(fXObjectResources[i]) &&
-                !newResourceObjects->contains(fXObjectResources[i])) {
-            newResourceObjects->add(fXObjectResources[i]);
-            fXObjectResources[i]->ref();
-            if (recursive) {
-                fXObjectResources[i]->getResources(knownResourceObjects,
-                                                   newResourceObjects);
-            }
-        }
-    }
-    for (int i = 0; i < fFontResources.count(); i++) {
-        if (!knownResourceObjects.contains(fFontResources[i]) &&
-                !newResourceObjects->contains(fFontResources[i])) {
-            newResourceObjects->add(fFontResources[i]);
-            fFontResources[i]->ref();
-            if (recursive) {
-                fFontResources[i]->getResources(knownResourceObjects,
-                                                newResourceObjects);
-            }
-        }
-    }
-    for (int i = 0; i < fShaderResources.count(); i++) {
-        if (!knownResourceObjects.contains(fShaderResources[i]) &&
-                !newResourceObjects->contains(fShaderResources[i])) {
-            newResourceObjects->add(fShaderResources[i]);
-            fShaderResources[i]->ref();
-            if (recursive) {
-                fShaderResources[i]->getResources(knownResourceObjects,
-                                                  newResourceObjects);
-            }
-        }
-    }
-}
-
 const SkTDArray<SkPDFFont*>& SkPDFDevice::getFontResources() const {
     return fFontResources;
 }
@@ -1771,8 +1698,10 @@ void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID,
             contentEntry->fState.fTextSize != paint.getTextSize() ||
             !contentEntry->fState.fFont->hasGlyph(glyphID)) {
         int fontIndex = getFontResourceIndex(typeface, glyphID);
-        contentEntry->fContent.writeText("/F");
-        contentEntry->fContent.writeDecAsText(fontIndex);
+        contentEntry->fContent.writeText("/");
+        contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName(
+                SkPDFResourceDict::kFont_ResourceType,
+                fontIndex).c_str());
         contentEntry->fContent.writeText(" ");
         SkPDFScalar::Append(paint.getTextSize(), &contentEntry->fContent);
         contentEntry->fContent.writeText(" Tf\n");
index 884e6db..e78891a 100644 (file)
@@ -12,6 +12,7 @@
 #include "SkMatrix.h"
 #include "SkPDFCatalog.h"
 #include "SkPDFDevice.h"
+#include "SkPDFResourceDict.h"
 #include "SkPDFUtils.h"
 #include "SkStream.h"
 #include "SkTypes.h"
@@ -21,7 +22,8 @@ SkPDFFormXObject::SkPDFFormXObject(SkPDFDevice* device) {
     // of content, so reference or copy everything we need (content and
     // resources).
     SkTSet<SkPDFObject*> emptySet;
-    device->getResources(emptySet, &fResources, false);
+    SkPDFResourceDict* resourceDict = device->getResourceDict();
+    resourceDict->getResources(emptySet, &fResources, false);
 
     SkAutoTUnref<SkStream> content(device->content());
     setData(content.get());
@@ -29,7 +31,7 @@ SkPDFFormXObject::SkPDFFormXObject(SkPDFDevice* device) {
     insertName("Type", "XObject");
     insertName("Subtype", "Form");
     SkSafeUnref(this->insert("BBox", device->copyMediaBox()));
-    insert("Resources", device->getResourceDict());
+    insert("Resources", resourceDict);
 
     // We invert the initial transform and apply that to the xobject so that
     // it doesn't get applied twice. We can't just undo it because it's
index d940f41..f59b5d5 100644 (file)
@@ -10,6 +10,7 @@
 #include "SkPDFCatalog.h"
 #include "SkPDFDevice.h"
 #include "SkPDFPage.h"
+#include "SkPDFResourceDict.h"
 #include "SkStream.h"
 
 SkPDFPage::SkPDFPage(SkPDFDevice* content)
@@ -23,8 +24,9 @@ SkPDFPage::~SkPDFPage() {}
 void SkPDFPage::finalizePage(SkPDFCatalog* catalog, bool firstPage,
                              const SkTSet<SkPDFObject*>& knownResourceObjects,
                              SkTSet<SkPDFObject*>* newResourceObjects) {
+    SkPDFResourceDict* resourceDict = fDevice->getResourceDict();
     if (fContentStream.get() == NULL) {
-        insert("Resources", fDevice->getResourceDict());
+        insert("Resources", resourceDict);
         SkSafeUnref(this->insert("MediaBox", fDevice->copyMediaBox()));
         if (!SkToBool(catalog->getDocumentFlags() &
                       SkPDFDocument::kNoLinks_Flags)) {
@@ -39,7 +41,7 @@ void SkPDFPage::finalizePage(SkPDFCatalog* catalog, bool firstPage,
         insert("Contents", new SkPDFObjRef(fContentStream.get()))->unref();
     }
     catalog->addObject(fContentStream.get(), firstPage);
-    fDevice->getResources(knownResourceObjects, newResourceObjects, true);
+    resourceDict->getResources(knownResourceObjects, newResourceObjects, true);
 }
 
 off_t SkPDFPage::getPageSize(SkPDFCatalog* catalog, off_t fileOffset) {
diff --git a/src/pdf/SkPDFResourceDict.cpp b/src/pdf/SkPDFResourceDict.cpp
new file mode 100644 (file)
index 0000000..fa72013
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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 "SkPostConfig.h"
+
+SK_DEFINE_INST_COUNT(SkPDFResourceDict)
+
+// Sanity check that the values of enum SkPDFResourceType correspond to the
+// expected values as defined in the arrays below.
+// If these are failing, you may need to update the resource_type_prefixes
+// and resource_type_names arrays below.
+SK_COMPILE_ASSERT(SkPDFResourceDict::kExtGState_ResourceType == 0,
+                  resource_type_mismatch);
+SK_COMPILE_ASSERT(SkPDFResourceDict::kPattern_ResourceType == 1,
+                  resource_type_mismatch);
+SK_COMPILE_ASSERT(SkPDFResourceDict::kXObject_ResourceType == 2,
+                  resource_type_mismatch);
+SK_COMPILE_ASSERT(SkPDFResourceDict::kFont_ResourceType == 3,
+                  resource_type_mismatch);
+
+static const char resource_type_prefixes[] = {
+        'G',
+        'P',
+        'X',
+        'F'
+};
+
+static const char* resource_type_names[] = {
+        "ExtGState",
+        "Pattern",
+        "XObject",
+        "Font"
+};
+
+static char get_resource_type_prefix(
+        SkPDFResourceDict::SkPDFResourceType type) {
+    SkASSERT(type >= 0);
+    SkASSERT(type < SkPDFResourceDict::kResourceTypeCount);
+
+    return resource_type_prefixes[type];
+}
+
+static const char* get_resource_type_name(
+        SkPDFResourceDict::SkPDFResourceType type) {
+    SkASSERT(type >= 0);
+    SkASSERT(type < SkPDFResourceDict::kResourceTypeCount);
+
+    return resource_type_names[type];
+}
+
+SkPDFResourceDict::SkPDFResourceDict() : SkPDFDict() {
+    const char procs[][7] = {"PDF", "Text", "ImageB", "ImageC", "ImageI"};
+    SkPDFArray* procSets = SkNEW(SkPDFArray());
+
+    procSets->reserve(SK_ARRAY_COUNT(procs));
+    for (size_t i = 0; i < SK_ARRAY_COUNT(procs); i++) {
+        procSets->appendName(procs[i]);
+    }
+    insert("ProcSets", procSets)->unref();
+
+    // Actual sub-dicts will be lazily added later
+    fTypes.setCount(kResourceTypeCount);
+    for (size_t i=0; i < kResourceTypeCount; i++) {
+        fTypes[i] = NULL;
+    }
+}
+
+SkPDFObject* SkPDFResourceDict::insertResourceAsRef(
+        SkPDFResourceType type, int key, SkPDFObject* value) {
+    SkAutoTUnref<SkPDFObjRef> ref(SkNEW_ARGS(SkPDFObjRef, (value)));
+    insertResource(type, key, ref);
+    fResources.add(value);
+
+    return value;
+}
+
+void SkPDFResourceDict::getResources(
+        const SkTSet<SkPDFObject*>& knownResourceObjects,
+        SkTSet<SkPDFObject*>* newResourceObjects,
+        bool recursive) const {
+    // TODO: reserve not correct if we need to recursively explore.
+    newResourceObjects->setReserve(newResourceObjects->count() +
+                                   fResources.count());
+
+    for (int i = 0; i < fResources.count(); i++) {
+        if (!knownResourceObjects.contains(fResources[i]) &&
+                !newResourceObjects->contains(fResources[i])) {
+            newResourceObjects->add(fResources[i]);
+            fResources[i]->ref();
+            if (recursive) {
+                fResources[i]->getResources(knownResourceObjects,
+                                            newResourceObjects);
+            }
+        }
+    }
+}
+
+SkString SkPDFResourceDict::getResourceName(
+        SkPDFResourceType type, int key) {
+    SkString keyString;
+    keyString.printf("%c%d", get_resource_type_prefix(type), key);
+    return keyString;
+}
+
+SkPDFObject* SkPDFResourceDict::insertResource(
+        SkPDFResourceType type, int key, SkPDFObject* value) {
+    SkPDFDict* typeDict = fTypes[type];
+    if (NULL == typeDict) {
+        SkAutoTUnref<SkPDFDict> newDict(SkNEW(SkPDFDict()));
+        SkPDFName* typeName = SkNEW_ARGS(
+                SkPDFName, (get_resource_type_name(type)));
+        insert(typeName, newDict);  // ref counting handled here
+        fTypes[type] = newDict;
+        typeDict = newDict.get();
+    }
+
+    SkPDFName* keyName = SkNEW_ARGS(SkPDFName, (getResourceName(type, key)));
+    typeDict->insert(keyName, value);
+    return value;
+}
diff --git a/src/pdf/SkPDFResourceDict.h b/src/pdf/SkPDFResourceDict.h
new file mode 100644 (file)
index 0000000..0041679
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkPDFResourceDict_DEFINED
+#define SkPDFResourceDict_DEFINED
+
+#include "SkPDFTypes.h"
+#include "SkTDArray.h"
+#include "SkTSet.h"
+#include "SkTypes.h"
+
+/** \class SkPDFResourceDict
+
+    A resource dictionary, which maintains the relevant sub-dicts and
+    allows generation of a list of referenced SkPDFObjects inserted with
+    insertResourceAsRef.
+*/
+class SkPDFResourceDict : public SkPDFDict {
+public:
+    SK_DECLARE_INST_COUNT(SkPDFResourceDict)
+
+     enum SkPDFResourceType{
+        kExtGState_ResourceType,
+        kPattern_ResourceType,
+        kXObject_ResourceType,
+        kFont_ResourceType,
+        // These additional types are defined by the spec, but not
+        // currently used by Skia: ColorSpace, Shading, Properties
+        kResourceTypeCount
+     };
+
+    /** Create a PDF resource dictionary.
+     *  The full set of ProcSet entries is automatically created for backwards
+     *  compatibility, as recommended by the PDF spec.
+     */
+    SkPDFResourceDict();
+
+    /** Add the value SkPDFObject as a reference to the resource dictionary
+     *  with the give type and key.
+     *  The relevant sub-dicts will be automatically generated, and the
+     *  resource will be named by concatenating a type-specific prefix and
+     *  the input key.
+     *  This object will be part of the resource list when requested later.
+     *  @param type  The type of resource being entered, like
+     *    kPattern_ResourceType or kExtGState_ResourceType.
+     *  @param key   The resource key, should be unique within its type.
+     *  @param value The resource itself.
+     *  @return The value argument is returned.
+     */
+    SkPDFObject* insertResourceAsRef(SkPDFResourceType type, int key,
+                                     SkPDFObject* value);
+
+    /**
+     * Gets resources inserted into this dictionary.
+     *
+     * @param knownResourceObjects Set containing currently known resources.
+     *     Resources in the dict and this set will not be added to the output.
+     * @param newResourceObjects   Output set to which non-preexisting resources
+     *     will be added.
+     * @param recursive            Whether or not to add resources of resources.
+     */
+    void getResources(
+            const SkTSet<SkPDFObject*>& knownResourceObjects,
+            SkTSet<SkPDFObject*>* newResourceObjects,
+            bool recursive) const;
+
+    /**
+     * Returns the name for the resource that will be generated by the resource
+     * dict.
+     *
+     *  @param type  The type of resource being entered, like
+     *    kPattern_ResourceType or kExtGState_ResourceType.
+     *  @param key   The resource key, should be unique within its type.
+     */
+    static SkString getResourceName(SkPDFResourceType type, int key);
+
+private:
+    /** Add the value to the dictionary with the given key.  Refs value.
+     *  The relevant sub-dicts will be automatically generated, and the
+     *  resource will be named by concatenating a type-specific prefix and
+     *  the input key.
+     *  The object will NOT be part of the resource list when requested later.
+     *  @param type  The type of resource being entered.
+     *  @param key   The resource key, should be unique within its type.
+     *  @param value The resource itself.
+     *  @return The value argument is returned.
+     */
+    SkPDFObject* insertResource(SkPDFResourceType type, int key,
+                                SkPDFObject* value);
+
+    SkTSet<SkPDFObject*> fResources;
+
+    SkTDArray<SkPDFDict*> fTypes;
+};
+
+#endif
index a0dffb7..fec9d05 100644 (file)
@@ -14,6 +14,7 @@
 #include "SkPDFCatalog.h"
 #include "SkPDFDevice.h"
 #include "SkPDFTypes.h"
+#include "SkPDFResourceDict.h"
 #include "SkPDFUtils.h"
 #include "SkScalar.h"
 #include "SkStream.h"
@@ -838,7 +839,8 @@ SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) {
     // Put the canvas into the pattern stream (fContent).
     SkAutoTUnref<SkStream> content(pattern.content());
     setData(content.get());
-    pattern.getResources(fResources, &fResources, false);
+    SkPDFResourceDict* resourceDict = pattern.getResourceDict();
+    resourceDict->getResources(fResources, &fResources, false);
 
     insertName("Type", "Pattern");
     insertInt("PatternType", 1);
@@ -847,7 +849,7 @@ SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) {
     insert("BBox", patternBBoxArray.get());
     insertScalar("XStep", patternBBox.width());
     insertScalar("YStep", patternBBox.height());
-    insert("Resources", pattern.getResourceDict());
+    insert("Resources", resourceDict);
     insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref();
 
     fState.get()->fImage.unlockPixels();
index 90e2058..16abc2f 100644 (file)
@@ -11,6 +11,7 @@
 #include "SkGeometry.h"
 #include "SkPaint.h"
 #include "SkPath.h"
+#include "SkPDFResourceDict.h"
 #include "SkPDFUtils.h"
 #include "SkStream.h"
 #include "SkString.h"
@@ -206,14 +207,18 @@ void SkPDFUtils::StrokePath(SkWStream* content) {
 
 // static
 void SkPDFUtils::DrawFormXObject(int objectIndex, SkWStream* content) {
-    content->writeText("/X");
-    content->writeDecAsText(objectIndex);
+    content->writeText("/");
+    content->writeText(SkPDFResourceDict::getResourceName(
+            SkPDFResourceDict::kXObject_ResourceType,
+            objectIndex).c_str());
     content->writeText(" Do\n");
 }
 
 // static
 void SkPDFUtils::ApplyGraphicState(int objectIndex, SkWStream* content) {
-    content->writeText("/G");
-    content->writeDecAsText(objectIndex);
+    content->writeText("/");
+    content->writeText(SkPDFResourceDict::getResourceName(
+            SkPDFResourceDict::kExtGState_ResourceType,
+            objectIndex).c_str());
     content->writeText(" gs\n");
 }