diff options
author | reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2009-04-08 05:03:52 +0000 |
---|---|---|
committer | reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2009-04-08 05:03:52 +0000 |
commit | d6638e644e430a721ea2dc2372e1880e16a3ff5d (patch) | |
tree | 193a8ec896667b1aa9721cd877b79a5f4a94f2d1 /src | |
parent | 16690af1c21dead3eedb25ebd0a4b9a091684ed4 (diff) |
add Table apis to SkFontHost
need to implement in _win backend
git-svn-id: http://skia.googlecode.com/svn/trunk@149 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src')
-rwxr-xr-x | src/ports/SkFontHost_mac.cpp | 88 | ||||
-rw-r--r-- | src/ports/SkFontHost_tables.cpp | 173 |
2 files changed, 261 insertions, 0 deletions
diff --git a/src/ports/SkFontHost_mac.cpp b/src/ports/SkFontHost_mac.cpp index b088c1e8da..06f1f312d8 100755 --- a/src/ports/SkFontHost_mac.cpp +++ b/src/ports/SkFontHost_mac.cpp @@ -483,3 +483,91 @@ void SkFontHost::GetGammaTables(const uint8_t* tables[2]) { tables[1] = NULL; // white gamma (e.g. exp= 1/1.4) } +/////////////////////////////////////////////////////////////////////////////// + +struct SkSFNTHeader { + uint32_t fVersion; + uint16_t fNumTables; + uint16_t fSearchRange; + uint16_t fEntrySelector; + uint16_t fRangeShift; +}; + +struct SkSFNTDirEntry { + uint32_t fTag; + uint32_t fChecksum; + uint32_t fOffset; + uint32_t fLength; +}; + +struct SfntHeader { + SfntHeader(SkFontID fontID, bool needDir) : fCount(0), fData(NULL) { + ByteCount size; + if (ATSFontGetTableDirectory(fontID, 0, NULL, &size)) { + return; + } + + SkAutoMalloc storage(size); + SkSFNTHeader* header = reinterpret_cast<SkSFNTHeader*>(storage.get()); + if (ATSFontGetTableDirectory(fontID, size, header, &size)) { + return; + } + + fCount = SkEndian_SwapBE16(header->fNumTables); + fData = header; + storage.detach(); + } + + ~SfntHeader() { + sk_free(fData); + } + + int count() const { return fCount; } + const SkSFNTDirEntry* entries() const { + return reinterpret_cast<const SkSFNTDirEntry*> + (reinterpret_cast<char*>(fData) + sizeof(SkSFNTHeader)); + } + +private: + int fCount; + void* fData; +}; + +int SkFontHost::CountTables(SkFontID fontID) { + SfntHeader header(fontID, false); + return header.count(); +} + +int SkFontHost::GetTableTags(SkFontID fontID, SkFontTableTag tags[]) { + SfntHeader header(fontID, true); + int count = header.count(); + const SkSFNTDirEntry* entry = header.entries(); + for (int i = 0; i < count; i++) { + tags[i] = SkEndian_SwapBE32(entry[i].fTag); + } + return count; +} + +size_t SkFontHost::GetTableSize(SkFontID fontID, SkFontTableTag tag) { + ByteCount size; + if (ATSFontGetTable(fontID, tag, 0, 0, NULL, &size)) { + return 0; + } + return size; +} + +size_t SkFontHost::GetTableData(SkFontID fontID, SkFontTableTag tag, + size_t offset, size_t length, void* data) { + ByteCount size; + if (ATSFontGetTable(fontID, tag, offset, length, data, &size)) { + return 0; + } + if (offset >= size) { + return 0; + } + if (offset + length > size) { + length = size - offset; + } + return length; +} + diff --git a/src/ports/SkFontHost_tables.cpp b/src/ports/SkFontHost_tables.cpp new file mode 100644 index 0000000000..f14e085575 --- /dev/null +++ b/src/ports/SkFontHost_tables.cpp @@ -0,0 +1,173 @@ +#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; + } + } + 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(); + if (stream->skip(offsetToDir) != offsetToDir) { + 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 (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; +} + |