diff options
author | reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2009-03-17 17:59:53 +0000 |
---|---|---|
committer | reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2009-03-17 17:59:53 +0000 |
commit | a14ea0e930c82daa2364ece4bd0b06256272302a (patch) | |
tree | 425f401e5731ead3050590fcc878ea49d006aaab | |
parent | 452f844f64d97e0f54b9258b800755686193136e (diff) |
Simplify font-chaining (fallbacks) to have fonthost just return the next
logical fontID.
Extend ImageRef to accept an imagedecoder factory, to replace calling the std
one.
git-svn-id: http://skia.googlecode.com/svn/trunk@125 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | include/core/SkFontHost.h | 11 | ||||
-rw-r--r-- | include/core/SkScalerContext.h | 19 | ||||
-rw-r--r-- | include/images/SkImageDecoder.h | 22 | ||||
-rw-r--r-- | include/images/SkImageRef.h | 13 | ||||
-rw-r--r-- | src/core/SkScalerContext.cpp | 131 | ||||
-rw-r--r-- | src/images/SkImageRef.cpp | 18 | ||||
-rw-r--r-- | src/ports/SkFontHost_android.cpp | 20 | ||||
-rwxr-xr-x | src/ports/SkFontHost_mac.cpp | 19 | ||||
-rw-r--r-- | src/ports/SkFontHost_none.cpp | 6 |
9 files changed, 156 insertions, 103 deletions
diff --git a/include/core/SkFontHost.h b/include/core/SkFontHost.h index d98c55f668..942350f9d1 100644 --- a/include/core/SkFontHost.h +++ b/include/core/SkFontHost.h @@ -117,11 +117,14 @@ public: */ static SkScalerContext* CreateScalerContext(const SkDescriptor* desc); - /** Return a scalercontext using the "fallback" font. If there is no - designated fallback, return null. + /** Given a "current" fontID, return the next logical fontID to use + when searching fonts for a given unicode value. Typically the caller + will query a given font, and if a unicode value is not supported, they + will call this, and if 0 is not returned, will search that font, and so + on. This process must be finite, and when the fonthost sees a + font with no logical successor, it must return 0. */ - static SkScalerContext* CreateFallbackScalerContext( - const SkScalerContext::Rec&); + static uint32_t NextLogicalFont(uint32_t fontID); /////////////////////////////////////////////////////////////////////////// diff --git a/include/core/SkScalerContext.h b/include/core/SkScalerContext.h index 583833e18e..b06a4434e3 100644 --- a/include/core/SkScalerContext.h +++ b/include/core/SkScalerContext.h @@ -169,10 +169,16 @@ public: SkScalerContext(const SkDescriptor* desc); virtual ~SkScalerContext(); + // remember our glyph offset/base void setBaseGlyphCount(unsigned baseGlyphCount) { fBaseGlyphCount = baseGlyphCount; } + /** Return the corresponding glyph for the specified unichar. Since contexts + may be chained (under the hood), the glyphID that is returned may in + fact correspond to a different font/context. In that case, we use the + base-glyph-count to know how to translate back into local glyph space. + */ uint16_t charToGlyphID(SkUnichar uni); unsigned getGlyphCount() const { return this->generateGlyphCount(); } @@ -208,12 +214,15 @@ private: void internalGetPath(const SkGlyph& glyph, SkPath* fillPath, SkPath* devPath, SkMatrix* fillToDevMatrix); - mutable SkScalerContext* fAuxScalerContext; + // return the next context, treating fNextContext as a cache of the answer + SkScalerContext* getNextContext(); - SkScalerContext* getGlyphContext(const SkGlyph& glyph) const; - - // return loaded fAuxScalerContext or NULL - SkScalerContext* loadAuxContext() const; + // returns the right context from our link-list for this glyph. If no match + // is found, just returns the original context (this) + SkScalerContext* getGlyphContext(const SkGlyph& glyph); + + // link-list of context, to handle missing chars. null-terminated. + SkScalerContext* fNextContext; }; #define kRec_SkDescriptorTag SkSetFourByteTag('s', 'r', 'e', 'c') diff --git a/include/images/SkImageDecoder.h b/include/images/SkImageDecoder.h index 3ea6198e33..c85a7cd758 100644 --- a/include/images/SkImageDecoder.h +++ b/include/images/SkImageDecoder.h @@ -147,7 +147,7 @@ public: If none is found, the method returns NULL. */ static SkImageDecoder* Factory(SkStream*); - + /** Decode the image stored in the specified file, and store the result in bitmap. Return true for success or false on failure. @@ -260,4 +260,24 @@ private: SkImageDecoder& operator=(const SkImageDecoder&); }; +/** Calling newDecoder with a stream returns a new matching imagedecoder + instance, or NULL if none can be found. The caller must manage its ownership + of the stream as usual, calling unref() when it is done, as the returned + decoder may have called ref() (and if so, the decoder is responsible for + balancing its ownership when it is destroyed). + */ +class SkImageDecoderFactory : public SkRefCnt { +public: + virtual SkImageDecoder* newDecoder(SkStream*) = 0; +}; + +class SkDefaultImageDecoderFactory : SkImageDecoderFactory { +public: + // calls SkImageDecoder::Factory(stream) + virtual SkImageDecoder* newDecoder(SkStream* stream) { + return SkImageDecoder::Factory(stream); + } +}; + + #endif diff --git a/include/images/SkImageRef.h b/include/images/SkImageRef.h index 26ade5e03c..6ab6e525ff 100644 --- a/include/images/SkImageRef.h +++ b/include/images/SkImageRef.h @@ -52,6 +52,10 @@ public: and ignore the bitmap parameter. */ bool getInfo(SkBitmap* bm); + + SkImageDecoderFactory* getDecoderFactory() const { return fFactory; } + // returns the factory parameter + SkImageDecoderFactory* setDecoderFactory(SkImageDecoderFactory*); // overrides virtual void flatten(SkFlattenableWriteBuffer&) const; @@ -81,10 +85,11 @@ private: // requested state (or further, i.e. has pixels) bool prepareBitmap(SkImageDecoder::Mode); - SkStream* fStream; - SkBitmap::Config fConfig; - int fSampleSize; - bool fErrorInDecoding; + SkImageDecoderFactory* fFactory; // may be null + SkStream* fStream; + SkBitmap::Config fConfig; + int fSampleSize; + bool fErrorInDecoding; friend class SkImageRefPool; diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp index bbcc1308c1..8f84cbba9c 100644 --- a/src/core/SkScalerContext.cpp +++ b/src/core/SkScalerContext.cpp @@ -95,7 +95,7 @@ SkScalerContext::SkScalerContext(const SkDescriptor* desc) } fBaseGlyphCount = 0; - fAuxScalerContext = NULL; + fNextContext = NULL; const Rec* rec = (const Rec*)desc->findEntry(kRec_SkDescriptorTag, NULL); SkASSERT(rec); @@ -121,78 +121,97 @@ SkScalerContext::SkScalerContext(const SkDescriptor* desc) } SkScalerContext::~SkScalerContext() { + SkDELETE(fNextContext); + fPathEffect->safeUnref(); fMaskFilter->safeUnref(); fRasterizer->safeUnref(); - - SkDELETE(fAuxScalerContext); } -SkScalerContext* SkScalerContext::loadAuxContext() const { - if (NULL == fAuxScalerContext) { - fAuxScalerContext = SkFontHost::CreateFallbackScalerContext(fRec); - if (NULL != fAuxScalerContext) { - fAuxScalerContext->setBaseGlyphCount(this->getGlyphCount()); - } +static SkScalerContext* allocNextContext(const SkScalerContext::Rec& rec) { + // fonthost will determine the next possible font to search, based + // on the current font in fRec. It will return NULL if ctx is our + // last font that can be searched (i.e. ultimate fallback font) + uint32_t newFontID = SkFontHost::NextLogicalFont(rec.fFontID); + if (0 == newFontID) { + return NULL; } - return fAuxScalerContext; -} -#ifdef TRACK_MISSING_CHARS - static uint8_t gMissingChars[1 << 13]; -#endif + SkAutoDescriptor ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1)); + SkDescriptor* desc = ad.getDesc(); -uint16_t SkScalerContext::charToGlyphID(SkUnichar uni) { - unsigned glyphID = this->generateCharToGlyph(uni); - - if (0 == glyphID) { // try auxcontext - SkScalerContext* ctx = this->loadAuxContext(); - if (NULL != ctx) { - glyphID = ctx->generateCharToGlyph(uni); - if (0 != glyphID) { // only fiddle with it if its not missing - glyphID += this->getGlyphCount(); - if (glyphID > 0xFFFF) { - glyphID = 0; - } - } + desc->init(); + SkScalerContext::Rec* newRec = + (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag, + sizeof(rec), &rec); + newRec->fFontID = newFontID; + desc->computeChecksum(); + + return SkFontHost::CreateScalerContext(desc); +} + +/* Return the next context, creating it if its not already created, but return + NULL if the fonthost says there are no more fonts to fallback to. + */ +SkScalerContext* SkScalerContext::getNextContext() { + SkScalerContext* next = fNextContext; + // if next is null, then either it isn't cached yet, or we're at the + // end of our possible chain + if (NULL == next) { + next = allocNextContext(fRec); + if (NULL == next) { + return NULL; } + // next's base is our base + our local count + next->setBaseGlyphCount(fBaseGlyphCount + this->getGlyphCount()); + // cache the answer + fNextContext = next; } -#ifdef TRACK_MISSING_CHARS - if (0 == glyphID) { - bool announce = false; - if (uni > 0xFFFF) { // we don't record these - announce = true; - } else { - unsigned index = uni >> 3; - unsigned mask = 1 << (uni & 7); - SkASSERT(index < SK_ARRAY_COUNT(gMissingChars)); - if ((gMissingChars[index] & mask) == 0) { - gMissingChars[index] |= mask; - announce = true; - } + return next; +} + +SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) { + unsigned glyphID = glyph.getGlyphID(); + SkScalerContext* ctx = this; + for (;;) { + unsigned count = ctx->getGlyphCount(); + if (glyphID < count) { + break; } - if (announce) { - printf(">>> MISSING CHAR <<< 0x%04X\n", uni); + glyphID -= count; + ctx = ctx->getNextContext(); + if (NULL == ctx) { + SkDebugf("--- no context for glyph %x\n", glyph.getGlyphID()); + // just return the original context (this) + return this; } } -#endif - return SkToU16(glyphID); + return ctx; } -/* Internal routine to resolve auxContextID into a real context. - Only makes sense to call once the glyph has been given a - valid auxGlyphID. -*/ -SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) const { - SkScalerContext* ctx = const_cast<SkScalerContext*>(this); - - if (glyph.getGlyphID() >= this->getGlyphCount()) { - ctx = this->loadAuxContext(); - if (NULL == ctx) { // if no aux, just return us - ctx = const_cast<SkScalerContext*>(this); +/* This loops through all available fallback contexts (if needed) until it + finds some context that can handle the unichar. If all fail, returns 0 + */ +uint16_t SkScalerContext::charToGlyphID(SkUnichar uni) { + SkScalerContext* ctx = this; + unsigned glyphID; + for (;;) { + glyphID = ctx->generateCharToGlyph(uni); + if (glyphID) { + break; // found it + } + ctx = ctx->getNextContext(); + if (NULL == ctx) { + return 0; // no more contexts, return missing glyph } } - return ctx; + // add the ctx's base, making glyphID unique for chain of contexts + glyphID += ctx->fBaseGlyphCount; + // check for overflow of 16bits, since our glyphID cannot exceed that + if (glyphID > 0xFFFF) { + glyphID = 0; + } + return SkToU16(glyphID); } void SkScalerContext::getAdvance(SkGlyph* glyph) { diff --git a/src/images/SkImageRef.cpp b/src/images/SkImageRef.cpp index 8b14375582..0865c88595 100644 --- a/src/images/SkImageRef.cpp +++ b/src/images/SkImageRef.cpp @@ -20,6 +20,7 @@ SkImageRef::SkImageRef(SkStream* stream, SkBitmap::Config config, fConfig = config; fSampleSize = sampleSize; fPrev = fNext = NULL; + fFactory = NULL; #ifdef DUMP_IMAGEREF_LIFECYCLE SkDebugf("add ImageRef %p [%d] data=%d\n", @@ -36,6 +37,7 @@ SkImageRef::~SkImageRef() { #endif fStream->unref(); + fFactory->safeUnref(); } bool SkImageRef::getInfo(SkBitmap* bitmap) { @@ -52,6 +54,12 @@ bool SkImageRef::getInfo(SkBitmap* bitmap) { return true; } +SkImageDecoderFactory* SkImageRef::setDecoderFactory( + SkImageDecoderFactory* fact) { + SkRefCnt_SafeAssign(fFactory, fact); + return fact; +} + /////////////////////////////////////////////////////////////////////////////// bool SkImageRef::onDecode(SkImageDecoder* codec, SkStream* stream, @@ -84,8 +92,14 @@ bool SkImageRef::prepareBitmap(SkImageDecoder::Mode mode) { SkASSERT(fBitmap.getPixels() == NULL); fStream->rewind(); - - SkImageDecoder* codec = SkImageDecoder::Factory(fStream); + + SkImageDecoder* codec; + if (fFactory) { + codec = fFactory->newDecoder(fStream); + } else { + codec = SkImageDecoder::Factory(fStream); + } + if (codec) { SkAutoTDelete<SkImageDecoder> ad(codec); diff --git a/src/ports/SkFontHost_android.cpp b/src/ports/SkFontHost_android.cpp index 43bbde3ed9..6ee75dc5d3 100644 --- a/src/ports/SkFontHost_android.cpp +++ b/src/ports/SkFontHost_android.cpp @@ -590,22 +590,14 @@ SkStream* SkFontHost::OpenStream(uint32_t fontID) return stream; } -SkScalerContext* SkFontHost::CreateFallbackScalerContext( - const SkScalerContext::Rec& rec) -{ +uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) { load_system_fonts(); - SkAutoDescriptor ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1)); - SkDescriptor* desc = ad.getDesc(); - - desc->init(); - SkScalerContext::Rec* newRec = - (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag, - sizeof(rec), &rec); - newRec->fFontID = gFallBackTypeface->uniqueID(); - desc->computeChecksum(); - - return SkFontHost::CreateScalerContext(desc); + if (gFallBackTypeface->uniqueID() == fontID) { + // no where to go, just return NULL + return 0; + } + return gFallBackTypeface->uniqueID(); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/ports/SkFontHost_mac.cpp b/src/ports/SkFontHost_mac.cpp index 6b8f9a3b2e..ff5905fc1e 100755 --- a/src/ports/SkFontHost_mac.cpp +++ b/src/ports/SkFontHost_mac.cpp @@ -446,19 +446,12 @@ SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) { return new SkScalerContext_Mac(desc); } -SkScalerContext* SkFontHost::CreateFallbackScalerContext(const SkScalerContext::Rec& rec) -{ - SkAutoDescriptor ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1)); - SkDescriptor* desc = ad.getDesc(); - - desc->init(); - SkScalerContext::Rec* newRec = - (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag, - sizeof(rec), &rec); - newRec->fFontID = find_default_fontID(); - desc->computeChecksum(); - - return SkFontHost::CreateScalerContext(desc); +uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) { + uint32_t newFontID = find_default_fontID(); + if (newFontID == fontID) { + newFontID = 0; + } + return newFontID; } SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, diff --git a/src/ports/SkFontHost_none.cpp b/src/ports/SkFontHost_none.cpp index 608ee29714..471ffd825f 100644 --- a/src/ports/SkFontHost_none.cpp +++ b/src/ports/SkFontHost_none.cpp @@ -62,10 +62,8 @@ SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) { return NULL; } -SkScalerContext* SkFontHost::CreateFallbackScalerContext( - const SkScalerContext::Rec&) { - SkASSERT(!"SkFontHost::CreateFallbackScalerContext unimplemented"); - return NULL; +uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) { + return 0; } |