From 9781ca586618cc8ea055f54021e706824313d4f5 Mon Sep 17 00:00:00 2001 From: "reed@android.com" Date: Tue, 14 Apr 2009 14:28:22 +0000 Subject: add SkSfntUtils to parse some known truetype tables add comments and cleanup to count_tables in SkFontHost_tables.cpp fix transparency bug in gifs use (alpha+1) for blending in srcover mode, to ensure opaque results git-svn-id: http://skia.googlecode.com/svn/trunk@155 2bbb7eff-a529-9590-31e7-b0007b416f81 --- Makefile | 13 +++++- bench/TextBench.cpp | 17 +++++++ include/core/SkColorPriv.h | 6 +++ include/utils/SkSfntUtils.h | 52 +++++++++++++++++++++ src/images/SkImageDecoder_libgif.cpp | 15 +++++-- src/ports/SkFontHost_tables.cpp | 34 ++++++++++---- src/utils/SkNinePatch.cpp | 2 +- src/utils/SkSfntUtils.cpp | 87 ++++++++++++++++++++++++++++++++++++ src/utils/utils_files.mk | 10 +++++ tests/SrcOverTest.cpp | 2 +- 10 files changed, 222 insertions(+), 16 deletions(-) create mode 100644 include/utils/SkSfntUtils.h create mode 100644 src/utils/SkSfntUtils.cpp create mode 100644 src/utils/utils_files.mk diff --git a/Makefile b/Makefile index 91ba2c7f99..4e7b8d1715 100644 --- a/Makefile +++ b/Makefile @@ -36,6 +36,13 @@ SRC_LIST += $(addprefix src/effects/, $(SOURCE)) include src/images/images_files.mk SRC_LIST += $(addprefix src/images/, $(SOURCE)) +# core util files +include src/utils/utils_files.mk +SRC_LIST += $(addprefix src/utils/, $(SOURCE)) + +# extra files we want to build to prevent bit-rot, but not link +JUST_COMPILE_LIST := src/ports/SkFontHost_tables.cpp + # conditional files based on our platform ifeq ($(SKIA_BUILD_FOR),mac) LINKER_OPTS += -framework Carbon @@ -65,7 +72,11 @@ out/%.o : %.cpp OBJ_LIST := $(SRC_LIST:.cpp=.o) OBJ_LIST := $(addprefix out/, $(OBJ_LIST)) -out/libskia.a: Makefile $(OBJ_LIST) +# we want to compile these, but we don't actually link them +JUST_COMPILE_OBJS := $(JUST_COMPILE_LIST:.cpp=.o) +JUST_COMPILE_OBJS := $(addprefix out/, $(JUST_COMPILE_OBJS)) + +out/libskia.a: Makefile $(OBJ_LIST) $(JUST_COMPILE_OBJS) $(HIDE)$(AR) ru $@ $(OBJ_LIST) $(HIDE)ranlib $@ diff --git a/bench/TextBench.cpp b/bench/TextBench.cpp index adbd96281b..ebd2b33215 100644 --- a/bench/TextBench.cpp +++ b/bench/TextBench.cpp @@ -3,6 +3,7 @@ #include "SkFontHost.h" #include "SkPaint.h" #include "SkRandom.h" +#include "SkSfntUtils.h" #include "SkString.h" #include "SkTemplates.h" @@ -22,6 +23,22 @@ static void dump_font(const char name[], SkFontID fontID) { 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]); } + + SkSfntTable_head head; + if (SkSfntUtils::ReadTable_head(fontID, &head)) { + SkDebugf("--- head: version=%x magic=%x upem=%d style=%x\n", head.fVersion, + head.fMagicNumber, head.fUnitsPerEm, head.fMacStyle); + } else { + SkDebugf("------- head wasn't read\n"); + } + + SkSfntTable_maxp maxp; + if (SkSfntUtils::ReadTable_maxp(fontID, &maxp)) { + SkDebugf("--- maxp: version=%x glyphs=%d points=%d ctrs=%d\n", maxp.fVersion, + maxp.fNumGlyphs, maxp.fMaxPoints, maxp.fMaxContours); + } else { + SkDebugf("------- maxp wasn't read\n"); + } } static void test_tables() { diff --git a/include/core/SkColorPriv.h b/include/core/SkColorPriv.h index 88028cb27f..a82697e3c9 100644 --- a/include/core/SkColorPriv.h +++ b/include/core/SkColorPriv.h @@ -33,7 +33,13 @@ */ static inline unsigned SkAlpha255To256(U8CPU alpha) { SkASSERT(SkToU8(alpha) == alpha); +#if 1 + // this one assues that blending on top of an opaque dst keeps it that way + // even though it is less accurate than a+(a>>7) for non-opaque dsts + return alpha + 1; +#else return alpha + (alpha >> 7); +#endif } /** Multiplify value by 0..256, and shift the result down 8 diff --git a/include/utils/SkSfntUtils.h b/include/utils/SkSfntUtils.h new file mode 100644 index 0000000000..1d8f74e83b --- /dev/null +++ b/include/utils/SkSfntUtils.h @@ -0,0 +1,52 @@ + +#ifndef SkSfntUtils_DEFINED +#define SkSfntUtils_DEFINED + +#include "SkFontHost.h" + +struct SkSfntTable_head { + SkFixed fVersion; + SkFixed fRevision; + uint32_t fCheckSumAdjustment; + uint32_t fMagicNumber; + uint16_t fFlags; + uint16_t fUnitsPerEm; + Sk64 fDateCreated; + Sk64 fDateModified; + int16_t fXMin; + int16_t fYMin; + int16_t fXMax; + int16_t fYMax; + uint16_t fMacStyle; + uint16_t fLowestPPEM; + int16_t fFontDirectionHint; + int16_t fIndexToLocFormat; + int16_t fGlyphDataFormat; +}; + +struct SkSfntTable_maxp { + SkFixed fVersion; + uint16_t fNumGlyphs; + uint16_t fMaxPoints; + uint16_t fMaxContours; + uint16_t fMaxComponentPoints; + uint16_t fMaxComponentContours; + uint16_t fMaxZones; + uint16_t fMaxTwilightPoints; + uint16_t fMaxStorage; + uint16_t fMaxFunctionDefs; + uint16_t fMaxInstructionDefs; + uint16_t fMaxStackElements; + uint16_t fMaxSizeOfInstructions; + uint16_t fMaxComponentElements; + uint16_t fMaxComponentDepth; +}; + +class SkSfntUtils { +public: + static bool ReadTable_head(SkFontID, SkSfntTable_head*); + static bool ReadTable_maxp(SkFontID, SkSfntTable_maxp*); +}; + +#endif + diff --git a/src/images/SkImageDecoder_libgif.cpp b/src/images/SkImageDecoder_libgif.cpp index ed8817ab86..86ead1faff 100644 --- a/src/images/SkImageDecoder_libgif.cpp +++ b/src/images/SkImageDecoder_libgif.cpp @@ -171,6 +171,7 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, int width, height; GifRecordType recType; GifByteType *extData; + int transpIndex = -1; // -1 means we don't have it (yet) do { if (DGifGetRecordType(gif, &recType) == GIF_ERROR) { @@ -226,7 +227,7 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, cmap->Colors[index].Green, cmap->Colors[index].Blue); - int transpIndex = find_transpIndex(temp_save, colorCount); + transpIndex = find_transpIndex(temp_save, colorCount); if (transpIndex < 0) ctable->setFlags(ctable->getFlags() | SkColorTable::kColorsAreOpaque_Flag); else @@ -257,12 +258,18 @@ bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, if ((desc.Top | desc.Left) > 0 || innerWidth < width || innerHeight < height) { - uint8_t fill = (uint8_t)gif->SBackGroundColor; + int fill; + if (transpIndex >= 0) { + fill = transpIndex; + } else { + fill = gif->SBackGroundColor; + } // check for valid fill index/color - if (fill >= (unsigned)colorCount) { + if (static_cast(fill) >= + static_cast(colorCount)) { fill = 0; } - memset(scanline, gif->SBackGroundColor, bm->getSize()); + memset(scanline, fill, bm->getSize()); // bump our starting address scanline += desc.Top * rowBytes + desc.Left; } diff --git a/src/ports/SkFontHost_tables.cpp b/src/ports/SkFontHost_tables.cpp index fdf0b063fe..49452728ed 100644 --- a/src/ports/SkFontHost_tables.cpp +++ b/src/ports/SkFontHost_tables.cpp @@ -29,18 +29,30 @@ struct SkSFNTDirEntry { uint32_t fLength; }; +/** Return the number of tables, or if this is a TTC (collection), return the + number of tables in the first element of the collection. In either case, + if offsetToDir is not-null, set it to the offset to the beginning of the + table headers (SkSFNTDirEntry), relative to the start of the stream. + + On an error, return 0 for number of tables, and ignore offsetToDir + */ static int count_tables(SkStream* stream, size_t* offsetToDir = NULL) { SkSharedTTHeader shared; if (stream->read(&shared, sizeof(shared)) != sizeof(shared)) { return 0; } + // by default, SkSFNTHeader is at the start of the stream + size_t offset = 0; + + // if we're really a collection, the first 4-bytes will be 'ttcf' 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); + // this is the offset to the first local SkSFNTHeader + offset = SkEndian_SwapBE32(shared.fCollection.fOffset0); stream->rewind(); if (stream->skip(offset) != offset) { return 0; @@ -48,13 +60,12 @@ static int count_tables(SkStream* stream, size_t* offsetToDir = NULL) { if (stream->read(&shared, sizeof(shared)) != sizeof(shared)) { return 0; } - if (offsetToDir) { - *offsetToDir = offset; - } - } else { - *offsetToDir = 0; } - + + if (offsetToDir) { + // add the size of the header, so we will point to the DirEntries + *offsetToDir = offset + sizeof(SkSFNTDirEntry); + } return SkEndian_SwapBE16(shared.fSingle.fNumTables); } @@ -64,6 +75,12 @@ struct SfntHeader { SfntHeader() : fCount(0), fDir(NULL) {} ~SfntHeader() { sk_free(fDir); } + /** If it returns true, then fCount and fDir are properly initialized. + Note: fDir will point to the raw array of SkSFNTDirEntry values, + meaning they will still be in the file's native endianness (BE). + + fDir will be automatically freed when this object is destroyed + */ bool init(SkStream* stream) { size_t offsetToDir; fCount = count_tables(stream, &offsetToDir); @@ -72,8 +89,7 @@ struct SfntHeader { } stream->rewind(); - const size_t tableRecordOffset = offsetToDir + sizeof(SkSFNTHeader); - if (stream->skip(tableRecordOffset) != tableRecordOffset) { + if (stream->skip(offsetToDir) != offsetToDir) { return false; } diff --git a/src/utils/SkNinePatch.cpp b/src/utils/SkNinePatch.cpp index b8e11fbcaf..3d85edcf93 100644 --- a/src/utils/SkNinePatch.cpp +++ b/src/utils/SkNinePatch.cpp @@ -186,7 +186,7 @@ void SkNinePatch::DrawMesh(SkCanvas* canvas, const SkRect& bounds, if (numXDivs == 2 && numYDivs <= 2) { mesh.fIndices = g3x3Indices; } else { - int n = fillIndices(indices, numXDivs + 1, numYDivs + 1); + SkDEBUGCODE(int n =) fillIndices(indices, numXDivs + 1, numYDivs + 1); SkASSERT(n == indexCount); mesh.fIndices = indices; } diff --git a/src/utils/SkSfntUtils.cpp b/src/utils/SkSfntUtils.cpp new file mode 100644 index 0000000000..36f1f97da9 --- /dev/null +++ b/src/utils/SkSfntUtils.cpp @@ -0,0 +1,87 @@ +#include "SkEndian.h" +#include "SkSfntUtils.h" + +static uint16_t parse_be16(const uint8_t*& p) { + uint16_t value = (p[0] << 8) | p[1]; + p += 2; + return value; +} + +static uint32_t parse_be32(const uint8_t*& p) { + uint32_t value = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + p += 4; + return value; +} + +static Sk64 parse_be64(const uint8_t*& p) { + Sk64 value; + value.fHi = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + value.fLo = (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]; + p += 8; + return value; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool SkSfntUtils::ReadTable_head(SkFontID fontID, SkSfntTable_head* head) { + static const uint32_t gTag = SkSetFourByteTag('h', 'e', 'a', 'd'); + static const ssize_t gSize = 54; + + uint8_t storage[gSize]; + ssize_t size = SkFontHost::GetTableData(fontID, gTag, 0, gSize, storage); + if (size != gSize) { + return false; + } + + const uint8_t* p = storage; + head->fVersion = parse_be32(p); + head->fRevision = parse_be32(p); + head->fCheckSumAdjustment = parse_be32(p); + head->fMagicNumber = parse_be32(p); + head->fFlags = parse_be16(p); + head->fUnitsPerEm = parse_be16(p); + head->fDateCreated = parse_be64(p); + head->fDateModified = parse_be64(p); + head->fXMin = parse_be16(p); + head->fXMin = parse_be16(p); + head->fXMin = parse_be16(p); + head->fXMin = parse_be16(p); + head->fMacStyle = parse_be16(p); + head->fLowestPPEM = parse_be16(p); + head->fFontDirectionHint = parse_be16(p); + head->fIndexToLocFormat = parse_be16(p); + head->fGlyphDataFormat = parse_be16(p); + SkASSERT(p - storage == size); + return true; +} + +bool SkSfntUtils::ReadTable_maxp(SkFontID fontID, SkSfntTable_maxp* maxp) { + static const uint32_t gTag = SkSetFourByteTag('m', 'a', 'x', 'p'); + static const ssize_t gSize = 32; + + uint8_t storage[gSize]; + ssize_t size = SkFontHost::GetTableData(fontID, gTag, 0, gSize, storage); + if (size != gSize) { + return false; + } + + const uint8_t* p = storage; + maxp->fVersion = parse_be32(p); + maxp->fNumGlyphs = parse_be16(p); + maxp->fMaxPoints = parse_be16(p); + maxp->fMaxContours = parse_be16(p); + maxp->fMaxComponentPoints = parse_be16(p); + maxp->fMaxComponentContours = parse_be16(p); + maxp->fMaxZones = parse_be16(p); + maxp->fMaxTwilightPoints = parse_be16(p); + maxp->fMaxStorage = parse_be16(p); + maxp->fMaxFunctionDefs = parse_be16(p); + maxp->fMaxInstructionDefs = parse_be16(p); + maxp->fMaxStackElements = parse_be16(p); + maxp->fMaxSizeOfInstructions = parse_be16(p); + maxp->fMaxComponentElements = parse_be16(p); + maxp->fMaxComponentDepth = parse_be16(p); + SkASSERT(p - storage == size); + return true; +} + diff --git a/src/utils/utils_files.mk b/src/utils/utils_files.mk new file mode 100644 index 0000000000..a8c9496a86 --- /dev/null +++ b/src/utils/utils_files.mk @@ -0,0 +1,10 @@ +SOURCE := \ + SkCamera.cpp \ + SkColorMatrix.cpp \ + SkCullPoints.cpp \ + SkDumpCanvas.cpp \ + SkInterpolator.cpp \ + SkNinePatch.cpp \ + SkProxyCanvas.cpp \ + SkSfntUtils.cpp \ + SkUnitMappers.cpp diff --git a/tests/SrcOverTest.cpp b/tests/SrcOverTest.cpp index 497b3a81e1..e95485be57 100644 --- a/tests/SrcOverTest.cpp +++ b/tests/SrcOverTest.cpp @@ -39,7 +39,7 @@ static void test_srcover_hack(skiatest::Reporter* reporter) { opaqueCounter0, opaqueCounter1, opaqueCounter2); #endif // we acknowledge that technique0 does not always return opaque - REPORTER_ASSERT(reporter, opaqueCounter0 == 129); + REPORTER_ASSERT(reporter, opaqueCounter0 == 256); REPORTER_ASSERT(reporter, opaqueCounter1 == 256); REPORTER_ASSERT(reporter, opaqueCounter2 == 256); -- cgit v1.2.3