handle failure when creating a scalercontext

git-svn-id: http://skia.googlecode.com/svn/trunk@90 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@android.com 2009-02-11 15:07:19 +00:00
parent d9c0f0b57a
commit 62900b4c64
4 changed files with 124 additions and 30 deletions

View File

@ -85,6 +85,12 @@ struct SkGlyph {
size_t computeImageSize() const; size_t computeImageSize() const;
/** Call this to set all of the metrics fields to 0 (e.g. if the scaler
encounters an error measuring a glyph). Note: this does not alter the
fImage, fPath, fID, fMaskFormat fields.
*/
void zeroMetrics();
enum { enum {
kSubBits = 2, kSubBits = 2,
kSubMask = ((1 << kSubBits) - 1), kSubMask = ((1 << kSubBits) - 1),

View File

@ -52,6 +52,19 @@ size_t SkGlyph::computeImageSize() const {
return size; return size;
} }
void SkGlyph::zeroMetrics() {
fAdvanceX = 0;
fAdvanceY = 0;
fWidth = 0;
fHeight = 0;
fTop = 0;
fLeft = 0;
fRsbDelta = 0;
fLsbDelta = 0;
}
///////////////////////////////////////////////////////////////////////////////
#ifdef SK_DEBUG #ifdef SK_DEBUG
#define DUMP_RECx #define DUMP_RECx
#endif #endif
@ -521,10 +534,46 @@ void SkScalerContext::Rec::getSingleMatrix(SkMatrix* m) const
} }
} }
///////////////////////////////////////////////////////////////////////////////
#include "SkFontHost.h" #include "SkFontHost.h"
class SkScalerContext_Empty : public SkScalerContext {
public:
SkScalerContext_Empty(const SkDescriptor* desc) : SkScalerContext(desc) {}
protected:
virtual unsigned generateGlyphCount() const {
return 0;
}
virtual uint16_t generateCharToGlyph(SkUnichar uni) {
return 0;
}
virtual void generateAdvance(SkGlyph* glyph) {
glyph->zeroMetrics();
}
virtual void generateMetrics(SkGlyph* glyph) {
glyph->zeroMetrics();
}
virtual void generateImage(const SkGlyph& glyph) {}
virtual void generatePath(const SkGlyph& glyph, SkPath* path) {}
virtual void generateFontMetrics(SkPaint::FontMetrics* mx,
SkPaint::FontMetrics* my) {
if (mx) {
bzero(mx, sizeof(*mx));
}
if (my) {
bzero(my, sizeof(*my));
}
}
};
SkScalerContext* SkScalerContext::Create(const SkDescriptor* desc) SkScalerContext* SkScalerContext::Create(const SkDescriptor* desc)
{ {
return SkFontHost::CreateScalerContext(desc); SkScalerContext* c = SkFontHost::CreateScalerContext(desc);
if (NULL == c) {
c = SkNEW_ARGS(SkScalerContext_Empty, (desc));
}
return c;
} }

View File

