*/
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);
///////////////////////////////////////////////////////////////////////////
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(); }
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')
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.
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
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;
// 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;
}
fBaseGlyphCount = 0;
- fAuxScalerContext = NULL;
+ fNextContext = NULL;
const Rec* rec = (const Rec*)desc->findEntry(kRec_SkDescriptorTag, NULL);
SkASSERT(rec);
}
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) {
fConfig = config;
fSampleSize = sampleSize;
fPrev = fNext = NULL;
+ fFactory = NULL;
#ifdef DUMP_IMAGEREF_LIFECYCLE
SkDebugf("add ImageRef %p [%d] data=%d\n",
#endif
fStream->unref();
+ fFactory->safeUnref();
}
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,
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);
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();
}
///////////////////////////////////////////////////////////////////////////////
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,
return NULL;
}
-SkScalerContext* SkFontHost::CreateFallbackScalerContext(
- const SkScalerContext::Rec&) {
- SkASSERT(!"SkFontHost::CreateFallbackScalerContext unimplemented");
- return NULL;
+uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) {
+ return 0;
}