summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-08 23:38:27 +0000
committeragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-08 23:38:27 +0000
commit8afd0ad9907d3bab3689fe510881a8da9fa6a5ee (patch)
tree2c4b54f28eef60a8e5fe01704b567bf47cdae25f
parenta96182f9c4be4a711bddf2c5aaee9e2638ea12e1 (diff)
downloadchromium_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.h48
-rw-r--r--skia/ports/SkFontHost_tables.cpp183
-rw-r--r--skia/skia.gyp2
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',
],
}],