@ -91,25 +91,62 @@ bool SkImageDecoder::allocPixelRef(SkBitmap* bitmap,
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/* Technically, this should be 342, since that is the cutoff point between
an index and 32bit bitmap (they take equal ram), but since 32bit is almost
always faster, I bump up the value a bit.
*/
#define MIN_SIZE_FOR_INDEX (512)
/* Return the "optimal" config for this bitmap. In this case, we just look to
promote index bitmaps to full-color, since those are a little faster to
draw (fewer memory lookups).
Seems like we could expose this to the caller through some exising or new
proxy object, allowing them to decide (after sniffing some aspect of the
original bitmap) what config they really want.
*/
static SkBitmap::Config optimal_config(const SkBitmap& bm,
SkBitmap::Config pref) {
if (bm.config() != pref) {
if (bm.config() == SkBitmap::kIndex8_Config) {
Sk64 size64 = bm.getSize64();
if (size64.is32()) {
int32_t size = size64.get32();
if (size < MIN_SIZE_FOR_INDEX) {
return SkBitmap::kARGB_8888_Config;
}
}
}
}
return bm.config();
}
bool SkImageDecoder::decode(SkStream* stream, SkBitmap* bm, bool SkImageDecoder::decode(SkStream* stream, SkBitmap* bm,
SkBitmap::Config pref, Mode mode) { SkBitmap::Config pref, Mode mode) {
// pass a temporary bitmap, so that if we return false, we are assured of
// leaving the caller's bitmap untouched.
SkBitmap tmp; SkBitmap tmp;
// we reset this to false before calling onDecode // we reset this to false before calling onDecode
fShouldCancelDecode = false; fShouldCancelDecode = false;
// pass a temporary bitmap, so that if we return false, we are assured of if (!this->onDecode(stream, &tmp, pref, mode)) {
// leaving the caller's bitmap untouched. return false;
if (this->onDecode(stream, &tmp, pref, mode)) {
/* We operate on a tmp bitmap until we know we succeed. This way
we're sure we don't change the caller's bitmap and then later
return false. Returning false must mean that their parameter
is unchanged.
*/
bm->swap(tmp);
return true;
} }
return false;
SkBitmap::Config c = optimal_config(tmp, pref);
if (c != tmp.config()) {
if (mode == kDecodeBounds_Mode) {
tmp.setConfig(c, tmp.width(), tmp.height());
} else {
SkBitmap tmp2;
if (tmp.copyTo(&tmp2, c, this->getAllocator())) {
tmp.swap(tmp2);
}
}
}
bm->swap(tmp);
return true;
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -63,6 +63,10 @@ class SkScalerContext_FreeType : public SkScalerContext {
public: public:
SkScalerContext_FreeType(const SkDescriptor* desc); SkScalerContext_FreeType(const SkDescriptor* desc);
virtual ~SkScalerContext_FreeType(); virtual ~SkScalerContext_FreeType();
bool success() const {
return fFaceRec != NULL && fFTSize != NULL;
}
protected: protected:
virtual unsigned generateGlyphCount() const; virtual unsigned generateGlyphCount() const;
@ -146,6 +150,7 @@ SkFaceRec::SkFaceRec(SkStream* strm, uint32_t fontID)
fFTStream.close = sk_stream_close; fFTStream.close = sk_stream_close;
} }
// Will return 0 on failure
static SkFaceRec* ref_ft_face(uint32_t fontID) { static SkFaceRec* ref_ft_face(uint32_t fontID) {
SkFaceRec* rec = gFaceRecHead; SkFaceRec* rec = gFaceRecHead;
while (rec) { while (rec) {
@ -160,7 +165,6 @@ static SkFaceRec* ref_ft_face(uint32_t fontID) {
SkStream* strm = SkFontHost::OpenStream(fontID); SkStream* strm = SkFontHost::OpenStream(fontID);
if (NULL == strm) { if (NULL == strm) {
SkDEBUGF(("SkFontHost::OpenStream failed opening %x\n", fontID)); SkDEBUGF(("SkFontHost::OpenStream failed opening %x\n", fontID));
sk_throw();
return 0; return 0;
} }
@ -187,7 +191,6 @@ static SkFaceRec* ref_ft_face(uint32_t fontID) {
if (err) { // bad filename, try the default font if (err) { // bad filename, try the default font
fprintf(stderr, "ERROR: unable to open font '%x'\n", fontID); fprintf(stderr, "ERROR: unable to open font '%x'\n", fontID);
SkDELETE(rec); SkDELETE(rec);
sk_throw();
return 0; return 0;
} else { } else {
SkASSERT(rec->fFace); SkASSERT(rec->fFace);
@ -225,7 +228,7 @@ static void unref_ft_face(FT_Face face) {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc) SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc)
: SkScalerContext(desc), fFTSize(NULL) { : SkScalerContext(desc) {
SkAutoMutexAcquire ac(gFTMutex); SkAutoMutexAcquire ac(gFTMutex);
FT_Error err; FT_Error err;
@ -238,8 +241,13 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc)
++gFTCount; ++gFTCount;
// load the font file // load the font file
fFTSize = NULL;
fFace = NULL;
fFaceRec = ref_ft_face(fRec.fFontID); fFaceRec = ref_ft_face(fRec.fFontID);
fFace = fFaceRec ? fFaceRec->fFace : NULL; if (NULL == fFaceRec) {
return;
}
fFace = fFaceRec->fFace;
// compute our factors from the record // compute our factors from the record
@ -417,17 +425,6 @@ static FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) {
} }
} }
static void set_glyph_metrics_on_error(SkGlyph* glyph) {
glyph->fRsbDelta = 0;
glyph->fLsbDelta = 0;
glyph->fWidth = 0;
glyph->fHeight = 0;
glyph->fTop = 0;
glyph->fLeft = 0;
glyph->fAdvanceX = 0;
glyph->fAdvanceY = 0;
}
void SkScalerContext_FreeType::generateAdvance(SkGlyph* glyph) { void SkScalerContext_FreeType::generateAdvance(SkGlyph* glyph) {
#ifdef FT_ADVANCES_H #ifdef FT_ADVANCES_H
/* unhinted and light hinted text have linearly scaled advances /* unhinted and light hinted text have linearly scaled advances
@ -437,7 +434,7 @@ void SkScalerContext_FreeType::generateAdvance(SkGlyph* glyph) {
SkAutoMutexAcquire ac(gFTMutex); SkAutoMutexAcquire ac(gFTMutex);
if (this->setupSize()) { if (this->setupSize()) {
set_glyph_metrics_on_error(glyph); glyph->zeroMetrics();
return; return;
} }
@ -478,7 +475,7 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) {
SkDEBUGF(("SkScalerContext_FreeType::generateMetrics(%x): FT_Load_Glyph(glyph:%d flags:%d) returned 0x%x\n", SkDEBUGF(("SkScalerContext_FreeType::generateMetrics(%x): FT_Load_Glyph(glyph:%d flags:%d) returned 0x%x\n",
fFaceRec->fFontID, glyph->getGlyphID(fBaseGlyphCount), fLoadGlyphFlags, err)); fFaceRec->fFontID, glyph->getGlyphID(fBaseGlyphCount), fLoadGlyphFlags, err));
ERROR: ERROR:
set_glyph_metrics_on_error(glyph); glyph->zeroMetrics();
return; return;
} }
@ -769,7 +766,12 @@ void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx,
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) { SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
return SkNEW_ARGS(SkScalerContext_FreeType, (desc)); SkScalerContext_FreeType* c = SkNEW_ARGS(SkScalerContext_FreeType, (desc));
if (!c->success()) {
SkDELETE(c);
c = NULL;
}
return c;
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////