aboutsummaryrefslogtreecommitdiffhomepage
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
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
-rw-r--r--Makefile2
-rw-r--r--bench/TextBench.cpp42
-rw-r--r--include/core/SkFontHost.h48
-rwxr-xr-xsrc/ports/SkFontHost_mac.cpp88
-rw-r--r--src/ports/SkFontHost_tables.cpp173
-rw-r--r--xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj2
6 files changed, 351 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index ddfecfc326..84742d4137 100644
--- a/Makefile
+++ b/Makefile
@@ -78,7 +78,7 @@ BENCH_SRCS += src/effects/SkNWayCanvas.cpp
# add any optional codecs for this app
ifeq ($(SKIA_BUILD_FOR),mac)
-# BENCH_SRCS += bench/TextBench.cpp
+ BENCH_SRCS += bench/TextBench.cpp
else
BENCH_SRCS += src/images/SkImageDecoder_libpng.cpp
endif
diff --git a/bench/TextBench.cpp b/bench/TextBench.cpp
index 799a3c852c..adbd96281b 100644
--- a/bench/TextBench.cpp
+++ b/bench/TextBench.cpp
@@ -1,10 +1,50 @@
#include "SkBenchmark.h"
#include "SkCanvas.h"
+#include "SkFontHost.h"
#include "SkPaint.h"
#include "SkRandom.h"
#include "SkString.h"
#include "SkTemplates.h"
+static void dump_font(const char name[], SkFontID fontID) {
+ SkDebugf("Font \"%s\" %x\n", name, fontID);
+ int count = SkFontHost::CountTables(fontID);
+ SkAutoTArray<SkFontTableTag> storage(count);
+ SkFontTableTag* tags = storage.get();
+ SkFontHost::GetTableTags(fontID, tags);
+ for (int i = 0; i < count; i++) {
+ uint32_t tag = tags[i];
+ uint8_t data[4];
+ size_t size = SkFontHost::GetTableSize(fontID, tag);
+ size_t bytes = SkFontHost::GetTableData(fontID, tag,
+ 0, sizeof(data), data);
+ SkDebugf(" tag=%c%c%c%c size=%d bytes=%d %x %x %x %x\n",
+ uint8_t(tag>>24), uint8_t(tag>>16), uint8_t(tag>>8), uint8_t(tag),
+ size, bytes, data[0], data[1], data[2], data[3]);
+ }
+}
+
+static void test_tables() {
+ static bool gOnce;
+ if (gOnce) {
+ return;
+ }
+ gOnce = true;
+
+ static const char* gNames[] = {
+ "Arial", "Times", "Courier"
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); i++) {
+ SkTypeface* tf = SkTypeface::CreateFromName(gNames[i], SkTypeface::kNormal);
+ if (tf) {
+ SkFontID fontID = tf->uniqueID();
+ dump_font(gNames[i], fontID);
+ tf->unref();
+ }
+ }
+}
+
/* Some considerations for performance:
short -vs- long strings (measuring overhead)
tiny -vs- large pointsize (measure blit -vs- overhead)
@@ -23,6 +63,8 @@ class TextBench : public SkBenchmark {
enum { N = 300 };
public:
TextBench(const char text[], int ps, bool linearText, bool posText) {
+ test_tables();
+
fText.set(text);
fPaint.setAntiAlias(true);
diff --git a/include/core/SkFontHost.h b/include/core/SkFontHost.h
index 942350f9d1..03ebfc7357 100644
--- a/include/core/SkFontHost.h
+++ b/include/core/SkFontHost.h
@@ -24,6 +24,9 @@ class SkDescriptor;
class SkStream;
class SkWStream;
+typedef uint32_t SkFontID;
+typedef uint32_t SkFontTableTag;
+
/** \class SkFontHost
This class is ported to each environment. It is responsible for bridging
@@ -91,13 +94,13 @@ public:
Returning false is similar to calling OpenStream with an invalid ID,
which will return NULL in that case.
*/
- static bool ValidFontID(uint32_t uniqueID);
+ static bool ValidFontID(SkFontID uniqueID);
/** Return a new stream to read the font data, or null if the uniqueID does
not match an existing typeface. .The caller must call stream->unref()
when it is finished reading the data.
*/
- static SkStream* OpenStream(uint32_t uniqueID);
+ static SkStream* OpenStream(SkFontID uniqueID);
///////////////////////////////////////////////////////////////////////////
@@ -124,10 +127,49 @@ public:
on. This process must be finite, and when the fonthost sees a
font with no logical successor, it must return 0.
*/
- static uint32_t NextLogicalFont(uint32_t fontID);
+ static uint32_t NextLogicalFont(SkFontID fontID);
///////////////////////////////////////////////////////////////////////////
+
+ /** 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);
+
+ ///////////////////////////////////////////////////////////////////////////
+
/** Return the number of bytes (approx) that should be purged from the font
cache. The input parameter is the cache's estimate of how much as been
allocated by the cache so far.
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;
+}
+
diff --git a/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj b/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj
index 7eea0ed831..3a3a581923 100644
--- a/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj
+++ b/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj
@@ -167,6 +167,7 @@
0041CE310F00A12400695E8C /* SampleNinePatch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleNinePatch.cpp; path = ../../samplecode/SampleNinePatch.cpp; sourceTree = SOURCE_ROOT; };
0041CE320F00A12400695E8C /* SampleOverflow.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleOverflow.cpp; path = ../../samplecode/SampleOverflow.cpp; sourceTree = SOURCE_ROOT; };
0041CE340F00A12400695E8C /* SamplePatch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SamplePatch.cpp; path = ../../samplecode/SamplePatch.cpp; sourceTree = SOURCE_ROOT; };
+ 0053528A0F8C4DFF00EE34B6 /* SkFontHost_tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkFontHost_tables.cpp; path = ../../src/ports/SkFontHost_tables.cpp; sourceTree = SOURCE_ROOT; };
007A7CA40F01658C00A2D6EE /* SamplePicture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SamplePicture.cpp; path = ../../samplecode/SamplePicture.cpp; sourceTree = SOURCE_ROOT; };
007A7CA50F01658C00A2D6EE /* SamplePoints.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SamplePoints.cpp; path = ../../samplecode/SamplePoints.cpp; sourceTree = SOURCE_ROOT; };
007A7CA70F01658C00A2D6EE /* SampleRegion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleRegion.cpp; path = ../../samplecode/SampleRegion.cpp; sourceTree = SOURCE_ROOT; };
@@ -334,6 +335,7 @@
002884490EFAA35C0083E387 /* core.xcodeproj */,
002884B40EFAB69F0083E387 /* maccore.xcodeproj */,
00003C8C0EFC230E000FF73A /* effects.xcodeproj */,
+ 0053528A0F8C4DFF00EE34B6 /* SkFontHost_tables.cpp */,
);
name = CICarbonSample;
sourceTree = "<group>";