diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-08 23:38:27 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-08 23:38:27 +0000 |
commit | 8afd0ad9907d3bab3689fe510881a8da9fa6a5ee (patch) | |
tree | 2c4b54f28eef60a8e5fe01704b567bf47cdae25f | |
parent | a96182f9c4be4a711bddf2c5aaee9e2638ea12e1 (diff) | |
download | chromium_src-8afd0ad9907d3bab3689fe510881a8da9fa6a5ee.zip chromium_src-8afd0ad9907d3bab3689fe510881a8da9fa6a5ee.tar.gz chromium_src-8afd0ad9907d3bab3689fe510881a8da9fa6a5ee.tar.bz2 |
Skia: Merge upstream's r149.
This brings in support for reading TrueType tables via Skia. This
should allow us to move some of our metrics changes into our WebKit
port and out of Skia.
http://codereview.chromium.org/63133
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13391 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | skia/include/SkFontHost.h | 48 | ||||
-rw-r--r-- | skia/ports/SkFontHost_tables.cpp | 183 | ||||
-rw-r--r-- | skia/skia.gyp | 2 |
3 files changed, 230 insertions, 3 deletions
diff --git a/skia/include/SkFontHost.h b/skia/include/SkFontHost.h index c3b2e2d..d140dec 100644 --- a/skia/include/SkFontHost.h +++ b/skia/include/SkFontHost.h @@ -24,6 +24,9 @@ class SkDescriptor; class SkStream; class SkWStream; +typedef uint32_t SkFontTableTag; +typedef uint32_t SkFontID; + /** \class SkFontHost This class is ported to each environment. It is responsible for bridging @@ -69,13 +72,13 @@ public: /** Return the typeface associated with the uniqueID, or null if that ID does not match any faces. */ - static SkTypeface* ResolveTypeface(uint32_t uniqueID); + static SkTypeface* ResolveTypeface(SkFontID uniqueID); /** Return a new stream to read the font data, or null if the uniqueID does not match an existing typeface */ - static SkStream* OpenStream(uint32_t uniqueID); - static void CloseStream(uint32_t uniqueID, SkStream*); + static SkStream* OpenStream(SkFontID uniqueID); + static void CloseStream(SkFontID uniqueID, SkStream*); /** Return a new typeface given the data buffer (owned by the caller). If the data does not represent a valid font, return null. @@ -84,6 +87,45 @@ public: /////////////////////////////////////////////////////////////////////////// + /** Return the number of tables in the font + */ + static int CountTables(SkFontID); + + /** Copy into tags[] (allocated by the caller) the list of table tags in + the font, and return the number. This will be the same as CountTables() + or 0 if an error occured. + */ + static int GetTableTags(SkFontID, SkFontTableTag[]); + + /** Given a table tag, return the size of its contents, or 0 if not present + */ + static size_t GetTableSize(SkFontID, SkFontTableTag); + + /** Copy the contents of a table into data (allocated by the caller). Note + that the contents of the table will be in their native endian order + (which for most truetype tables is big endian). If the table tag is + not found, or there is an error copying the data, then 0 is returned. + If this happens, it is possible that some or all of the memory pointed + to by data may have been written to, even though an error has occured. + + @param fontID the font to copy the table from + @param tag The table tag whose contents are to be copied + @param offset The offset in bytes into the table's contents where the + copy should start from. + @param length The number of bytes, starting at offset, of table data + to copy. + @param data storage address where the table contents are copied to + @return the number of bytes actually copied into data. If offset+length + exceeds the table's size, then only the bytes up to the table's + size are actually copied, and this is the value returned. If + offset > the table's size, or tag is not a valid table, + then 0 is returned. + */ + static size_t GetTableData(SkFontID fontID, SkFontTableTag tag, + size_t offset, size_t length, void* data); + + /////////////////////////////////////////////////////////////////////////// + /** Write a unique identifier to the stream, so that the same typeface can be retrieved with Deserialize(). */ diff --git a/skia/ports/SkFontHost_tables.cpp b/skia/ports/SkFontHost_tables.cpp new file mode 100644 index 0000000..fdf0b06 --- /dev/null +++ b/skia/ports/SkFontHost_tables.cpp @@ -0,0 +1,183 @@ +#include "SkEndian.h" +#include "SkFontHost.h" +#include "SkStream.h" + +struct SkSFNTHeader { + uint32_t fVersion; + uint16_t fNumTables; + uint16_t fSearchRange; + uint16_t fEntrySelector; + uint16_t fRangeShift; +}; + +struct SkTTCFHeader { + uint32_t fTag; + uint32_t fVersion; + uint32_t fNumOffsets; + uint32_t fOffset0; // the first of N (fNumOffsets) +}; + +union SkSharedTTHeader { + SkSFNTHeader fSingle; + SkTTCFHeader fCollection; +}; + +struct SkSFNTDirEntry { + uint32_t fTag; + uint32_t fChecksum; + uint32_t fOffset; + uint32_t fLength; +}; + +static int count_tables(SkStream* stream, size_t* offsetToDir = NULL) { + SkSharedTTHeader shared; + if (stream->read(&shared, sizeof(shared)) != sizeof(shared)) { + return 0; + } + + uint32_t tag = SkEndian_SwapBE32(shared.fCollection.fTag); + if (SkSetFourByteTag('t', 't', 'c', 'f') == tag) { + if (shared.fCollection.fNumOffsets == 0) { + return 0; + } + size_t offset = SkEndian_SwapBE32(shared.fCollection.fOffset0); + stream->rewind(); + if (stream->skip(offset) != offset) { + return 0; + } + if (stream->read(&shared, sizeof(shared)) != sizeof(shared)) { + return 0; + } + if (offsetToDir) { + *offsetToDir = offset; + } + } else { + *offsetToDir = 0; + } + + return SkEndian_SwapBE16(shared.fSingle.fNumTables); +} + +/////////////////////////////////////////////////////////////////////////////// + +struct SfntHeader { + SfntHeader() : fCount(0), fDir(NULL) {} + ~SfntHeader() { sk_free(fDir); } + + bool init(SkStream* stream) { + size_t offsetToDir; + fCount = count_tables(stream, &offsetToDir); + if (0 == fCount) { + return false; + } + + stream->rewind(); + const size_t tableRecordOffset = offsetToDir + sizeof(SkSFNTHeader); + if (stream->skip(tableRecordOffset) != tableRecordOffset) { + return false; + } + + size_t size = fCount * sizeof(SkSFNTDirEntry); + fDir = reinterpret_cast<SkSFNTDirEntry*>(sk_malloc_throw(size)); + return stream->read(fDir, size) == size; + } + + int fCount; + SkSFNTDirEntry* fDir; +}; + +/////////////////////////////////////////////////////////////////////////////// + +int SkFontHost::CountTables(SkFontID fontID) { + SkStream* stream = SkFontHost::OpenStream(fontID); + if (NULL == stream) { + return 0; + } + + SkAutoUnref au(stream); + return count_tables(stream); +} + +int SkFontHost::GetTableTags(SkFontID fontID, SkFontTableTag tags[]) { + SkStream* stream = SkFontHost::OpenStream(fontID); + if (NULL == stream) { + return 0; + } + + SkAutoUnref au(stream); + SfntHeader header; + if (!header.init(stream)) { + return 0; + } + + for (int i = 0; i < header.fCount; i++) { + tags[i] = SkEndian_SwapBE32(header.fDir[i].fTag); + } + return header.fCount; +} + +size_t SkFontHost::GetTableSize(SkFontID fontID, SkFontTableTag tag) { + SkStream* stream = SkFontHost::OpenStream(fontID); + if (NULL == stream) { + return 0; + } + + SkAutoUnref au(stream); + SfntHeader header; + if (!header.init(stream)) { + return 0; + } + + for (int i = 0; i < header.fCount; i++) { + if (SkEndian_SwapBE32(header.fDir[i].fTag) == tag) { + return SkEndian_SwapBE32(header.fDir[i].fLength); + } + } + return 0; +} + +size_t SkFontHost::GetTableData(SkFontID fontID, SkFontTableTag tag, + size_t offset, size_t length, void* data) { + SkStream* stream = SkFontHost::OpenStream(fontID); + if (NULL == stream) { + return 0; + } + + SkAutoUnref au(stream); + SfntHeader header; + if (!header.init(stream)) { + return 0; + } + + for (int i = 0; i < header.fCount; i++) { + if (SkEndian_SwapBE32(header.fDir[i].fTag) == tag) { + size_t realOffset = SkEndian_SwapBE32(header.fDir[i].fOffset); + size_t realLength = SkEndian_SwapBE32(header.fDir[i].fLength); + // now sanity check the caller's offset/length + if (offset >= realLength) { + return 0; + } + // if the caller is trusting the length from the file, then a + // hostile file might choose a value which would overflow offset + + // length. + if (offset + length < offset) { + return 0; + } + if (offset + length > realLength) { + length = realLength - offset; + } + // skip the stream to the part of the table we want to copy from + stream->rewind(); + size_t bytesToSkip = realOffset + offset; + if (stream->skip(bytesToSkip) != bytesToSkip) { + return 0; + } + if (stream->read(data, length) != length) { + return 0; + } + return length; + } + } + return 0; +} + diff --git a/skia/skia.gyp b/skia/skia.gyp index 55071c8..568e4e8 100644 --- a/skia/skia.gyp +++ b/skia/skia.gyp @@ -460,6 +460,7 @@ 'ports/SkFontHost_fontconfig.cpp', #'ports/SkFontHost_FONTPATH.cpp', 'ports/SkFontHost_FreeType.cpp', + 'ports/SkFontHost_tables.cpp', #'ports/SkFontHost_gamma.cpp', 'ports/SkFontHost_gamma_none.cpp', #'ports/SkFontHost_linux.cpp', @@ -676,6 +677,7 @@ 'ports/SkFontHost_TryeType_Tables.cpp', 'ports/SkFontHost_gamma_none.cpp', 'ports/SkFontHost_fontconfig.cpp', + 'ports/SkFontHost_tables.cpp', 'sgl/SkTypeface.cpp', ], }], |