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;
|
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),
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
Loading…
Reference in New Issue
Block a user