summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvandebo@chromium.org <vandebo@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-07-23 20:22:53 +0000
committervandebo@chromium.org <vandebo@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-07-23 20:22:53 +0000
commitb89adda612508bba835a9bad692549a670912e4c (patch)
treefef31987c254f7988b05a62df1987e30ffcb4f10
parent5429fd61245d67509e80d5c820d3a9de0ef964ae (diff)
downloadsrc-b89adda612508bba835a9bad692549a670912e4c.tar.gz
[PDF] Refactor SkPDFFont to enable font/cmap subsetting.
Patch from Arthur Hsu, original CL: http://codereview.appspot.com/4633050/ Review URL: http://codereview.appspot.com/4811049 git-svn-id: http://skia.googlecode.com/svn/trunk/src@1943 2bbb7eff-a529-9590-31e7-b0007b416f81
-rwxr-xr-xpdf/SkBitSet.cpp4
-rw-r--r--pdf/SkPDFDevice.cpp31
-rw-r--r--pdf/SkPDFDocument.cpp28
-rw-r--r--[-rwxr-xr-x]pdf/SkPDFFont.cpp776
-rwxr-xr-xpdf/SkPDFFontImpl.h90
-rw-r--r--pdf/SkPDFPage.cpp4
6 files changed, 644 insertions, 289 deletions
diff --git a/pdf/SkBitSet.cpp b/pdf/SkBitSet.cpp
index f19dd69a..c7af832b 100755
--- a/pdf/SkBitSet.cpp
+++ b/pdf/SkBitSet.cpp
@@ -73,12 +73,12 @@ void SkBitSet::setBit(int index, bool value) {
}
}
-bool SkBitSet::isBitSet(int index) {
+bool SkBitSet::isBitSet(int index) const {
uint32_t mask = 1 << (index % 32);
return (*internalGet(index) & mask);
}
-bool SkBitSet::orBits(SkBitSet& source) {
+bool SkBitSet::orBits(const SkBitSet& source) {
if (fBitCount != source.fBitCount) {
return false;
}
diff --git a/pdf/SkPDFDevice.cpp b/pdf/SkPDFDevice.cpp
index 619d55d4..e2dfba69 100644
--- a/pdf/SkPDFDevice.cpp
+++ b/pdf/SkPDFDevice.cpp
@@ -424,8 +424,8 @@ void GraphicStackState::updateDrawingState(const GraphicStateEntry& state) {
}
}
-SkDevice* SkPDFDevice::onCreateCompatibleDevice(SkBitmap::Config config,
- int width, int height,
+SkDevice* SkPDFDevice::onCreateCompatibleDevice(SkBitmap::Config config,
+ int width, int height,
bool isOpaque,
Usage usage) {
SkMatrix initialTransform;
@@ -544,7 +544,7 @@ SkPDFDevice::SkPDFDevice(const SkISize& layerSize,
}
SkPDFDevice::~SkPDFDevice() {
- this->cleanUp();
+ this->cleanUp(true);
}
void SkPDFDevice::init() {
@@ -553,18 +553,24 @@ void SkPDFDevice::init() {
fLastContentEntry = NULL;
fMarginContentEntries.reset();
fLastMarginContentEntry = NULL;
- fDrawingArea = kContent_DrawingArea;
+ fDrawingArea = kContent_DrawingArea;
+ if (fFontGlyphUsage == NULL) {
+ fFontGlyphUsage.reset(new SkPDFGlyphSetMap());
+ }
}
-void SkPDFDevice::cleanUp() {
+void SkPDFDevice::cleanUp(bool clearFontUsage) {
fGraphicStateResources.unrefAll();
fXObjectResources.unrefAll();
fFontResources.unrefAll();
fShaderResources.unrefAll();
+ if (clearFontUsage) {
+ fFontGlyphUsage->reset();
+ }
}
void SkPDFDevice::clear(SkColor color) {
- this->cleanUp();
+ this->cleanUp(true);
this->init();
SkPaint paint;
@@ -825,6 +831,8 @@ void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
size_t availableGlyphs =
font->glyphsToPDFFontEncoding(glyphIDs + consumedGlyphCount,
numGlyphs - consumedGlyphCount);
+ fFontGlyphUsage->noteGlyphUsage(font, glyphIDs + consumedGlyphCount,
+ availableGlyphs);
SkString encodedString =
SkPDFString::FormatString(glyphIDs + consumedGlyphCount,
availableGlyphs, font->multiByteGlyphs());
@@ -893,6 +901,7 @@ void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
i--;
continue;
}
+ fFontGlyphUsage->noteGlyphUsage(font, &encodedValue, 1);
SkScalar x = pos[i * scalarsPerPos];
SkScalar y = scalarsPerPos == 1 ? constY : pos[i * scalarsPerPos + 1];
align_text(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y, NULL);
@@ -952,6 +961,9 @@ void SkPDFDevice::drawDevice(const SkDraw& d, SkDevice* device, int x, int y,
fXObjectResources.push(xobject); // Transfer reference.
SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
&content.entry()->fContent);
+
+ // Merge glyph sets from the drawn device.
+ fFontGlyphUsage->merge(pdfDevice->getFontGlyphUsage());
}
ContentEntry* SkPDFDevice::getLastContentEntry() {
@@ -1142,7 +1154,7 @@ SkData* SkPDFDevice::copyContentToData() const {
SkRect r = SkRect::MakeWH(this->width(), this->height());
emit_clip(NULL, &r, &data);
}
-
+
SkPDFDevice::copyContentEntriesToData(fContentEntries.get(), &data);
// potentially we could cache this SkData, and only rebuild it if we
@@ -1154,7 +1166,10 @@ void SkPDFDevice::createFormXObjectFromDevice(
SkRefPtr<SkPDFFormXObject>* xobject) {
*xobject = new SkPDFFormXObject(this);
(*xobject)->unref(); // SkRefPtr and new both took a reference.
- cleanUp(); // Reset this device to have no content.
+ // We always draw the form xobjects that we create back into the device, so
+ // we simply preserve the font usage instead of pulling it out and merging
+ // it back in later.
+ cleanUp(false); // Reset this device to have no content.
init();
}
diff --git a/pdf/SkPDFDocument.cpp b/pdf/SkPDFDocument.cpp
index 71c3784c..38f4f329 100644
--- a/pdf/SkPDFDocument.cpp
+++ b/pdf/SkPDFDocument.cpp
@@ -18,6 +18,7 @@
#include "SkPDFDevice.h"
#include "SkPDFDocument.h"
#include "SkPDFPage.h"
+#include "SkPDFFont.h"
#include "SkStream.h"
// Add the resources, starting at firstIndex to the catalog, removing any dupes.
@@ -37,6 +38,29 @@ void addResourcesToCatalog(int firstIndex, bool firstPage,
}
}
+static void perform_font_subsetting(SkPDFCatalog* catalog,
+ const SkTDArray<SkPDFPage*>& pages,
+ SkTDArray<SkPDFObject*>* substitutes) {
+ SkASSERT(catalog);
+ SkASSERT(substitutes);
+
+ SkPDFGlyphSetMap usage;
+ for (int i = 0; i < pages.count(); ++i) {
+ usage.merge(pages[i]->getFontGlyphUsage());
+ }
+ SkPDFGlyphSetMap::F2BIter iterator(usage);
+ SkPDFGlyphSetMap::FontGlyphSetPair* entry = iterator.next();
+ while (entry) {
+ SkPDFFont* subsetFont =
+ entry->fFont->getFontSubset(entry->fGlyphSet);
+ if (subsetFont) {
+ catalog->setSubstitute(entry->fFont, subsetFont);
+ substitutes->push(subsetFont); // Transfer ownership to substitutes
+ }
+ entry = iterator.next();
+ }
+}
+
SkPDFDocument::SkPDFDocument(Flags flags)
: fXRefFileOffset(0),
fSecondPageFirstResourceIndex(0) {
@@ -55,6 +79,7 @@ SkPDFDocument::~SkPDFDocument() {
fPageTree[i]->clear();
fPageTree.safeUnrefAll();
fPageResources.safeUnrefAll();
+ fSubstitutes.safeUnrefAll();
}
bool SkPDFDocument::emitPDF(SkWStream* stream) {
@@ -98,6 +123,9 @@ bool SkPDFDocument::emitPDF(SkWStream* stream) {
}
}
+ // Build font subsetting info before proceeding.
+ perform_font_subsetting(fCatalog.get(), fPages, &fSubstitutes);
+
// Figure out the size of things and inform the catalog of file offsets.
off_t fileOffset = headerSize();
fileOffset += fCatalog->setFileOffset(fDocCatalog.get(), fileOffset);
diff --git a/pdf/SkPDFFont.cpp b/pdf/SkPDFFont.cpp
index be16c769..f50580a4 100755..100644
--- a/pdf/SkPDFFont.cpp
+++ b/pdf/SkPDFFont.cpp
@@ -20,8 +20,10 @@
#include "SkFontHost.h"
#include "SkGlyphCache.h"
#include "SkPaint.h"
+#include "SkPDFCatalog.h"
#include "SkPDFDevice.h"
#include "SkPDFFont.h"
+#include "SkPDFFontImpl.h"
#include "SkPDFStream.h"
#include "SkPDFTypes.h"
#include "SkPDFUtils.h"
@@ -34,6 +36,10 @@
namespace {
+///////////////////////////////////////////////////////////////////////////////
+// File-Local Functions
+///////////////////////////////////////////////////////////////////////////////
+
bool parsePFBSection(const uint8_t** src, size_t* len, int sectionType,
size_t* size) {
// PFB sections have a two or six bytes header. 0x80 and a one byte
@@ -134,7 +140,7 @@ int8_t hexToBin(uint8_t c) {
SkStream* handleType1Stream(SkStream* srcStream, size_t* headerLen,
size_t* dataLen, size_t* trailerLen) {
- // srcStream may be backed by a file or a unseekable fd, so we may not be
+ // srcStream may be backed by a file or a unseekable fd, so we may not be
// able to use skip(), rewind(), or getMemoryBase(). read()ing through
// the input only once is doable, but very ugly. Furthermore, it'd be nice
// if the data was NUL terminated so that we can use strstr() to search it.
@@ -385,14 +391,14 @@ static void append_cmap_footer(SkDynamicMemoryWStream* cmap) {
// Generate <bfchar> table according to PDF spec 1.4 and Adobe Technote 5014.
static void append_cmap_bfchar_sections(
const SkTDArray<SkUnichar>& glyphUnicode,
- SkDynamicMemoryWStream* cmap) {
+ const SkPDFGlyphSet* subset, SkDynamicMemoryWStream* cmap) {
// PDF spec defines that every bf* list can have at most 100 entries.
const size_t kMaxEntries = 100;
uint16_t glyphId[kMaxEntries];
SkUnichar unicode[kMaxEntries];
size_t index = 0;
for (int i = 0; i < glyphUnicode.count(); i++) {
- if (glyphUnicode[i]) {
+ if (glyphUnicode[i] && (subset == NULL || subset->has(i))) {
glyphId[index] = i;
unicode[index] = glyphUnicode[i];
++index;
@@ -408,6 +414,112 @@ static void append_cmap_bfchar_sections(
}
}
+static SkPDFStream* generate_tounicode_cmap(
+ const SkTDArray<SkUnichar>& glyphUnicode,
+ const SkPDFGlyphSet* subset) {
+ SkDynamicMemoryWStream cmap;
+ append_tounicode_header(&cmap);
+ append_cmap_bfchar_sections(glyphUnicode, subset, &cmap);
+ append_cmap_footer(&cmap);
+ SkRefPtr<SkMemoryStream> cmapStream = new SkMemoryStream();
+ cmapStream->unref(); // SkRefPtr and new took a reference.
+ cmapStream->setData(cmap.copyToData());
+ return new SkPDFStream(cmapStream.get());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// class SkPDFGlyphSet
+///////////////////////////////////////////////////////////////////////////////
+
+SkPDFGlyphSet::SkPDFGlyphSet() : fBitSet(SK_MaxU16 + 1) {
+}
+
+void SkPDFGlyphSet::set(const uint16_t* glyphIDs, int numGlyphs) {
+ for (int i = 0; i < numGlyphs; ++i) {
+ fBitSet.setBit(glyphIDs[i], true);
+ }
+}
+
+bool SkPDFGlyphSet::has(uint16_t glyphID) const {
+ return fBitSet.isBitSet(glyphID);
+}
+
+void SkPDFGlyphSet::merge(const SkPDFGlyphSet& usage) {
+ fBitSet.orBits(usage.fBitSet);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// class SkPDFGlyphSetMap
+///////////////////////////////////////////////////////////////////////////////
+SkPDFGlyphSetMap::FontGlyphSetPair::FontGlyphSetPair(SkPDFFont* font,
+ SkPDFGlyphSet* glyphSet)
+ : fFont(font),
+ fGlyphSet(glyphSet) {
+}
+
+SkPDFGlyphSetMap::F2BIter::F2BIter(const SkPDFGlyphSetMap& map) {
+ reset(map);
+}
+
+SkPDFGlyphSetMap::FontGlyphSetPair* SkPDFGlyphSetMap::F2BIter::next() const {
+ if (fIndex >= fMap->count()) {
+ return NULL;
+ }
+ return &((*fMap)[fIndex++]);
+}
+
+void SkPDFGlyphSetMap::F2BIter::reset(const SkPDFGlyphSetMap& map) {
+ fMap = &(map.fMap);
+ fIndex = 0;
+}
+
+SkPDFGlyphSetMap::SkPDFGlyphSetMap() {
+}
+
+SkPDFGlyphSetMap::~SkPDFGlyphSetMap() {
+ reset();
+}
+
+void SkPDFGlyphSetMap::merge(const SkPDFGlyphSetMap& usage) {
+ for (int i = 0; i < usage.fMap.count(); ++i) {
+ SkPDFGlyphSet* myUsage = getGlyphSetForFont(usage.fMap[i].fFont);
+ myUsage->merge(*(usage.fMap[i].fGlyphSet));
+ }
+}
+
+void SkPDFGlyphSetMap::reset() {
+ for (int i = 0; i < fMap.count(); ++i) {
+ delete fMap[i].fGlyphSet; // Should not be NULL.
+ }
+ fMap.reset();
+}
+
+void SkPDFGlyphSetMap::noteGlyphUsage(SkPDFFont* font, const uint16_t* glyphIDs,
+ int numGlyphs) {
+ SkPDFGlyphSet* subset = getGlyphSetForFont(font);
+ if (subset) {
+ subset->set(glyphIDs, numGlyphs);
+ }
+}
+
+SkPDFGlyphSet* SkPDFGlyphSetMap::getGlyphSetForFont(SkPDFFont* font) {
+ int index = fMap.count();
+ for (int i = 0; i < index; ++i) {
+ if (fMap[i].fFont == font) {
+ return fMap[i].fGlyphSet;
+ }
+ }
+ fMap.append();
+ index = fMap.count() - 1;
+ fMap[index].fFont = font;
+ fMap[index].fGlyphSet = new SkPDFGlyphSet();
+ return fMap[index].fGlyphSet;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// class SkPDFFont
+///////////////////////////////////////////////////////////////////////////////
+
/* Font subset design: It would be nice to be able to subset fonts
* (particularly type 3 fonts), but it's a lot of work and not a priority.
*
@@ -425,11 +537,6 @@ SkPDFFont::~SkPDFFont() {
int index;
if (Find(SkTypeface::UniqueID(fTypeface.get()), fFirstGlyphID, &index)) {
CanonicalFonts().removeShuffle(index);
-#ifdef SK_DEBUG
- SkASSERT(!fDescendant);
- } else {
- SkASSERT(fDescendant);
-#endif
}
fResources.unrefAll();
}
@@ -443,21 +550,17 @@ SkTypeface* SkPDFFont::typeface() {
}
SkAdvancedTypefaceMetrics::FontType SkPDFFont::getType() {
- return fType;
+ return fFontType;
}
bool SkPDFFont::hasGlyph(uint16_t id) {
return (id >= fFirstGlyphID && id <= fLastGlyphID) || id == 0;
}
-bool SkPDFFont::multiByteGlyphs() {
- return fMultiByteGlyphs;
-}
-
size_t SkPDFFont::glyphsToPDFFontEncoding(uint16_t* glyphIDs,
size_t numGlyphs) {
// A font with multibyte glyphs will support all glyph IDs in a single font.
- if (fMultiByteGlyphs) {
+ if (this->multiByteGlyphs()) {
return numGlyphs;
}
@@ -478,19 +581,19 @@ size_t SkPDFFont::glyphsToPDFFontEncoding(uint16_t* glyphIDs,
SkPDFFont* SkPDFFont::GetFontResource(SkTypeface* typeface, uint16_t glyphID) {
SkAutoMutexAcquire lock(CanonicalFontsMutex());
const uint32_t fontID = SkTypeface::UniqueID(typeface);
- int index;
- if (Find(fontID, glyphID, &index)) {
- CanonicalFonts()[index].fFont->ref();
- return CanonicalFonts()[index].fFont;
+ int relatedFontIndex;
+ if (Find(fontID, glyphID, &relatedFontIndex)) {
+ CanonicalFonts()[relatedFontIndex].fFont->ref();
+ return CanonicalFonts()[relatedFontIndex].fFont;
}
- SkRefPtr<SkAdvancedTypefaceMetrics> fontInfo;
- SkPDFDict* fontDescriptor = NULL;
- if (index >= 0) {
- SkPDFFont* relatedFont = CanonicalFonts()[index].fFont;
+ SkRefPtr<SkAdvancedTypefaceMetrics> fontMetrics;
+ SkPDFDict* relatedFontDescriptor = NULL;
+ if (relatedFontIndex >= 0) {
+ SkPDFFont* relatedFont = CanonicalFonts()[relatedFontIndex].fFont;
SkASSERT(relatedFont->fFontInfo.get());
- fontInfo = relatedFont->fFontInfo;
- fontDescriptor = relatedFont->fDescriptor.get();
+ fontMetrics = relatedFont->fontInfo();
+ relatedFontDescriptor = relatedFont->getFontDescriptor();
} else {
SkAdvancedTypefaceMetrics::PerGlyphInfo info;
info = SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo;
@@ -498,18 +601,21 @@ SkPDFFont* SkPDFFont::GetFontResource(SkTypeface* typeface, uint16_t glyphID) {
info, SkAdvancedTypefaceMetrics::kGlyphNames_PerGlyphInfo);
info = SkTBitOr<SkAdvancedTypefaceMetrics::PerGlyphInfo>(
info, SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo);
- fontInfo = SkFontHost::GetAdvancedTypefaceMetrics(fontID, info);
- SkSafeUnref(fontInfo.get()); // SkRefPtr and Get both took a reference.
+ fontMetrics = SkFontHost::GetAdvancedTypefaceMetrics(fontID, info);
+ SkSafeUnref(fontMetrics.get()); // SkRefPtr and Get both took a ref.
}
- SkPDFFont* font = new SkPDFFont(fontInfo.get(), typeface, glyphID, false,
- fontDescriptor);
+ SkPDFFont* font = Create(fontMetrics.get(), typeface, glyphID,
+ relatedFontDescriptor);
FontRec newEntry(font, fontID, font->fFirstGlyphID);
- index = CanonicalFonts().count();
CanonicalFonts().push(newEntry);
return font; // Return the reference new SkPDFFont() created.
}
+SkPDFFont* SkPDFFont::getFontSubset(const SkPDFGlyphSet* usage) {
+ return NULL; // Default: no support.
+}
+
// static
SkTDArray<SkPDFFont::FontRec>& SkPDFFont::CanonicalFonts() {
// This initialization is only thread safe with gcc.
@@ -536,96 +642,270 @@ bool SkPDFFont::Find(uint32_t fontID, uint16_t glyphID, int* index) {
return false;
}
-SkPDFFont::SkPDFFont(class SkAdvancedTypefaceMetrics* fontInfo,
- SkTypeface* typeface,
- uint16_t glyphID,
- bool descendantFont,
- SkPDFDict* fontDescriptor)
+SkPDFFont::SkPDFFont(SkAdvancedTypefaceMetrics* info, SkTypeface* typeface,
+ uint16_t glyphID, bool descendantFont)
: SkPDFDict("Font"),
fTypeface(typeface),
- fType(fontInfo ? fontInfo->fType :
- SkAdvancedTypefaceMetrics::kNotEmbeddable_Font),
-#ifdef SK_DEBUG
- fDescendant(descendantFont),
-#endif
- fMultiByteGlyphs(false),
fFirstGlyphID(1),
- fLastGlyphID(fontInfo ? fontInfo->fLastGlyphID : 0),
- fFontInfo(fontInfo),
- fDescriptor(fontDescriptor) {
- if (fontInfo && fontInfo->fMultiMaster) {
+ fLastGlyphID(info ? info->fLastGlyphID : 0),
+ fFontInfo(info) {
+ if (info == NULL) {
+ fFontType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
+ } else if (info->fMultiMaster) {
+ fFontType = SkAdvancedTypefaceMetrics::kOther_Font;
+ } else {
+ fFontType = info->fType;
+ }
+}
+
+// static
+SkPDFFont* SkPDFFont::Create(SkAdvancedTypefaceMetrics* info,
+ SkTypeface* typeface, uint16_t glyphID,
+ SkPDFDict* relatedFontDescriptor) {
+ SkAdvancedTypefaceMetrics::FontType type =
+ info ? info->fType : SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
+
+ if (info && info->fMultiMaster) {
NOT_IMPLEMENTED(true, true);
- fType = SkAdvancedTypefaceMetrics::kOther_Font;
+ return new SkPDFType3Font(info,
+ typeface,
+ glyphID,
+ relatedFontDescriptor);
}
- if (fType == SkAdvancedTypefaceMetrics::kType1CID_Font ||
- fType == SkAdvancedTypefaceMetrics::kTrueType_Font) {
- if (descendantFont) {
- populateCIDFont();
- } else {
- populateType0Font();
- }
- // No need to hold onto the font info for fonts types that
- // support multibyte glyphs.
- fFontInfo = NULL;
- return;
+ if (type == SkAdvancedTypefaceMetrics::kType1CID_Font ||
+ type == SkAdvancedTypefaceMetrics::kTrueType_Font) {
+ SkASSERT(relatedFontDescriptor == NULL);
+ return new SkPDFType0Font(info, typeface);
+ }
+ if (type == SkAdvancedTypefaceMetrics::kType1_Font) {
+ return new SkPDFType1Font(info,
+ typeface,
+ glyphID,
+ relatedFontDescriptor);
+ }
+
+ SkASSERT(type == SkAdvancedTypefaceMetrics::kCFF_Font ||
+ type == SkAdvancedTypefaceMetrics::kOther_Font ||
+ type == SkAdvancedTypefaceMetrics::kNotEmbeddable_Font);
+
+ return new SkPDFType3Font(info, typeface, glyphID, relatedFontDescriptor);
+}
+
+SkAdvancedTypefaceMetrics* SkPDFFont::fontInfo() {
+ return fFontInfo.get();
+}
+
+uint16_t SkPDFFont::firstGlyphID() const {
+ return fFirstGlyphID;
+}
+
+uint16_t SkPDFFont::lastGlyphID() const {
+ return fLastGlyphID;
+}
+
+void SkPDFFont::setLastGlyphID(uint16_t glyphID) {
+ fLastGlyphID = glyphID;
+}
+
+void SkPDFFont::addResource(SkPDFObject* object) {
+ SkASSERT(object != NULL);
+ fResources.push(object);
+}
+
+SkPDFDict* SkPDFFont::getFontDescriptor() {
+ return fDescriptor.get();
+}
+
+void SkPDFFont::setFontDescriptor(SkPDFDict* descriptor) {
+ fDescriptor = descriptor;
+}
+
+bool SkPDFFont::addCommonFontDescriptorEntries(int16_t defaultWidth) {
+ if (fDescriptor.get() == NULL) {
+ return false;
+ }
+
+ const uint16_t emSize = fFontInfo->fEmSize;
+
+ fDescriptor->insertName("FontName", fFontInfo->fFontName);
+ fDescriptor->insertInt("Flags", fFontInfo->fStyle);
+ fDescriptor->insertScalar("Ascent",
+ scaleFromFontUnits(fFontInfo->fAscent, emSize));
+ fDescriptor->insertScalar("Descent",
+ scaleFromFontUnits(fFontInfo->fDescent, emSize));
+ fDescriptor->insertScalar("StemV",
+ scaleFromFontUnits(fFontInfo->fStemV, emSize));
+ fDescriptor->insertScalar("CapHeight",
+ scaleFromFontUnits(fFontInfo->fCapHeight, emSize));
+ fDescriptor->insertInt("ItalicAngle", fFontInfo->fItalicAngle);
+ fDescriptor->insert("FontBBox", makeFontBBox(fFontInfo->fBBox,
+ fFontInfo->fEmSize))->unref();
+
+ if (defaultWidth > 0) {
+ fDescriptor->insertScalar("MissingWidth",
+ scaleFromFontUnits(defaultWidth, emSize));
+ }
+ return true;
+}
+
+void SkPDFFont::adjustGlyphRangeForSingleByteEncoding(int16_t glyphID) {
+ // Single byte glyph encoding supports a max of 255 glyphs.
+ fFirstGlyphID = glyphID - (glyphID - 1) % 255;
+ if (fLastGlyphID > fFirstGlyphID + 255 - 1) {
+ fLastGlyphID = fFirstGlyphID + 255 - 1;
+ }
+}
+
+bool SkPDFFont::FontRec::operator==(const SkPDFFont::FontRec& b) const {
+ if (fFontID != b.fFontID)
+ return false;
+ if (fFont != NULL && b.fFont != NULL) {
+ return fFont->fFirstGlyphID == b.fFont->fFirstGlyphID &&
+ fFont->fLastGlyphID == b.fFont->fLastGlyphID;
+ }
+ if (fGlyphID == 0 || b.fGlyphID == 0)
+ return true;
+
+ if (fFont != NULL) {
+ return fFont->fFirstGlyphID <= b.fGlyphID &&
+ b.fGlyphID <= fFont->fLastGlyphID;
+ } else if (b.fFont != NULL) {
+ return b.fFont->fFirstGlyphID <= fGlyphID &&
+ fGlyphID <= b.fFont->fLastGlyphID;
}
+ return fGlyphID == b.fGlyphID;
+}
- if (fType == SkAdvancedTypefaceMetrics::kType1_Font &&
- populateType1Font(glyphID)) {
+SkPDFFont::FontRec::FontRec(SkPDFFont* font, uint32_t fontID, uint16_t glyphID)
+ : fFont(font),
+ fFontID(fontID),
+ fGlyphID(glyphID) {
+}
+
+void SkPDFFont::populateToUnicodeTable(const SkPDFGlyphSet* subset) {
+ if (fFontInfo == NULL || fFontInfo->fGlyphToUnicode.begin() == NULL) {
return;
}
+ SkRefPtr<SkPDFStream> pdfCmap =
+ generate_tounicode_cmap(fFontInfo->fGlyphToUnicode, subset);
+ addResource(pdfCmap.get()); // Pass reference from new.
+ insert("ToUnicode", new SkPDFObjRef(pdfCmap.get()))->unref();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// class SkPDFType0Font
+///////////////////////////////////////////////////////////////////////////////
- SkASSERT(fType == SkAdvancedTypefaceMetrics::kType1_Font ||
- fType == SkAdvancedTypefaceMetrics::kCFF_Font ||
- fType == SkAdvancedTypefaceMetrics::kOther_Font ||
- fType == SkAdvancedTypefaceMetrics::kNotEmbeddable_Font);
- populateType3Font(glyphID);
+SkPDFType0Font::SkPDFType0Font(SkAdvancedTypefaceMetrics* info,
+ SkTypeface* typeface)
+ : SkPDFFont(info, typeface, 0, false) {
+ SkDEBUGCODE(fPopulated = false);
}
-void SkPDFFont::populateType0Font() {
- fMultiByteGlyphs = true;
+SkPDFType0Font::~SkPDFType0Font() {}
+SkPDFFont* SkPDFType0Font::getFontSubset(const SkPDFGlyphSet* subset) {
+ SkPDFType0Font* newSubset = new SkPDFType0Font(fontInfo(), typeface());
+ newSubset->populate(subset);
+ return newSubset;
+}
+
+#ifdef SK_DEBUG
+void SkPDFType0Font::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
+ bool indirect) {
+ SkASSERT(fPopulated);
+ return INHERITED::emitObject(stream, catalog, indirect);
+}
+#endif
+
+bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset) {
insertName("Subtype", "Type0");
- insertName("BaseFont", fFontInfo->fFontName);
+ insertName("BaseFont", fontInfo()->fFontName);
insertName("Encoding", "Identity-H");
+ // Pass ref new created to fResources.
+ SkPDFCIDFont* newCIDFont =
+ new SkPDFCIDFont(fontInfo(), typeface(), subset);
+ addResource(newCIDFont);
SkRefPtr<SkPDFArray> descendantFonts = new SkPDFArray();
descendantFonts->unref(); // SkRefPtr and new took a reference.
-
- // Pass ref new created to fResources.
- fResources.push(
- new SkPDFFont(fFontInfo.get(), fTypeface.get(), 1, true, NULL));
- descendantFonts->append(new SkPDFObjRef(fResources.top()))->unref();
+ descendantFonts->append(new SkPDFObjRef(newCIDFont))->unref();
insert("DescendantFonts", descendantFonts.get());
- populateToUnicodeTable();
+ populateToUnicodeTable(subset);
+
+ SkDEBUGCODE(fPopulated = true);
+ return true;
}
-void SkPDFFont::populateToUnicodeTable() {
- if (fFontInfo.get() == NULL ||
- fFontInfo->fGlyphToUnicode.begin() == NULL) {
- return;
+///////////////////////////////////////////////////////////////////////////////
+// class SkPDFCIDFont
+///////////////////////////////////////////////////////////////////////////////
+
+SkPDFCIDFont::SkPDFCIDFont(SkAdvancedTypefaceMetrics* info,
+ SkTypeface* typeface, const SkPDFGlyphSet* subset)
+ : SkPDFFont(info, typeface, 0, true) {
+ populate(subset);
+}
+
+SkPDFCIDFont::~SkPDFCIDFont() {}
+
+bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth,
+ const SkPDFGlyphSet* subset) {
+ SkRefPtr<SkPDFDict> descriptor = new SkPDFDict("FontDescriptor");
+ descriptor->unref(); // SkRefPtr and new both took a ref.
+ setFontDescriptor(descriptor.get());
+
+ switch (getType()) {
+ case SkAdvancedTypefaceMetrics::kTrueType_Font: {
+ // TODO(arthurhsu): sfntly font subsetting
+ SkRefPtr<SkStream> fontData =
+ SkFontHost::OpenStream(SkTypeface::UniqueID(typeface()));
+ fontData->unref(); // SkRefPtr and OpenStream both took a ref.
+ SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get());
+ // SkRefPtr and new both ref()'d fontStream, pass one.
+ addResource(fontStream.get());
+
+ fontStream->insertInt("Length1", fontData->getLength());
+ descriptor->insert("FontFile2",
+ new SkPDFObjRef(fontStream.get()))->unref();
+ break;
+ }
+ case SkAdvancedTypefaceMetrics::kCFF_Font:
+ case SkAdvancedTypefaceMetrics::kType1CID_Font: {
+ SkRefPtr<SkStream> fontData =
+ SkFontHost::OpenStream(SkTypeface::UniqueID(typeface()));
+ fontData->unref(); // SkRefPtr and OpenStream both took a ref.
+ SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get());
+ // SkRefPtr and new both ref()'d fontStream, pass one.
+ addResource(fontStream.get());
+
+ if (getType() == SkAdvancedTypefaceMetrics::kCFF_Font) {
+ fontStream->insertName("Subtype", "Type1C");
+ } else {
+ fontStream->insertName("Subtype", "CIDFontType0c");
+ }
+ descriptor->insert("FontFile3",
+ new SkPDFObjRef(fontStream.get()))->unref();
+ break;
+ }
+ default:
+ SkASSERT(false);
}
- SkDynamicMemoryWStream cmap;
- append_tounicode_header(&cmap);
- append_cmap_bfchar_sections(fFontInfo->fGlyphToUnicode, &cmap);
- append_cmap_footer(&cmap);
- SkRefPtr<SkMemoryStream> cmapStream = new SkMemoryStream();
- cmapStream->unref(); // SkRefPtr and new took a reference.
- cmapStream->setData(cmap.copyToData())->unref();
- SkRefPtr<SkPDFStream> pdfCmap = new SkPDFStream(cmapStream.get());
- fResources.push(pdfCmap.get()); // Pass reference from new.
- insert("ToUnicode", new SkPDFObjRef(pdfCmap.get()))->unref();
+ addResource(descriptor.get());
+ descriptor->ref();
+
+ insert("FontDescriptor", new SkPDFObjRef(descriptor.get()))->unref();
+ return addCommonFontDescriptorEntries(defaultWidth);
}
-void SkPDFFont::populateCIDFont() {
- fMultiByteGlyphs = true;
- insertName("BaseFont", fFontInfo->fFontName);
+bool SkPDFCIDFont::populate(const SkPDFGlyphSet* subset) {
+ insertName("BaseFont", fontInfo()->fFontName);
- if (fFontInfo->fType == SkAdvancedTypefaceMetrics::kType1CID_Font) {
+ if (getType() == SkAdvancedTypefaceMetrics::kType1CID_Font) {
insertName("Subtype", "CIDFontType0");
- } else if (fFontInfo->fType == SkAdvancedTypefaceMetrics::kTrueType_Font) {
+ } else if (getType() == SkAdvancedTypefaceMetrics::kTrueType_Font) {
insertName("Subtype", "CIDFontType2");
insertName("CIDToGIDMap", "Identity");
} else {
@@ -639,29 +919,30 @@ void SkPDFFont::populateCIDFont() {
sysInfo->insertInt("Supplement", 0);
insert("CIDSystemInfo", sysInfo.get());
- addFontDescriptor(0);
+ addFontDescriptor(0, subset);
- if (fFontInfo->fGlyphWidths.get()) {
+ if (fontInfo()->fGlyphWidths.get()) {
int16_t defaultWidth = 0;
SkRefPtr<SkPDFArray> widths =
- composeAdvanceData(fFontInfo->fGlyphWidths.get(),
- fFontInfo->fEmSize, &appendWidth, &defaultWidth);
+ composeAdvanceData(fontInfo()->fGlyphWidths.get(),
+ fontInfo()->fEmSize, &appendWidth,
+ &defaultWidth);
widths->unref(); // SkRefPtr and compose both took a reference.
if (widths->size())
insert("W", widths.get());
if (defaultWidth != 0) {
insertScalar("DW", scaleFromFontUnits(defaultWidth,
- fFontInfo->fEmSize));
+ fontInfo()->fEmSize));
}
}
- if (fFontInfo->fVerticalMetrics.get()) {
+ if (fontInfo()->fVerticalMetrics.get()) {
struct SkAdvancedTypefaceMetrics::VerticalMetric defaultAdvance;
defaultAdvance.fVerticalAdvance = 0;
defaultAdvance.fOriginXDisp = 0;
defaultAdvance.fOriginYDisp = 0;
SkRefPtr<SkPDFArray> advances =
- composeAdvanceData(fFontInfo->fVerticalMetrics.get(),
- fFontInfo->fEmSize, &appendVerticalAdvance,
+ composeAdvanceData(fontInfo()->fVerticalMetrics.get(),
+ fontInfo()->fEmSize, &appendVerticalAdvance,
&defaultAdvance);
advances->unref(); // SkRefPtr and compose both took a ref.
if (advances->size())
@@ -670,22 +951,77 @@ void SkPDFFont::populateCIDFont() {
defaultAdvance.fOriginXDisp ||
defaultAdvance.fOriginYDisp) {
insert("DW2", appendVerticalAdvance(defaultAdvance,
- fFontInfo->fEmSize,
+ fontInfo()->fEmSize,
new SkPDFArray))->unref();
}
}
+
+ return true;
}
-bool SkPDFFont::populateType1Font(int16_t glyphID) {
- SkASSERT(!fFontInfo->fVerticalMetrics.get());
- SkASSERT(fFontInfo->fGlyphWidths.get());
+///////////////////////////////////////////////////////////////////////////////
+// class SkPDFType1Font
+///////////////////////////////////////////////////////////////////////////////
+
+SkPDFType1Font::SkPDFType1Font(SkAdvancedTypefaceMetrics* info,
+ SkTypeface* typeface,
+ uint16_t glyphID,
+ SkPDFDict* relatedFontDescriptor)
+ : SkPDFFont(info, typeface, glyphID, false) {
+ populate(glyphID);
+}
+
+SkPDFType1Font::~SkPDFType1Font() {}
+
+bool SkPDFType1Font::addFontDescriptor(int16_t defaultWidth) {
+ SkRefPtr<SkPDFDict> descriptor = getFontDescriptor();
+ if (descriptor.get() != NULL) {
+ addResource(descriptor.get());
+ descriptor->ref();
+ insert("FontDescriptor", new SkPDFObjRef(descriptor.get()))->unref();
+ return true;
+ }
+
+ descriptor = new SkPDFDict("FontDescriptor");
+ descriptor->unref(); // SkRefPtr and new both took a ref.
+ setFontDescriptor(descriptor.get());
+
+ size_t header SK_INIT_TO_AVOID_WARNING;
+ size_t data SK_INIT_TO_AVOID_WARNING;
+ size_t trailer SK_INIT_TO_AVOID_WARNING;
+ SkRefPtr<SkStream> rawFontData =
+ SkFontHost::OpenStream(SkTypeface::UniqueID(typeface()));
+ rawFontData->unref(); // SkRefPtr and OpenStream both took a ref.
+ SkStream* fontData = handleType1Stream(rawFontData.get(), &header, &data,
+ &trailer);
+ if (fontData == NULL) {
+ return false;
+ }
+ SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData);
+ // SkRefPtr and new both ref()'d fontStream, pass one.
+ addResource(fontStream.get());
+ fontStream->insertInt("Length1", header);
+ fontStream->insertInt("Length2", data);
+ fontStream->insertInt("Length3", trailer);
+ descriptor->insert("FontFile", new SkPDFObjRef(fontStream.get()))->unref();
+
+ addResource(descriptor.get());
+ descriptor->ref();
+ insert("FontDescriptor", new SkPDFObjRef(descriptor.get()))->unref();
+
+ return addCommonFontDescriptorEntries(defaultWidth);
+}
+
+bool SkPDFType1Font::populate(int16_t glyphID) {
+ SkASSERT(!fontInfo()->fVerticalMetrics.get());
+ SkASSERT(fontInfo()->fGlyphWidths.get());
adjustGlyphRangeForSingleByteEncoding(glyphID);
int16_t defaultWidth = 0;
const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry = NULL;
const SkAdvancedTypefaceMetrics::WidthRange* widthEntry;
- for (widthEntry = fFontInfo.get()->fGlyphWidths.get();
+ for (widthEntry = fontInfo()->fGlyphWidths.get();
widthEntry != NULL;
widthEntry = widthEntry->fNext.get()) {
switch (widthEntry->fType) {
@@ -706,7 +1042,7 @@ bool SkPDFFont::populateType1Font(int16_t glyphID) {
return false;
insertName("Subtype", "Type1");
- insertName("BaseFont", fFontInfo->fFontName);
+ insertName("BaseFont", fontInfo()->fFontName);
addWidthInfoFromRange(defaultWidth, widthRangeEntry);
@@ -718,26 +1054,67 @@ bool SkPDFFont::populateType1Font(int16_t glyphID) {
encDiffs->unref(); // SkRefPtr and new both took a reference.
encoding->insert("Differences", encDiffs.get());
- encDiffs->reserve(fLastGlyphID - fFirstGlyphID + 2);
+ encDiffs->reserve(lastGlyphID() - firstGlyphID() + 2);
encDiffs->appendInt(1);
- for (int gID = fFirstGlyphID; gID <= fLastGlyphID; gID++) {
- encDiffs->appendName(fFontInfo->fGlyphNames->get()[gID].c_str());
+ for (int gID = firstGlyphID(); gID <= lastGlyphID(); gID++) {
+ encDiffs->appendName(fontInfo()->fGlyphNames->get()[gID].c_str());
}
- if (fFontInfo->fLastGlyphID <= 255)
- fFontInfo = NULL;
return true;
}
-void SkPDFFont::populateType3Font(int16_t glyphID) {
+void SkPDFType1Font::addWidthInfoFromRange(
+ int16_t defaultWidth,
+ const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry) {
+ SkRefPtr<SkPDFArray> widthArray = new SkPDFArray();
+ widthArray->unref(); // SkRefPtr and new both took a ref.
+ int firstChar = 0;
+ if (widthRangeEntry) {
+ const uint16_t emSize = fontInfo()->fEmSize;
+ int startIndex = firstGlyphID() - widthRangeEntry->fStartId;
+ int endIndex = startIndex + lastGlyphID() - firstGlyphID() + 1;
+ if (startIndex < 0)
+ startIndex = 0;
+ if (endIndex > widthRangeEntry->fAdvance.count())
+ endIndex = widthRangeEntry->fAdvance.count();
+ if (widthRangeEntry->fStartId == 0) {
+ appendWidth(widthRangeEntry->fAdvance[0], emSize, widthArray.get());
+ } else {
+ firstChar = startIndex + widthRangeEntry->fStartId;
+ }
+ for (int i = startIndex; i < endIndex; i++)
+ appendWidth(widthRangeEntry->fAdvance[i], emSize, widthArray.get());
+ } else {
+ appendWidth(defaultWidth, 1000, widthArray.get());
+ }
+ insertInt("FirstChar", firstChar);
+ insertInt("LastChar", firstChar + widthArray->size() - 1);
+ insert("Widths", widthArray.get());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// class SkPDFType3Font
+///////////////////////////////////////////////////////////////////////////////
+
+SkPDFType3Font::SkPDFType3Font(SkAdvancedTypefaceMetrics* info,
+ SkTypeface* typeface,
+ uint16_t glyphID,
+ SkPDFDict* relatedFontDescriptor)
+ : SkPDFFont(info, typeface, glyphID, false) {
+ populate(glyphID);
+}
+
+SkPDFType3Font::~SkPDFType3Font() {}
+
+bool SkPDFType3Font::populate(int16_t glyphID) {
SkPaint paint;
- paint.setTypeface(fTypeface.get());
+ paint.setTypeface(typeface());
paint.setTextSize(1000);
SkAutoGlyphCache autoCache(paint, NULL);
SkGlyphCache* cache = autoCache.getCache();
// If fLastGlyphID isn't set (because there is not fFontInfo), look it up.
- if (fLastGlyphID == 0) {
- fLastGlyphID = cache->getGlyphCount() - 1;
+ if (lastGlyphID() == 0) {
+ setLastGlyphID(cache->getGlyphCount() - 1);
}
adjustGlyphRangeForSingleByteEncoding(glyphID);
@@ -759,14 +1136,14 @@ void SkPDFFont::populateType3Font(int16_t glyphID) {
SkRefPtr<SkPDFArray> encDiffs = new SkPDFArray;
encDiffs->unref(); // SkRefPtr and new both took a reference.
encoding->insert("Differences", encDiffs.get());
- encDiffs->reserve(fLastGlyphID - fFirstGlyphID + 2);
+ encDiffs->reserve(lastGlyphID() - firstGlyphID() + 2);
encDiffs->appendInt(1);
SkRefPtr<SkPDFArray> widthArray = new SkPDFArray();
widthArray->unref(); // SkRefPtr and new both took a ref.
SkIRect bbox = SkIRect::MakeEmpty();
- for (int gID = fFirstGlyphID; gID <= fLastGlyphID; gID++) {
+ for (int gID = firstGlyphID(); gID <= lastGlyphID(); gID++) {
SkString characterName;
characterName.printf("gid%d", gID);
encDiffs->appendName(characterName.c_str());
@@ -793,176 +1170,17 @@ void SkPDFFont::populateType3Font(int16_t glyphID) {
SkRefPtr<SkPDFStream> glyphDescription =
new SkPDFStream(glyphStream.get());
// SkRefPtr and new both ref()'d charProcs, pass one.
- fResources.push(glyphDescription.get());
+ addResource(glyphDescription.get());
charProcs->insert(characterName.c_str(),
new SkPDFObjRef(glyphDescription.get()))->unref();
}
insert("FontBBox", makeFontBBox(bbox, 1000))->unref();
- insertInt("FirstChar", fFirstGlyphID);
- insertInt("LastChar", fLastGlyphID);
+ insertInt("FirstChar", firstGlyphID());
+ insertInt("LastChar", lastGlyphID());
insert("Widths", widthArray.get());
insertName("CIDToGIDMap", "Identity");
- if (fFontInfo && fFontInfo->fLastGlyphID <= 255) {
- fFontInfo = NULL;
- }
- populateToUnicodeTable();
-}
-
-bool SkPDFFont::addFontDescriptor(int16_t defaultWidth) {
- if (fDescriptor.get() != NULL) {
- fResources.push(fDescriptor.get());
- fDescriptor->ref();
- insert("FontDescriptor", new SkPDFObjRef(fDescriptor.get()))->unref();
- return true;
- }
-
- fDescriptor = new SkPDFDict("FontDescriptor");
- fDescriptor->unref(); // SkRefPtr and new both took a ref.
-
- switch (fFontInfo->fType) {
- case SkAdvancedTypefaceMetrics::kType1_Font: {
- size_t header SK_INIT_TO_AVOID_WARNING;
- size_t data SK_INIT_TO_AVOID_WARNING;
- size_t trailer SK_INIT_TO_AVOID_WARNING;
- SkRefPtr<SkStream> rawFontData =
- SkFontHost::OpenStream(SkTypeface::UniqueID(fTypeface.get()));
- rawFontData->unref(); // SkRefPtr and OpenStream both took a ref.
- SkStream* fontData = handleType1Stream(rawFontData.get(), &header,
- &data, &trailer);
- if (fontData == NULL)
- return false;
- SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData);
- // SkRefPtr and new both ref()'d fontStream, pass one.
- fResources.push(fontStream.get());
- fontStream->insertInt("Length1", header);
- fontStream->insertInt("Length2", data);
- fontStream->insertInt("Length3", trailer);
- fDescriptor->insert("FontFile",
- new SkPDFObjRef(fontStream.get()))->unref();
- break;
- }
- case SkAdvancedTypefaceMetrics::kTrueType_Font: {
- SkRefPtr<SkStream> fontData =
- SkFontHost::OpenStream(SkTypeface::UniqueID(fTypeface.get()));
- fontData->unref(); // SkRefPtr and OpenStream both took a ref.
- SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get());
- // SkRefPtr and new both ref()'d fontStream, pass one.
- fResources.push(fontStream.get());
-
- fontStream->insertInt("Length1", fontData->getLength());
- fDescriptor->insert("FontFile2",
- new SkPDFObjRef(fontStream.get()))->unref();
- break;
- }
- case SkAdvancedTypefaceMetrics::kCFF_Font:
- case SkAdvancedTypefaceMetrics::kType1CID_Font: {
- SkRefPtr<SkStream> fontData =
- SkFontHost::OpenStream(SkTypeface::UniqueID(fTypeface.get()));
- fontData->unref(); // SkRefPtr and OpenStream both took a ref.
- SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get());
- // SkRefPtr and new both ref()'d fontStream, pass one.
- fResources.push(fontStream.get());
-
- if (fFontInfo->fType == SkAdvancedTypefaceMetrics::kCFF_Font) {
- fontStream->insertName("Subtype", "Type1C");
- } else {
- fontStream->insertName("Subtype", "CIDFontType0c");
- }
- fDescriptor->insert("FontFile3",
- new SkPDFObjRef(fontStream.get()))->unref();
- break;
- }
- default:
- SkASSERT(false);
- }
-
- const uint16_t emSize = fFontInfo->fEmSize;
- fResources.push(fDescriptor.get());
- fDescriptor->ref();
- insert("FontDescriptor", new SkPDFObjRef(fDescriptor.get()))->unref();
-
- fDescriptor->insertName("FontName", fFontInfo->fFontName);
- fDescriptor->insertInt("Flags", fFontInfo->fStyle);
- fDescriptor->insertScalar("Ascent",
- scaleFromFontUnits(fFontInfo->fAscent, emSize));
- fDescriptor->insertScalar("Descent",
- scaleFromFontUnits(fFontInfo->fDescent, emSize));
- fDescriptor->insertScalar("StemV",
- scaleFromFontUnits(fFontInfo->fStemV, emSize));
- fDescriptor->insertScalar("CapHeight",
- scaleFromFontUnits(fFontInfo->fCapHeight, emSize));
- fDescriptor->insertInt("ItalicAngle", fFontInfo->fItalicAngle);
- fDescriptor->insert("FontBBox", makeFontBBox(fFontInfo->fBBox,
- fFontInfo->fEmSize))->unref();
-
- if (defaultWidth > 0) {
- fDescriptor->insertScalar("MissingWidth",
- scaleFromFontUnits(defaultWidth, emSize));
- }
+ populateToUnicodeTable(NULL);
return true;
}
-void SkPDFFont::addWidthInfoFromRange(
- int16_t defaultWidth,
- const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry) {
- SkRefPtr<SkPDFArray> widthArray = new SkPDFArray();
- widthArray->unref(); // SkRefPtr and new both took a ref.
- int firstChar = 0;
- if (widthRangeEntry) {
- const uint16_t emSize = fFontInfo->fEmSize;
- int startIndex = fFirstGlyphID - widthRangeEntry->fStartId;
- int endIndex = startIndex + fLastGlyphID - fFirstGlyphID + 1;
- if (startIndex < 0)
- startIndex = 0;
- if (endIndex > widthRangeEntry->fAdvance.count())
- endIndex = widthRangeEntry->fAdvance.count();
- if (widthRangeEntry->fStartId == 0) {
- appendWidth(widthRangeEntry->fAdvance[0], emSize, widthArray.get());
- } else {
- firstChar = startIndex + widthRangeEntry->fStartId;
- }
- for (int i = startIndex; i < endIndex; i++)
- appendWidth(widthRangeEntry->fAdvance[i], emSize, widthArray.get());
- } else {
- appendWidth(defaultWidth, 1000, widthArray.get());
- }
- insertInt("FirstChar", firstChar);
- insertInt("LastChar", firstChar + widthArray->size() - 1);
- insert("Widths", widthArray.get());
-}
-
-void SkPDFFont::adjustGlyphRangeForSingleByteEncoding(int16_t glyphID) {
- // Single byte glyph encoding supports a max of 255 glyphs.
- fFirstGlyphID = glyphID - (glyphID - 1) % 255;
- if (fLastGlyphID > fFirstGlyphID + 255 - 1) {
- fLastGlyphID = fFirstGlyphID + 255 - 1;
- }
-}
-
-
-bool SkPDFFont::FontRec::operator==(const SkPDFFont::FontRec& b) const {
- if (fFontID != b.fFontID)
- return false;
- if (fFont != NULL && b.fFont != NULL) {
- return fFont->fFirstGlyphID == b.fFont->fFirstGlyphID &&
- fFont->fLastGlyphID == b.fFont->fLastGlyphID;
- }
- if (fGlyphID == 0 || b.fGlyphID == 0)
- return true;
-
- if (fFont != NULL) {
- return fFont->fFirstGlyphID <= b.fGlyphID &&
- b.fGlyphID <= fFont->fLastGlyphID;
- } else if (b.fFont != NULL) {
- return b.fFont->fFirstGlyphID <= fGlyphID &&
- fGlyphID <= b.fFont->fLastGlyphID;
- }
- return fGlyphID == b.fGlyphID;
-}
-
-SkPDFFont::FontRec::FontRec(SkPDFFont* font, uint32_t fontID, uint16_t glyphID)
- : fFont(font),
- fFontID(fontID),
- fGlyphID(glyphID) {
-}
diff --git a/pdf/SkPDFFontImpl.h b/pdf/SkPDFFontImpl.h
new file mode 100755
index 00000000..22206255
--- /dev/null
+++ b/pdf/SkPDFFontImpl.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SkPDFFontImpl_DEFINED
+#define SkPDFFontImpl_DEFINED
+
+#include "SkPDFFont.h"
+
+class SkPDFType0Font : public SkPDFFont {
+public:
+ virtual ~SkPDFType0Font();
+ virtual bool multiByteGlyphs() const { return true; }
+ SK_API virtual SkPDFFont* getFontSubset(const SkPDFGlyphSet* usage);
+#ifdef SK_DEBUG
+ virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,
+ bool indirect);
+#endif
+
+private:
+ friend class SkPDFFont; // to access the constructor
+#ifdef SK_DEBUG
+ bool fPopulated;
+ typedef SkPDFDict INHERITED;
+#endif
+
+ SkPDFType0Font(SkAdvancedTypefaceMetrics* info, SkTypeface* typeface);
+
+ bool populate(const SkPDFGlyphSet* subset);
+};
+
+class SkPDFCIDFont : public SkPDFFont {
+public:
+ virtual ~SkPDFCIDFont();
+ virtual bool multiByteGlyphs() const { return true; }
+
+private:
+ friend class SkPDFType0Font; // to access the constructor
+
+ SkPDFCIDFont(SkAdvancedTypefaceMetrics* info, SkTypeface* typeface,
+ const SkPDFGlyphSet* subset);
+
+ bool populate(const SkPDFGlyphSet* subset);
+ bool addFontDescriptor(int16_t defaultWidth, const SkPDFGlyphSet* subset);
+};
+
+class SkPDFType1Font : public SkPDFFont {
+public:
+ virtual ~SkPDFType1Font();
+ virtual bool multiByteGlyphs() const { return false; }
+
+private:
+ friend class SkPDFFont; // to access the constructor
+
+ SkPDFType1Font(SkAdvancedTypefaceMetrics* info, SkTypeface* typeface,
+ uint16_t glyphID, SkPDFDict* relatedFontDescriptor);
+
+ bool populate(int16_t glyphID);
+ bool addFontDescriptor(int16_t defaultWidth);
+ void addWidthInfoFromRange(int16_t defaultWidth,
+ const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry);
+};
+
+class SkPDFType3Font : public SkPDFFont {
+public:
+ virtual ~SkPDFType3Font();
+ virtual bool multiByteGlyphs() const { return false; }
+
+private:
+ friend class SkPDFFont; // to access the constructor
+
+ SkPDFType3Font(SkAdvancedTypefaceMetrics* info, SkTypeface* typeface,
+ uint16_t glyphID, SkPDFDict* relatedFontDescriptor);
+
+ bool populate(int16_t glyphID);
+};
+
+#endif
diff --git a/pdf/SkPDFPage.cpp b/pdf/SkPDFPage.cpp
index 09849b0a..846df64a 100644
--- a/pdf/SkPDFPage.cpp
+++ b/pdf/SkPDFPage.cpp
@@ -141,3 +141,7 @@ void SkPDFPage::GeneratePageTree(const SkTDArray<SkPDFPage*>& pages,
const SkTDArray<SkPDFFont*>& SkPDFPage::getFontResources() const {
return fDevice->getFontResources();
}
+
+const SkPDFGlyphSetMap& SkPDFPage::getFontGlyphUsage() const {
+ return fDevice->getFontGlyphUsage();
+}