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:
parent
d9c0f0b57a
commit
62900b4c64
@ -85,6 +85,12 @@ struct SkGlyph {
|
||||
|
||||
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 {
|
||||
kSubBits = 2,
|
||||
kSubMask = ((1 << kSubBits) - 1),
|
||||
|
@ -52,6 +52,19 @@ size_t SkGlyph::computeImageSize() const {
|
||||
return size;
|
||||
}
|
||||
|
||||
void SkGlyph::zeroMetrics() {
|
||||
fAdvanceX = 0;
|
||||
fAdvanceY = 0;
|
||||
fWidth = 0;
|
||||
fHeight = 0;
|
||||
fTop = 0;
|
||||
fLeft = 0;
|
||||
fRsbDelta = 0;
|
||||
fLsbDelta = 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
#define DUMP_RECx
|
||||
#endif
|
||||
@ -521,10 +534,46 @@ void SkScalerContext::Rec::getSingleMatrix(SkMatrix* m) const
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#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)
|
||||
{
|
||||
return SkFontHost::CreateScalerContext(desc);
|
||||
SkScalerContext* c = SkFontHost::CreateScalerContext(desc);
|
||||
if (NULL == c) {
|
||||
c = SkNEW_ARGS(SkScalerContext_Empty, (desc));
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
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;
|
||||
|
||||
// we reset this to false before calling onDecode
|
||||
fShouldCancelDecode = false;
|
||||
|
||||
// pass a temporary bitmap, so that if we return false, we are assured of
|
||||
// leaving the caller's bitmap untouched.
|
||||
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;
|
||||
if (!this->onDecode(stream, &tmp, pref, mode)) {
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -63,6 +63,10 @@ class SkScalerContext_FreeType : public SkScalerContext {
|
||||
public:
|
||||
SkScalerContext_FreeType(const SkDescriptor* desc);
|
||||
virtual ~SkScalerContext_FreeType();
|
||||
|
||||
bool success() const {
|
||||
return fFaceRec != NULL && fFTSize != NULL;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual unsigned generateGlyphCount() const;
|
||||
@ -146,6 +150,7 @@ SkFaceRec::SkFaceRec(SkStream* strm, uint32_t fontID)
|
||||
fFTStream.close = sk_stream_close;
|
||||
}
|
||||
|
||||
// Will return 0 on failure
|
||||
static SkFaceRec* ref_ft_face(uint32_t fontID) {
|
||||
SkFaceRec* rec = gFaceRecHead;
|
||||
while (rec) {
|
||||
@ -160,7 +165,6 @@ static SkFaceRec* ref_ft_face(uint32_t fontID) {
|
||||
SkStream* strm = SkFontHost::OpenStream(fontID);
|
||||
if (NULL == strm) {
|
||||
SkDEBUGF(("SkFontHost::OpenStream failed opening %x\n", fontID));
|
||||
sk_throw();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -187,7 +191,6 @@ static SkFaceRec* ref_ft_face(uint32_t fontID) {
|
||||
if (err) { // bad filename, try the default font
|
||||
fprintf(stderr, "ERROR: unable to open font '%x'\n", fontID);
|
||||
SkDELETE(rec);
|
||||
sk_throw();
|
||||
return 0;
|
||||
} else {
|
||||
SkASSERT(rec->fFace);
|
||||
@ -225,7 +228,7 @@ static void unref_ft_face(FT_Face face) {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc)
|
||||
: SkScalerContext(desc), fFTSize(NULL) {
|
||||
: SkScalerContext(desc) {
|
||||
SkAutoMutexAcquire ac(gFTMutex);
|
||||
|
||||
FT_Error err;
|
||||
@ -238,8 +241,13 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc)
|
||||
++gFTCount;
|
||||
|
||||
// load the font file
|
||||
fFTSize = NULL;
|
||||
fFace = NULL;
|
||||
fFaceRec = ref_ft_face(fRec.fFontID);
|
||||
fFace = fFaceRec ? fFaceRec->fFace : NULL;
|
||||
if (NULL == fFaceRec) {
|
||||
return;
|
||||
}
|
||||
fFace = fFaceRec->fFace;
|
||||
|
||||
// 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) {
|
||||
#ifdef FT_ADVANCES_H
|
||||
/* unhinted and light hinted text have linearly scaled advances
|
||||
@ -437,7 +434,7 @@ void SkScalerContext_FreeType::generateAdvance(SkGlyph* glyph) {
|
||||
SkAutoMutexAcquire ac(gFTMutex);
|
||||
|
||||
if (this->setupSize()) {
|
||||
set_glyph_metrics_on_error(glyph);
|
||||
glyph->zeroMetrics();
|
||||
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",
|
||||
fFaceRec->fFontID, glyph->getGlyphID(fBaseGlyphCount), fLoadGlyphFlags, err));
|
||||
ERROR:
|
||||
set_glyph_metrics_on_error(glyph);
|
||||
glyph->zeroMetrics();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -769,7 +766,12 @@ void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx,
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
Loading…
Reference in New Issue
Block a user