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
This commit is contained in:
parent
452f844f64
commit
a14ea0e930
@ -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);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -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')
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,80 +121,99 @@ 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;
|
||||
|
||||
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 = newFontID;
|
||||
desc->computeChecksum();
|
||||
|
||||
return SkFontHost::CreateScalerContext(desc);
|
||||
}
|
||||
|
||||
#ifdef TRACK_MISSING_CHARS
|
||||
static uint8_t gMissingChars[1 << 13];
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
if (announce) {
|
||||
printf(">>> MISSING CHAR <<< 0x%04X\n", uni);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return SkToU16(glyphID);
|
||||
return next;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) {
|
||||
unsigned glyphID = glyph.getGlyphID();
|
||||
SkScalerContext* ctx = this;
|
||||
for (;;) {
|
||||
unsigned count = ctx->getGlyphCount();
|
||||
if (glyphID < count) {
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/* 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
|
||||
}
|
||||
}
|
||||
// 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) {
|
||||
// mark us as just having a valid advance
|
||||
glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user