aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2009-04-08 05:03:52 +0000
committerGravatar reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2009-04-08 05:03:52 +0000
commitd6638e644e430a721ea2dc2372e1880e16a3ff5d (patch)
tree193a8ec896667b1aa9721cd877b79a5f4a94f2d1 /src
parent16690af1c21dead3eedb25ebd0a4b9a091684ed4 (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-xsrc/ports/SkFontHost_mac.cpp88
-rw-r--r--src/ports/SkFontHost_tables.cpp173
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;
+}
+