aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2009-03-17 17:59:53 +0000
committerGravatar reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2009-03-17 17:59:53 +0000
commita14ea0e930c82daa2364ece4bd0b06256272302a (patch)
tree425f401e5731ead3050590fcc878ea49d006aaab
parent452f844f64d97e0f54b9258b800755686193136e (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.h11
-rw-r--r--include/core/SkScalerContext.h19
-rw-r--r--include/images/SkImageDecoder.h22
-rw-r--r--include/images/SkImageRef.h13
-rw-r--r--src/core/SkScalerContext.cpp131
-rw-r--r--src/images/SkImageRef.cpp18
-rw-r--r--src/ports/SkFontHost_android.cpp20
-rwxr-xr-xsrc/ports/SkFontHost_mac.cpp19
-rw-r--r--src/ports/SkFontHost_none.cpp6
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;
}