diff options
author | vandebo@chromium.org <vandebo@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-03-22 20:45:15 +0000 |
---|---|---|
committer | vandebo@chromium.org <vandebo@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-03-22 20:45:15 +0000 |
commit | 7d6c8f997f8fe2c222f9d6d31f984c2e7cf16cc5 (patch) | |
tree | 95d8dc5cf623018c83ef2154f10b618c8990b4a0 /src/pdf | |
parent | 7c9594259bbf007bf6dab857544586f2327ea66e (diff) |
[PDF] Move most of the headers to be private.
Compute font stats in SkPDFDocument in order to make more of the headers private.
Previous review: https://codereview.appspot.com/5868049/
Review URL: https://codereview.appspot.com/5875049
git-svn-id: http://skia.googlecode.com/svn/trunk@3470 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/pdf')
-rw-r--r-- | src/pdf/SkPDFCatalog.h | 137 | ||||
-rw-r--r-- | src/pdf/SkPDFDocument.cpp | 22 | ||||
-rw-r--r-- | src/pdf/SkPDFFont.h | 202 | ||||
-rw-r--r-- | src/pdf/SkPDFFormXObject.h | 48 | ||||
-rw-r--r-- | src/pdf/SkPDFGraphicState.h | 101 | ||||
-rw-r--r-- | src/pdf/SkPDFImage.h | 70 | ||||
-rw-r--r-- | src/pdf/SkPDFPage.h | 100 | ||||
-rw-r--r-- | src/pdf/SkPDFShader.h | 65 | ||||
-rw-r--r-- | src/pdf/SkPDFStream.h | 75 | ||||
-rw-r--r-- | src/pdf/SkPDFTypes.h | 403 | ||||
-rw-r--r-- | src/pdf/SkPDFUtils.h | 54 |
11 files changed, 1274 insertions, 3 deletions
diff --git a/src/pdf/SkPDFCatalog.h b/src/pdf/SkPDFCatalog.h new file mode 100644 index 0000000000..44005c6784 --- /dev/null +++ b/src/pdf/SkPDFCatalog.h @@ -0,0 +1,137 @@ + +/* + * Copyright 2010 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPDFCatalog_DEFINED +#define SkPDFCatalog_DEFINED + +#include <sys/types.h> + +#include "SkPDFDocument.h" +#include "SkPDFTypes.h" +#include "SkRefCnt.h" +#include "SkTDArray.h" + +/** \class SkPDFCatalog + + The PDF catalog manages object numbers and file offsets. It is used + to create the PDF cross reference table. +*/ +class SkPDFCatalog { +public: + /** Create a PDF catalog. + */ + explicit SkPDFCatalog(SkPDFDocument::Flags flags); + ~SkPDFCatalog(); + + /** Add the passed object to the catalog. Refs obj. + * @param obj The object to add. + * @param onFirstPage Is the object on the first page. + * @return The obj argument is returned. + */ + SkPDFObject* addObject(SkPDFObject* obj, bool onFirstPage); + + /** Inform the catalog of the object's position in the final stream. + * The object should already have been added to the catalog. Returns + * the object's size. + * @param obj The object to add. + * @param offset The byte offset in the output stream of this object. + */ + size_t setFileOffset(SkPDFObject* obj, size_t offset); + + /** Output the object number for the passed object. + * @param obj The object of interest. + * @param stream The writable output stream to send the output to. + */ + void emitObjectNumber(SkWStream* stream, SkPDFObject* obj); + + /** Return the number of bytes that would be emitted for the passed + * object's object number. + * @param obj The object of interest + */ + size_t getObjectNumberSize(SkPDFObject* obj); + + /** Return the document flags in effect for this catalog/document. + */ + SkPDFDocument::Flags getDocumentFlags() const { return fDocumentFlags; } + + /** Output the cross reference table for objects in the catalog. + * Returns the total number of objects. + * @param stream The writable output stream to send the output to. + * @param firstPage If true, include first page objects only, otherwise + * include all objects not on the first page. + */ + int32_t emitXrefTable(SkWStream* stream, bool firstPage); + + /** Set substitute object for the passed object. + */ + void setSubstitute(SkPDFObject* original, SkPDFObject* substitute); + + /** Find and return any substitute object set for the passed object. If + * there is none, return the passed object. + */ + SkPDFObject* getSubstituteObject(SkPDFObject* object); + + /** Set file offsets for the resources of substitute objects. + * @param fileOffset Accumulated offset of current document. + * @param firstPage Indicate whether this is for the first page only. + * @return Total size of resources of substitute objects. + */ + off_t setSubstituteResourcesOffsets(off_t fileOffset, bool firstPage); + + /** Emit the resources of substitute objects. + */ + void emitSubstituteResources(SkWStream* stream, bool firstPage); + +private: + struct Rec { + Rec(SkPDFObject* object, bool onFirstPage) + : fObject(object), + fFileOffset(0), + fObjNumAssigned(false), + fOnFirstPage(onFirstPage) { + } + SkPDFObject* fObject; + off_t fFileOffset; + bool fObjNumAssigned; + bool fOnFirstPage; + }; + + struct SubstituteMapping { + SubstituteMapping(SkPDFObject* original, SkPDFObject* substitute) + : fOriginal(original), fSubstitute(substitute) { + } + SkPDFObject* fOriginal; + SkPDFObject* fSubstitute; + }; + + // TODO(vandebo): Make this a hash if it's a performance problem. + SkTDArray<struct Rec> fCatalog; + + // TODO(arthurhsu): Make this a hash if it's a performance problem. + SkTDArray<SubstituteMapping> fSubstituteMap; + SkTDArray<SkPDFObject*> fSubstituteResourcesFirstPage; + SkTDArray<SkPDFObject*> fSubstituteResourcesRemaining; + + // Number of objects on the first page. + uint32_t fFirstPageCount; + // Next object number to assign (on page > 1). + uint32_t fNextObjNum; + // Next object number to assign on the first page. + uint32_t fNextFirstPageObjNum; + + SkPDFDocument::Flags fDocumentFlags; + + int findObjectIndex(SkPDFObject* obj) const; + + int assignObjNum(SkPDFObject* obj); + + SkTDArray<SkPDFObject*>* getSubstituteList(bool firstPage); +}; + +#endif diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp index cb87d8fc74..3ec4877b98 100644 --- a/src/pdf/SkPDFDocument.cpp +++ b/src/pdf/SkPDFDocument.cpp @@ -10,8 +10,9 @@ #include "SkPDFCatalog.h" #include "SkPDFDevice.h" #include "SkPDFDocument.h" -#include "SkPDFPage.h" #include "SkPDFFont.h" +#include "SkPDFPage.h" +#include "SkPDFTypes.h" #include "SkStream.h" // Add the resources, starting at firstIndex to the catalog, removing any dupes. @@ -222,8 +223,23 @@ bool SkPDFDocument::appendPage(SkPDFDevice* pdfDevice) { return true; } -const SkTDArray<SkPDFPage*>& SkPDFDocument::getPages() { - return fPages; +void SkPDFDocument::getCountOfFontTypes( + int counts[SkAdvancedTypefaceMetrics::kNotEmbeddable_Font + 1]) const { + memset(counts, 0, + sizeof(int)* SkAdvancedTypefaceMetrics::kNotEmbeddable_Font + 1); + SkTDArray<SkFontID> seenFonts; + + for (int pageNumber = 0; pageNumber < fPages.count(); pageNumber++) { + const SkTDArray<SkPDFFont*>& fontResources = + fPages[pageNumber]->getFontResources(); + for (int font = 0; font < fontResources.count(); font++) { + SkFontID fontID = fontResources[font]->typeface()->uniqueID(); + if (seenFonts.find(fontID) == -1) { + counts[fontResources[font]->getType()]++; + seenFonts.push(fontID); + } + } + } } void SkPDFDocument::emitHeader(SkWStream* stream) { diff --git a/src/pdf/SkPDFFont.h b/src/pdf/SkPDFFont.h new file mode 100644 index 0000000000..f463ed740a --- /dev/null +++ b/src/pdf/SkPDFFont.h @@ -0,0 +1,202 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPDFFont_DEFINED +#define SkPDFFont_DEFINED + +#include "SkAdvancedTypefaceMetrics.h" +#include "SkBitSet.h" +#include "SkPDFTypes.h" +#include "SkTDArray.h" +#include "SkThread.h" +#include "SkTypeface.h" + +class SkPaint; +class SkPDFCatalog; +class SkPDFFont; + +class SkPDFGlyphSet : public SkNoncopyable { +public: + SkPDFGlyphSet(); + + void set(const uint16_t* glyphIDs, int numGlyphs); + bool has(uint16_t glyphID) const; + void merge(const SkPDFGlyphSet& usage); + void exportTo(SkTDArray<uint32_t>* glyphIDs) const; + +private: + SkBitSet fBitSet; +}; + +class SkPDFGlyphSetMap : public SkNoncopyable { +public: + struct FontGlyphSetPair { + FontGlyphSetPair(SkPDFFont* font, SkPDFGlyphSet* glyphSet); + + SkPDFFont* fFont; + SkPDFGlyphSet* fGlyphSet; + }; + + SkPDFGlyphSetMap(); + ~SkPDFGlyphSetMap(); + + class F2BIter { + public: + explicit F2BIter(const SkPDFGlyphSetMap& map); + FontGlyphSetPair* next() const; + void reset(const SkPDFGlyphSetMap& map); + + private: + const SkTDArray<FontGlyphSetPair>* fMap; + mutable int fIndex; + }; + + void merge(const SkPDFGlyphSetMap& usage); + void reset(); + + void noteGlyphUsage(SkPDFFont* font, const uint16_t* glyphIDs, + int numGlyphs); + +private: + SkPDFGlyphSet* getGlyphSetForFont(SkPDFFont* font); + + SkTDArray<FontGlyphSetPair> fMap; +}; + + +/** \class SkPDFFont + A PDF Object class representing a font. The font may have resources + attached to it in order to embed the font. SkPDFFonts are canonicalized + so that resource deduplication will only include one copy of a font. + This class uses the same pattern as SkPDFGraphicState, a static weak + reference to each instantiated class. +*/ +class SkPDFFont : public SkPDFDict { +public: + virtual ~SkPDFFont(); + + virtual void getResources(SkTDArray<SkPDFObject*>* resourceList); + + /** Returns the typeface represented by this class. Returns NULL for the + * default typeface. + */ + SkTypeface* typeface(); + + /** Returns the font type represented in this font. For Type0 fonts, + * returns the type of the decendant font. + */ + virtual SkAdvancedTypefaceMetrics::FontType getType(); + + /** Returns true if this font encoding supports glyph IDs above 255. + */ + virtual bool multiByteGlyphs() const = 0; + + /** Return true if this font has an encoding for the passed glyph id. + */ + bool hasGlyph(uint16_t glyphID); + + /** Convert (in place) the input glyph IDs into the font encoding. If the + * font has more glyphs than can be encoded (like a type 1 font with more + * than 255 glyphs) this method only converts up to the first out of range + * glyph ID. + * @param glyphIDs The input text as glyph IDs. + * @param numGlyphs The number of input glyphs. + * @return Returns the number of glyphs consumed. + */ + size_t glyphsToPDFFontEncoding(uint16_t* glyphIDs, size_t numGlyphs); + + /** Get the font resource for the passed typeface and glyphID. The + * reference count of the object is incremented and it is the caller's + * responsibility to unreference it when done. This is needed to + * accommodate the weak reference pattern used when the returned object + * is new and has no other references. + * @param typeface The typeface to find. + * @param glyphID Specify which section of a large font is of interest. + */ + static SkPDFFont* GetFontResource(SkTypeface* typeface, + uint16_t glyphID); + + /** Subset the font based on usage set. Returns a SkPDFFont instance with + * subset. + * @param usage Glyph subset requested. + * @return NULL if font does not support subsetting, a new instance + * of SkPDFFont otherwise. + */ + virtual SkPDFFont* getFontSubset(const SkPDFGlyphSet* usage); + +protected: + // Common constructor to handle common members. + SkPDFFont(SkAdvancedTypefaceMetrics* fontInfo, SkTypeface* typeface, + uint16_t glyphID, bool descendantFont); + + // Accessors for subclass. + SkAdvancedTypefaceMetrics* fontInfo(); + void setFontInfo(SkAdvancedTypefaceMetrics* info); + uint16_t firstGlyphID() const; + uint16_t lastGlyphID() const; + void setLastGlyphID(uint16_t glyphID); + + // Add object to resource list. + void addResource(SkPDFObject* object); + + // Accessors for FontDescriptor associated with this object. + SkPDFDict* getFontDescriptor(); + void setFontDescriptor(SkPDFDict* descriptor); + + // Add common entries to FontDescriptor. + bool addCommonFontDescriptorEntries(int16_t defaultWidth); + + /** Set fFirstGlyphID and fLastGlyphID to span at most 255 glyphs, + * including the passed glyphID. + */ + void adjustGlyphRangeForSingleByteEncoding(int16_t glyphID); + + // Generate ToUnicode table according to glyph usage subset. + // If subset is NULL, all available glyph ids will be used. + void populateToUnicodeTable(const SkPDFGlyphSet* subset); + + // Create instances of derived types based on fontInfo. + static SkPDFFont* Create(SkAdvancedTypefaceMetrics* fontInfo, + SkTypeface* typeface, uint16_t glyphID, + SkPDFDict* fontDescriptor); + + static bool Find(uint32_t fontID, uint16_t glyphID, int* index); + +private: + class FontRec { + public: + SkPDFFont* fFont; + uint32_t fFontID; + uint16_t fGlyphID; + + // A fGlyphID of 0 with no fFont always matches. + bool operator==(const FontRec& b) const; + FontRec(SkPDFFont* font, uint32_t fontID, uint16_t fGlyphID); + }; + + SkRefPtr<SkTypeface> fTypeface; + + // The glyph IDs accessible with this font. For Type1 (non CID) fonts, + // this will be a subset if the font has more than 255 glyphs. + uint16_t fFirstGlyphID; + uint16_t fLastGlyphID; + // The font info is only kept around after construction for large + // Type1 (non CID) fonts that need multiple "fonts" to access all glyphs. + SkRefPtr<SkAdvancedTypefaceMetrics> fFontInfo; + SkTDArray<SkPDFObject*> fResources; + SkRefPtr<SkPDFDict> fDescriptor; + + SkAdvancedTypefaceMetrics::FontType fFontType; + + // This should be made a hash table if performance is a problem. + static SkTDArray<FontRec>& CanonicalFonts(); + static SkBaseMutex& CanonicalFontsMutex(); +}; + +#endif diff --git a/src/pdf/SkPDFFormXObject.h b/src/pdf/SkPDFFormXObject.h new file mode 100644 index 0000000000..0c49152a1b --- /dev/null +++ b/src/pdf/SkPDFFormXObject.h @@ -0,0 +1,48 @@ + +/* + * Copyright 2010 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPDFFormXObject_DEFINED +#define SkPDFFormXObject_DEFINED + +#include "SkPDFStream.h" +#include "SkPDFTypes.h" +#include "SkRefCnt.h" +#include "SkString.h" + +class SkMatrix; +class SkPDFDevice; +class SkPDFCatalog; + +/** \class SkPDFFormXObject + + A form XObject; a self contained description of graphics objects. A form + XObject is basically a page object with slightly different syntax, that + can be drawn onto a page. +*/ + +// The caller could keep track of the form XObjects it creates and +// canonicalize them, but the Skia API doesn't provide enough context to +// automatically do it (trivially). +class SkPDFFormXObject : public SkPDFStream { +public: + /** Create a PDF form XObject. Entries for the dictionary entries are + * automatically added. + * @param device The set of graphical elements on this form. + */ + explicit SkPDFFormXObject(SkPDFDevice* device); + virtual ~SkPDFFormXObject(); + + // The SkPDFObject interface. + virtual void getResources(SkTDArray<SkPDFObject*>* resourceList); + +private: + SkTDArray<SkPDFObject*> fResources; +}; + +#endif diff --git a/src/pdf/SkPDFGraphicState.h b/src/pdf/SkPDFGraphicState.h new file mode 100644 index 0000000000..af01737276 --- /dev/null +++ b/src/pdf/SkPDFGraphicState.h @@ -0,0 +1,101 @@ + +/* + * Copyright 2010 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPDFGraphicState_DEFINED +#define SkPDFGraphicState_DEFINED + +#include "SkPaint.h" +#include "SkPDFTypes.h" +#include "SkTemplates.h" +#include "SkThread.h" + +class SkPDFFormXObject; + +/** \class SkPDFGraphicState + SkPaint objects roughly correspond to graphic state dictionaries that can + be installed. So that a given dictionary is only output to the pdf file + once, we want to canonicalize them. Static methods in this class manage + a weakly referenced set of SkPDFGraphicState objects: when the last + reference to a SkPDFGraphicState is removed, it removes itself from the + static set of objects. + +*/ +class SkPDFGraphicState : public SkPDFDict { +public: + virtual ~SkPDFGraphicState(); + + virtual void getResources(SkTDArray<SkPDFObject*>* resourceList); + + // Override emitObject and getOutputSize so that we can populate + // the dictionary on demand. + virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog, + bool indirect); + virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect); + + /** Get the graphic state for the passed SkPaint. The reference count of + * the object is incremented and it is the caller's responsibility to + * unreference it when done. This is needed to accommodate the weak + * reference pattern used when the returned object is new and has no + * other references. + * @param paint The SkPaint to emulate. + */ + static SkPDFGraphicState* GetGraphicStateForPaint(const SkPaint& paint); + + /** Make a graphic state that only sets the passed soft mask. The + * reference count of the object is incremented and it is the caller's + * responsibility to unreference it when done. + * @param sMask The form xobject to use as a soft mask. + * @param invert Indicates if the alpha of the sMask should be inverted. + */ + static SkPDFGraphicState* GetSMaskGraphicState(SkPDFFormXObject* sMask, + bool invert); + + /** Get a graphic state that only unsets the soft mask. The reference + * count of the object is incremented and it is the caller's responsibility + * to unreference it when done. This is needed to accommodate the weak + * reference pattern used when the returned object is new and has no + * other references. + */ + static SkPDFGraphicState* GetNoSMaskGraphicState(); + +private: + const SkPaint fPaint; + SkTDArray<SkPDFObject*> fResources; + bool fPopulated; + bool fSMask; + + class GSCanonicalEntry { + public: + SkPDFGraphicState* fGraphicState; + const SkPaint* fPaint; + + bool operator==(const GSCanonicalEntry& b) const; + explicit GSCanonicalEntry(SkPDFGraphicState* gs) + : fGraphicState(gs), + fPaint(&gs->fPaint) {} + explicit GSCanonicalEntry(const SkPaint* paint) + : fGraphicState(NULL), + fPaint(paint) {} + }; + + // This should be made a hash table if performance is a problem. + static SkTDArray<GSCanonicalEntry>& CanonicalPaints(); + static SkBaseMutex& CanonicalPaintsMutex(); + + SkPDFGraphicState(); + explicit SkPDFGraphicState(const SkPaint& paint); + + void populateDict(); + + static SkPDFObject* GetInvertFunction(); + + static int Find(const SkPaint& paint); +}; + +#endif diff --git a/src/pdf/SkPDFImage.h b/src/pdf/SkPDFImage.h new file mode 100644 index 0000000000..48b0157da9 --- /dev/null +++ b/src/pdf/SkPDFImage.h @@ -0,0 +1,70 @@ + +/* + * Copyright 2010 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPDFImage_DEFINED +#define SkPDFImage_DEFINED + +#include "SkPDFStream.h" +#include "SkPDFTypes.h" +#include "SkRefCnt.h" + +class SkBitmap; +class SkPaint; +class SkPDFCatalog; +struct SkIRect; + +/** \class SkPDFImage + + An image XObject. +*/ + +// We could play the same trick here as is done in SkPDFGraphicState, storing +// a copy of the Bitmap object (not the pixels), the pixel generation number, +// and settings used from the paint to canonicalize image objects. +class SkPDFImage : public SkPDFStream { +public: + /** Create a new Image XObject to represent the passed bitmap. + * @param bitmap The image to encode. + * @param srcRect The rectangle to cut out of bitmap. + * @param paint Used to calculate alpha, masks, etc. + * @return The image XObject or NUll if there is nothing to draw for + * the given parameters. + */ + static SkPDFImage* CreateImage(const SkBitmap& bitmap, + const SkIRect& srcRect, + const SkPaint& paint); + + virtual ~SkPDFImage(); + + /** Add a Soft Mask (alpha or shape channel) to the image. Refs mask. + * @param mask A gray scale image representing the mask. + * @return The mask argument is returned. + */ + SkPDFImage* addSMask(SkPDFImage* mask); + + // The SkPDFObject interface. + virtual void getResources(SkTDArray<SkPDFObject*>* resourceList); + +private: + SkTDArray<SkPDFObject*> fResources; + + /** Create a PDF image XObject. Entries for the image properties are + * automatically added to the stream dictionary. + * @param imageData The final raw bits representing the image. + * @param bitmap The image parameters to use (Config, etc). + * @param srcRect The clipping applied to bitmap before generating + * imageData. + * @param alpha Is this the alpha channel of the bitmap. + * @param paint Used to calculate alpha, masks, etc. + */ + SkPDFImage(SkStream* imageData, const SkBitmap& bitmap, + const SkIRect& srcRect, bool alpha, const SkPaint& paint); +}; + +#endif diff --git a/src/pdf/SkPDFPage.h b/src/pdf/SkPDFPage.h new file mode 100644 index 0000000000..8ef909e573 --- /dev/null +++ b/src/pdf/SkPDFPage.h @@ -0,0 +1,100 @@ + +/* + * Copyright 2010 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPDFPage_DEFINED +#define SkPDFPage_DEFINED + +#include "SkPDFTypes.h" +#include "SkPDFStream.h" +#include "SkRefCnt.h" +#include "SkTDArray.h" + +class SkPDFCatalog; +class SkPDFDevice; +class SkWStream; + +/** \class SkPDFPage + + A SkPDFPage contains meta information about a page, is used in the page + tree and points to the content of the page. +*/ +class SkPDFPage : public SkPDFDict { +public: + /** Create a PDF page with the passed PDF device. The device need not + * have content on it yet. + * @param content The page content. + */ + explicit SkPDFPage(SkPDFDevice* content); + ~SkPDFPage(); + + /** Before a page and its contents can be sized and emitted, it must + * be finalized. No changes to the PDFDevice will be honored after + * finalizePage has been called. This function adds the page content + * to the passed catalog, so it must be called for each document + * that the page is part of. + * @param catalog The catalog to add page content objects to. + * @param firstPage Indicate if this is the first page of a document. + * @param resourceObjects All the resource objects (recursively) used on + * the page are added to this array. This gives + * the caller a chance to deduplicate resources + * across pages. + */ + void finalizePage(SkPDFCatalog* catalog, bool firstPage, + SkTDArray<SkPDFObject*>* resourceObjects); + + /** Determine the size of the page content and store to the catalog + * the offsets of all nonresource-indirect objects that make up the page + * content. This must be called before emitPage(), but after finalizePage. + * @param catalog The catalog to add the object offsets to. + * @param fileOffset The file offset where the page content will be + * emitted. + */ + off_t getPageSize(SkPDFCatalog* catalog, off_t fileOffset); + + /** Output the page content to the passed stream. + * @param stream The writable output stream to send the content to. + * @param catalog The active object catalog. + */ + void emitPage(SkWStream* stream, SkPDFCatalog* catalog); + + /** Generate a page tree for the passed vector of pages. New objects are + * added to the catalog. The pageTree vector is populated with all of + * the 'Pages' dictionaries as well as the 'Page' objects. Page trees + * have both parent and children links, creating reference cycles, so + * it must be torn down explicitly. The first page is not added to + * the pageTree dictionary array so the caller can handle it specially. + * @param pages The ordered vector of page objects. + * @param catalog The catalog to add new objects into. + * @param pageTree An output vector with all of the internal and leaf + * nodes of the pageTree. + * @param rootNode An output parameter set to the root node. + */ + static void GeneratePageTree(const SkTDArray<SkPDFPage*>& pages, + SkPDFCatalog* catalog, + SkTDArray<SkPDFDict*>* pageTree, + SkPDFDict** rootNode); + + /** Get the fonts used on this page. + */ + const SkTDArray<SkPDFFont*>& getFontResources() const; + + /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font + * that shows on this page. + */ + const SkPDFGlyphSetMap& getFontGlyphUsage() const; + +private: + // Multiple pages may reference the content. + SkRefPtr<SkPDFDevice> fDevice; + + // Once the content is finalized, put it into a stream for output. + SkRefPtr<SkPDFStream> fContentStream; +}; + +#endif diff --git a/src/pdf/SkPDFShader.h b/src/pdf/SkPDFShader.h new file mode 100644 index 0000000000..439d83bbd5 --- /dev/null +++ b/src/pdf/SkPDFShader.h @@ -0,0 +1,65 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPDFShader_DEFINED +#define SkPDFShader_DEFINED + +#include "SkPDFStream.h" +#include "SkPDFTypes.h" +#include "SkMatrix.h" +#include "SkRefCnt.h" +#include "SkShader.h" + +class SkObjRef; +class SkPDFCatalog; + +/** \class SkPDFShader + + In PDF parlance, this is a pattern, used in place of a color when the + pattern color space is selected. +*/ + +class SkPDFShader { +public: + /** Get the PDF shader for the passed SkShader. If the SkShader is + * invalid in some way, returns NULL. The reference count of + * the object is incremented and it is the caller's responsibility to + * unreference it when done. This is needed to accommodate the weak + * reference pattern used when the returned object is new and has no + * other references. + * @param shader The SkShader to emulate. + * @param matrix The current transform. (PDF shaders are absolutely + * positioned, relative to where the page is drawn.) + * @param surfceBBox The bounding box of the drawing surface (with matrix + * already applied). + */ + static SkPDFObject* GetPDFShader(const SkShader& shader, + const SkMatrix& matrix, + const SkIRect& surfaceBBox); + +protected: + class State; + + class ShaderCanonicalEntry { + public: + ShaderCanonicalEntry(SkPDFObject* pdfShader, const State* state); + bool operator==(const ShaderCanonicalEntry& b) const; + + SkPDFObject* fPDFShader; + const State* fState; + }; + // This should be made a hash table if performance is a problem. + static SkTDArray<ShaderCanonicalEntry>& CanonicalShaders(); + static SkBaseMutex& CanonicalShadersMutex(); + static void RemoveShader(SkPDFObject* shader); + + SkPDFShader(); +}; + +#endif diff --git a/src/pdf/SkPDFStream.h b/src/pdf/SkPDFStream.h new file mode 100644 index 0000000000..b3a7ad34e3 --- /dev/null +++ b/src/pdf/SkPDFStream.h @@ -0,0 +1,75 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPDFStream_DEFINED +#define SkPDFStream_DEFINED + +#include "SkPDFTypes.h" +#include "SkRefCnt.h" +#include "SkStream.h" +#include "SkTemplates.h" + +class SkPDFCatalog; + +/** \class SkPDFStream + + A stream object in a PDF. Note, all streams must be indirect objects (via + SkObjRef). +*/ +class SkPDFStream : public SkPDFDict { +public: + /** Create a PDF stream. A Length entry is automatically added to the + * stream dictionary. The stream may be retained (stream->ref() may be + * called) so its contents must not be changed after calling this. + * @param data The data part of the stream. + */ + explicit SkPDFStream(SkData* data); + /** Deprecated constructor. */ + explicit SkPDFStream(SkStream* stream); + /** Create a PDF stream with the same content and dictionary entries + * as the passed one. + */ + explicit SkPDFStream(const SkPDFStream& pdfStream); + virtual ~SkPDFStream(); + + // The SkPDFObject interface. + virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog, + bool indirect); + virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect); + +protected: + /* Create a PDF stream with no data. The setData method must be called to + * set the data. + */ + SkPDFStream(); + + void setData(SkStream* stream); + +private: + enum State { + kUnused_State, //!< The stream hasn't been requested yet. + kNoCompression_State, //!< The stream's been requested in an + // uncompressed form. + kCompressed_State, //!< The stream's already been compressed. + }; + // Indicates what form (or if) the stream has been requested. + State fState; + + // TODO(vandebo): Use SkData (after removing deprecated constructor). + SkRefPtr<SkStream> fData; + SkRefPtr<SkPDFStream> fSubstitute; + + typedef SkPDFDict INHERITED; + + // Populate the stream dictionary. This method returns false if + // fSubstitute should be used. + bool populate(SkPDFCatalog* catalog); +}; + +#endif diff --git a/src/pdf/SkPDFTypes.h b/src/pdf/SkPDFTypes.h new file mode 100644 index 0000000000..6334938d77 --- /dev/null +++ b/src/pdf/SkPDFTypes.h @@ -0,0 +1,403 @@ + +/* + * Copyright 2010 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPDFTypes_DEFINED +#define SkPDFTypes_DEFINED + +#include "SkRefCnt.h" +#include "SkScalar.h" +#include "SkString.h" +#include "SkTDArray.h" +#include "SkTypes.h" + +class SkPDFCatalog; +class SkWStream; + +/** \class SkPDFObject + + A PDF Object is the base class for primitive elements in a PDF file. A + common subtype is used to ease the use of indirect object references, + which are common in the PDF format. +*/ +class SkPDFObject : public SkRefCnt { +public: + /** Create a PDF object. + */ + SkPDFObject(); + virtual ~SkPDFObject(); + + /** Return the size (number of bytes) of this object in the final output + * file. Compound objects or objects that are computationally intensive + * to output should override this method. + * @param catalog The object catalog to use. + * @param indirect If true, output an object identifier with the object. + */ + virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect); + + /** For non-primitive objects (i.e. objects defined outside this file), + * this method will add to resourceList any objects that this method + * depends on. This operates recursively so if this object depends on + * another object and that object depends on two more, all three objects + * will be added. + * @param resourceList The list to append dependant resources to. + */ + virtual void getResources(SkTDArray<SkPDFObject*>* resourceList); + + /** Emit this object unless the catalog has a substitute object, in which + * case emit that. + * @see emitObject + */ + void emit(SkWStream* stream, SkPDFCatalog* catalog, bool indirect); + + /** Helper function to output an indirect object. + * @param catalog The object catalog to use. + * @param stream The writable output stream to send the output to. + */ + void emitIndirectObject(SkWStream* stream, SkPDFCatalog* catalog); + + /** Helper function to find the size of an indirect object. + * @param catalog The object catalog to use. + */ + size_t getIndirectOutputSize(SkPDFCatalog* catalog); + + /** Static helper function to add a resource to a list. The list takes + * a reference. + * @param resource The resource to add. + * @param list The list to add the resource to. + */ + static void AddResourceHelper(SkPDFObject* resource, + SkTDArray<SkPDFObject*>* list); + + /** Static helper function to copy and reference the resources (and all + * their subresources) into a new list. + * @param resources The resource list. + * @param result The list to add to. + */ + static void GetResourcesHelper(SkTDArray<SkPDFObject*>* resources, + SkTDArray<SkPDFObject*>* result); + +protected: + /** Subclasses must implement this method to print the object to the + * PDF file. + * @param catalog The object catalog to use. + * @param indirect If true, output an object identifier with the object. + * @param stream The writable output stream to send the output to. + */ + virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog, + bool indirect) = 0; +}; + +/** \class SkPDFObjRef + + An indirect reference to a PDF object. +*/ +class SkPDFObjRef : public SkPDFObject { +public: + /** Create a reference to an existing SkPDFObject. + * @param obj The object to reference. + */ + explicit SkPDFObjRef(SkPDFObject* obj); + virtual ~SkPDFObjRef(); + + // The SkPDFObject interface. + virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog, + bool indirect); + virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect); + +private: + SkRefPtr<SkPDFObject> fObj; +}; + +/** \class SkPDFInt + + An integer object in a PDF. +*/ +class SkPDFInt : public SkPDFObject { +public: + /** Create a PDF integer (usually for indirect reference purposes). + * @param value An integer value between 2^31 - 1 and -2^31. + */ + explicit SkPDFInt(int32_t value); + virtual ~SkPDFInt(); + + // The SkPDFObject interface. + virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog, + bool indirect); + +private: + int32_t fValue; +}; + +/** \class SkPDFBool + + An boolean value in a PDF. +*/ +class SkPDFBool : public SkPDFObject { +public: + /** Create a PDF boolean. + * @param value true or false. + */ + explicit SkPDFBool(bool value); + virtual ~SkPDFBool(); + + // The SkPDFObject interface. + virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog, + bool indirect); + virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect); + +private: + bool fValue; +}; + +/** \class SkPDFScalar + + A real number object in a PDF. +*/ +class SkPDFScalar : public SkPDFObject { +public: + /** Create a PDF real number. + * @param value A real value. + */ + explicit SkPDFScalar(SkScalar value); + virtual ~SkPDFScalar(); + + static void Append(SkScalar value, SkWStream* stream); + + // The SkPDFObject interface. + virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog, + bool indirect); + +private: + SkScalar fValue; +}; + +/** \class SkPDFString + + A string object in a PDF. +*/ +class SkPDFString : public SkPDFObject { +public: + /** Create a PDF string. Maximum length (in bytes) is 65,535. + * @param value A string value. + */ + explicit SkPDFString(const char value[]); + explicit SkPDFString(const SkString& value); + + /** Create a PDF string. Maximum length (in bytes) is 65,535. + * @param value A string value. + * @param len The length of value. + * @param wideChars Indicates if the top byte in value is significant and + * should be encoded (true) or not (false). + */ + SkPDFString(const uint16_t* value, size_t len, bool wideChars); + virtual ~SkPDFString(); + + // The SkPDFObject interface. + virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog, + bool indirect); + virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect); + + static SkString FormatString(const char* input, size_t len); + static SkString FormatString(const uint16_t* input, size_t len, + bool wideChars); +private: + static const size_t kMaxLen = 65535; + + const SkString fValue; + + static SkString DoFormatString(const void* input, size_t len, + bool wideInput, bool wideOutput); +}; + +/** \class SkPDFName + + A name object in a PDF. +*/ +class SkPDFName : public SkPDFObject { +public: + /** Create a PDF name object. Maximum length is 127 bytes. + * @param value The name. + */ + explicit SkPDFName(const char name[]); + explicit SkPDFName(const SkString& name); + virtual ~SkPDFName(); + + bool operator==(const SkPDFName& b) const; + + // The SkPDFObject interface. + virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog, + bool indirect); + virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect); + +private: + static const size_t kMaxLen = 127; + + const SkString fValue; + + static SkString FormatName(const SkString& input); +}; + +/** \class SkPDFArray + + An array object in a PDF. +*/ +class SkPDFArray : public SkPDFObject { +public: + /** Create a PDF array. Maximum length is 8191. + */ + SkPDFArray(); + virtual ~SkPDFArray(); + + // The SkPDFObject interface. + virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog, + bool indirect); + virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect); + + /** The size of the array. + */ + int size() { return fValue.count(); } + + /** Preallocate space for the given number of entries. + * @param length The number of array slots to preallocate. + */ + void reserve(int length); + + /** Returns the object at the given offset in the array. + * @param index The index into the array to retrieve. + */ + SkPDFObject* getAt(int index) { return fValue[index]; } + + /** Set the object at the given offset in the array. Ref's value. + * @param index The index into the array to set. + * @param value The value to add to the array. + * @return The value argument is returned. + */ + SkPDFObject* setAt(int index, SkPDFObject* value); + + /** Append the object to the end of the array and increments its ref count. + * @param value The value to add to the array. + * @return The value argument is returned. + */ + SkPDFObject* append(SkPDFObject* value); + + /** Creates a SkPDFInt object and appends it to the array. + * @param value The value to add to the array. + */ + void appendInt(int32_t value); + + /** Creates a SkPDFScalar object and appends it to the array. + * @param value The value to add to the array. + */ + void appendScalar(SkScalar value); + + /** Creates a SkPDFName object and appends it to the array. + * @param value The value to add to the array. + */ + void appendName(const char name[]); + +private: + static const int kMaxLen = 8191; + SkTDArray<SkPDFObject*> fValue; +}; + +/** \class SkPDFDict + + A dictionary object in a PDF. +*/ +class SkPDFDict : public SkPDFObject { +public: + /** Create a PDF dictionary. Maximum number of entries is 4095. + */ + SkPDFDict(); + + /** Create a PDF dictionary with a Type entry. + * @param type The value of the Type entry. + */ + explicit SkPDFDict(const char type[]); + + virtual ~SkPDFDict(); + + // The SkPDFObject interface. + virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog, + bool indirect); + virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect); + + /** The size of the dictionary. + */ + int size() { return fValue.count(); } + + /** Add the value to the dictionary with the given key. Refs value. + * @param key The key for this dictionary entry. + * @param value The value for this dictionary entry. + * @return The value argument is returned. + */ + SkPDFObject* insert(SkPDFName* key, SkPDFObject* value); + + /** Add the value to the dictionary with the given key. Refs value. The + * method will create the SkPDFName object. + * @param key The text of the key for this dictionary entry. + * @param value The value for this dictionary entry. + * @return The value argument is returned. + */ + SkPDFObject* insert(const char key[], SkPDFObject* value); + + /** Add the int to the dictionary with the given key. + * @param key The text of the key for this dictionary entry. + * @param value The int value for this dictionary entry. + */ + void insertInt(const char key[], int32_t value); + + /** Add the scalar to the dictionary with the given key. + * @param key The text of the key for this dictionary entry. + * @param value The scalar value for this dictionary entry. + */ + void insertScalar(const char key[], SkScalar value); + + /** Add the name to the dictionary with the given key. + * @param key The text of the key for this dictionary entry. + * @param name The name for this dictionary entry. + */ + void insertName(const char key[], const char name[]); + + /** Add the name to the dictionary with the given key. + * @param key The text of the key for this dictionary entry. + * @param name The name for this dictionary entry. + */ + void insertName(const char key[], const SkString& name) { + this->insertName(key, name.c_str()); + } + + /** Remove all entries from the dictionary. + */ + void clear(); + +private: + struct Rec { + SkPDFName* key; + SkPDFObject* value; + }; + +public: + class Iter { + public: + explicit Iter(const SkPDFDict& dict); + SkPDFName* next(SkPDFObject** value); + + private: + Rec* fIter; + Rec* fStop; + }; + +private: + static const int kMaxLen = 4095; + + SkTDArray<struct Rec> fValue; +}; + +#endif diff --git a/src/pdf/SkPDFUtils.h b/src/pdf/SkPDFUtils.h new file mode 100644 index 0000000000..5b9d74e321 --- /dev/null +++ b/src/pdf/SkPDFUtils.h @@ -0,0 +1,54 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#ifndef SkPDFUtils_DEFINED +#define SkPDFUtils_DEFINED + +#include "SkPath.h" + +class SkMatrix; +class SkPath; +class SkPDFArray; +struct SkRect; + +#if 0 +#define PRINT_NOT_IMPL(str) fprintf(stderr, str) +#else +#define PRINT_NOT_IMPL(str) +#endif + +#define NOT_IMPLEMENTED(condition, assert) \ + do { \ + if (condition) { \ + PRINT_NOT_IMPL("NOT_IMPLEMENTED: " #condition "\n"); \ + SkDEBUGCODE(SkASSERT(!assert);) \ + } \ + } while (0) + +class SkPDFUtils { +public: + static SkPDFArray* MatrixToArray(const SkMatrix& matrix); + static void AppendTransform(const SkMatrix& matrix, SkWStream* content); + + static void MoveTo(SkScalar x, SkScalar y, SkWStream* content); + static void AppendLine(SkScalar x, SkScalar y, SkWStream* content); + static void AppendCubic(SkScalar ctl1X, SkScalar ctl1Y, + SkScalar ctl2X, SkScalar ctl2Y, + SkScalar dstX, SkScalar dstY, SkWStream* content); + static void AppendRectangle(const SkRect& rect, SkWStream* content); + static void EmitPath(const SkPath& path, SkWStream* content); + static void ClosePath(SkWStream* content); + static void PaintPath(SkPaint::Style style, SkPath::FillType fill, + SkWStream* content); + static void StrokePath(SkWStream* content); + static void DrawFormXObject(int objectIndex, SkWStream* content); + static void ApplyGraphicState(int objectIndex, SkWStream* content); +}; + +#endif |