support lcd16 in text atlas (sans shader support)
git-svn-id: http://skia.googlecode.com/svn/trunk@939 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
b7e9aee1ac
commit
98539c607b
@ -28,10 +28,11 @@ class GrAtlasMgr;
|
||||
|
||||
class GrAtlas {
|
||||
public:
|
||||
GrAtlas(GrAtlasMgr*, int plotX, int plotY);
|
||||
GrAtlas(GrAtlasMgr*, int plotX, int plotY, GrMaskFormat);
|
||||
|
||||
int getPlotX() const { return fPlot.fX; }
|
||||
int getPlotY() const { return fPlot.fY; }
|
||||
GrMaskFormat getMaskFormat() const { return fMaskFormat; }
|
||||
|
||||
GrTexture* texture() const { return fTexture; }
|
||||
|
||||
@ -56,6 +57,7 @@ private:
|
||||
GrRectanizer* fRects;
|
||||
GrAtlasMgr* fAtlasMgr;
|
||||
GrIPoint16 fPlot;
|
||||
GrMaskFormat fMaskFormat;
|
||||
|
||||
friend class GrAtlasMgr;
|
||||
};
|
||||
@ -68,7 +70,7 @@ public:
|
||||
~GrAtlasMgr();
|
||||
|
||||
GrAtlas* addToAtlas(GrAtlas*, int width, int height, const void*,
|
||||
GrIPoint16*);
|
||||
GrMaskFormat, GrIPoint16*);
|
||||
|
||||
GrTexture* getTexture() const { return fTexture; }
|
||||
|
||||
|
@ -33,6 +33,7 @@ class GrPath;
|
||||
class GrFontScaler : public GrRefCnt {
|
||||
public:
|
||||
virtual const GrKey* getKey() = 0;
|
||||
virtual GrMaskFormat getMaskFormat() = 0;
|
||||
virtual bool getPackedGlyphBounds(GrGlyph::PackedID, GrIRect* bounds) = 0;
|
||||
virtual bool getPackedGlyphImage(GrGlyph::PackedID, int width, int height,
|
||||
int rowBytes, void* image) = 0;
|
||||
|
@ -35,11 +35,13 @@ class GrFontPurgeListener;
|
||||
*/
|
||||
class GrTextStrike {
|
||||
public:
|
||||
GrTextStrike(GrFontCache*, const GrKey* fontScalerKey, GrAtlasMgr*);
|
||||
GrTextStrike(GrFontCache*, const GrKey* fontScalerKey, GrMaskFormat,
|
||||
GrAtlasMgr*);
|
||||
~GrTextStrike();
|
||||
|
||||
const GrKey* getFontScalerKey() const { return fFontScalerKey; }
|
||||
GrFontCache* getFontCache() const { return fFontCache; }
|
||||
GrMaskFormat getMaskFormat() const { return fMaskFormat; }
|
||||
|
||||
inline GrGlyph* getGlyph(GrGlyph::PackedID, GrFontScaler*);
|
||||
bool getGlyphAtlas(GrGlyph*, GrFontScaler*);
|
||||
@ -66,6 +68,8 @@ private:
|
||||
GrAtlasMgr* fAtlasMgr;
|
||||
GrAtlas* fAtlas; // linklist
|
||||
|
||||
GrMaskFormat fMaskFormat;
|
||||
|
||||
GrGlyph* generateGlyph(GrGlyph::PackedID packed, GrFontScaler* scaler);
|
||||
// returns true if after the purge, the strike is empty
|
||||
bool purgeAtlasAtY(GrAtlas* atlas, int yCoord);
|
||||
@ -110,7 +114,7 @@ private:
|
||||
GrGpu* fGpu;
|
||||
GrAtlasMgr* fAtlasMgr;
|
||||
|
||||
|
||||
|
||||
GrTextStrike* generateStrike(GrFontScaler*, const Key&);
|
||||
inline void detachStrikeFromList(GrTextStrike*);
|
||||
};
|
||||
|
@ -188,6 +188,22 @@ enum GrBlendCoeff {
|
||||
kIDA_BlendCoeff, //<! one minus dst alpha
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats for masks, used by the font cache
|
||||
*/
|
||||
enum GrMaskFormat {
|
||||
kA8_GrMaskFormat, //!< 1-byte per pixel
|
||||
kA565_GrMaskFormat //!< 2-bytes per pixel
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the number of bytes-per-pixel for the specified mask format.
|
||||
*/
|
||||
static inline int GrMaskFormatBytesPerPixel(GrMaskFormat format) {
|
||||
GrAssert((unsigned)format <= 1);
|
||||
return (int)format + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Operations used to construct clips.
|
||||
*/
|
||||
|
@ -51,7 +51,7 @@
|
||||
static int gCounter;
|
||||
#endif
|
||||
|
||||
GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY) {
|
||||
GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY, GrMaskFormat format) {
|
||||
fAtlasMgr = mgr; // just a pointer, not an owner
|
||||
fNext = NULL;
|
||||
fTexture = mgr->getTexture(); // we're not an owner, just a pointer
|
||||
@ -60,6 +60,8 @@ GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY) {
|
||||
fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH - BORDER,
|
||||
GR_ATLAS_HEIGHT - BORDER);
|
||||
|
||||
fMaskFormat = format;
|
||||
|
||||
#if GR_DEBUG
|
||||
GrPrintf(" GrAtlas %p [%d %d] %d\n", this, plotX, plotY, gCounter);
|
||||
gCounter += 1;
|
||||
@ -82,6 +84,13 @@ static void adjustForPlot(GrIPoint16* loc, const GrIPoint16& plot) {
|
||||
loc->fY += plot.fY * GR_ATLAS_HEIGHT;
|
||||
}
|
||||
|
||||
static uint8_t* zerofill(uint8_t* ptr, int count) {
|
||||
while (--count >= 0) {
|
||||
*ptr++ = 0;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool GrAtlas::addSubImage(int width, int height, const void* image,
|
||||
GrIPoint16* loc) {
|
||||
if (!fRects->addRect(width + BORDER, height + BORDER, loc)) {
|
||||
@ -89,23 +98,26 @@ bool GrAtlas::addSubImage(int width, int height, const void* image,
|
||||
}
|
||||
|
||||
GrAutoSMalloc<1024> storage;
|
||||
int srcW = width + 2*BORDER;
|
||||
int srcH = height + 2*BORDER;
|
||||
int dstW = width + 2*BORDER;
|
||||
int dstH = height + 2*BORDER;
|
||||
if (BORDER) {
|
||||
uint8_t* ptr = (uint8_t*)storage.realloc(srcW * srcH);
|
||||
Gr_bzero(ptr, srcW); // zero top row
|
||||
ptr += srcW;
|
||||
const int bpp = GrMaskFormatBytesPerPixel(fMaskFormat);
|
||||
const size_t dstRB = dstW * bpp;
|
||||
uint8_t* dst = (uint8_t*)storage.realloc(dstH * dstRB);
|
||||
Gr_bzero(dst, dstRB); // zero top row
|
||||
dst += dstRB;
|
||||
for (int y = 0; y < height; y++) {
|
||||
*ptr++ = 0; // zero left edge
|
||||
memcpy(ptr, image, width); ptr += width;
|
||||
*ptr++ = 0; // zero right edge
|
||||
image = (const void*)((const char*)image + width);
|
||||
dst = zerofill(dst, bpp); // zero left edge
|
||||
memcpy(dst, image, width * bpp);
|
||||
dst += width * bpp;
|
||||
dst = zerofill(dst, bpp); // zero right edge
|
||||
image = (const void*)((const char*)image + width * bpp);
|
||||
}
|
||||
Gr_bzero(ptr, srcW); // zero bottom row
|
||||
Gr_bzero(dst, dstRB); // zero bottom row
|
||||
image = storage.get();
|
||||
}
|
||||
adjustForPlot(loc, fPlot);
|
||||
fTexture->uploadTextureData(loc->fX, loc->fY, srcW, srcH, image);
|
||||
fTexture->uploadTextureData(loc->fX, loc->fY, dstW, dstH, image);
|
||||
|
||||
// now tell the caller to skip the top/left BORDER
|
||||
loc->fX += BORDER;
|
||||
@ -128,9 +140,23 @@ GrAtlasMgr::~GrAtlasMgr() {
|
||||
fGpu->unref();
|
||||
}
|
||||
|
||||
static GrTexture::PixelConfig maskformat2pixelconfig(GrMaskFormat format) {
|
||||
switch (format) {
|
||||
case kA8_GrMaskFormat:
|
||||
return GrTexture::kAlpha_8_PixelConfig;
|
||||
case kA565_GrMaskFormat:
|
||||
return GrTexture::kRGB_565_PixelConfig;
|
||||
default:
|
||||
GrAssert(!"unknown maskformat");
|
||||
}
|
||||
return GrTexture::kUnknown_PixelConfig;
|
||||
}
|
||||
|
||||
GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
|
||||
int width, int height, const void* image,
|
||||
GrMaskFormat format,
|
||||
GrIPoint16* loc) {
|
||||
GrAssert(NULL == atlas || atlas->getMaskFormat() == format);
|
||||
if (atlas && atlas->addSubImage(width, height, image, loc)) {
|
||||
return atlas;
|
||||
}
|
||||
@ -145,11 +171,11 @@ GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
|
||||
|
||||
if (NULL == fTexture) {
|
||||
GrGpu::TextureDesc desc = {
|
||||
GrGpu::kDynamicUpdate_TextureFlag,
|
||||
GrGpu::kDynamicUpdate_TextureFlag,
|
||||
GrGpu::kNone_AALevel,
|
||||
GR_ATLAS_TEXTURE_WIDTH,
|
||||
GR_ATLAS_TEXTURE_WIDTH,
|
||||
GR_ATLAS_TEXTURE_HEIGHT,
|
||||
GrTexture::kAlpha_8_PixelConfig
|
||||
maskformat2pixelconfig(format)
|
||||
};
|
||||
fTexture = fGpu->createTexture(desc, NULL, 0);
|
||||
if (NULL == fTexture) {
|
||||
@ -157,7 +183,7 @@ GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
|
||||
}
|
||||
}
|
||||
|
||||
GrAtlas* newAtlas = new GrAtlas(this, plot.fX, plot.fY);
|
||||
GrAtlas* newAtlas = new GrAtlas(this, plot.fX, plot.fY, format);
|
||||
if (!newAtlas->addSubImage(width, height, image, loc)) {
|
||||
delete newAtlas;
|
||||
return NULL;
|
||||
|
@ -41,7 +41,8 @@ GrTextStrike* GrFontCache::generateStrike(GrFontScaler* scaler,
|
||||
if (NULL == fAtlasMgr) {
|
||||
fAtlasMgr = new GrAtlasMgr(fGpu);
|
||||
}
|
||||
GrTextStrike* strike = new GrTextStrike(this, scaler->getKey(), fAtlasMgr);
|
||||
GrTextStrike* strike = new GrTextStrike(this, scaler->getKey(),
|
||||
scaler->getMaskFormat(), fAtlasMgr);
|
||||
fCache.insert(key, strike);
|
||||
|
||||
if (fHead) {
|
||||
@ -131,6 +132,7 @@ void GrFontCache::validate() const {
|
||||
*/
|
||||
|
||||
GrTextStrike::GrTextStrike(GrFontCache* cache, const GrKey* key,
|
||||
GrMaskFormat format,
|
||||
GrAtlasMgr* atlasMgr) : fPool(64) {
|
||||
fFontScalerKey = key;
|
||||
fFontScalerKey->ref();
|
||||
@ -139,6 +141,8 @@ GrTextStrike::GrTextStrike(GrFontCache* cache, const GrKey* key,
|
||||
fAtlasMgr = atlasMgr; // no need to ref, it won't go away before we do
|
||||
fAtlas = NULL;
|
||||
|
||||
fMaskFormat = format;
|
||||
|
||||
#if GR_DEBUG
|
||||
GrPrintf(" GrTextStrike %p %d\n", this, gCounter);
|
||||
gCounter += 1;
|
||||
@ -180,17 +184,20 @@ bool GrTextStrike::getGlyphAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
|
||||
}
|
||||
|
||||
GrAutoRef ar(scaler);
|
||||
|
||||
size_t size = glyph->fBounds.area();
|
||||
|
||||
int bytesPerPixel = GrMaskFormatBytesPerPixel(fMaskFormat);
|
||||
size_t size = glyph->fBounds.area() * bytesPerPixel;
|
||||
GrAutoSMalloc<1024> storage(size);
|
||||
if (!scaler->getPackedGlyphImage(glyph->fPackedID, glyph->width(),
|
||||
glyph->height(), glyph->width(),
|
||||
glyph->height(),
|
||||
glyph->width() * bytesPerPixel,
|
||||
storage.get())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GrAtlas* atlas = fAtlasMgr->addToAtlas(fAtlas, glyph->width(),
|
||||
glyph->height(), storage.get(),
|
||||
fMaskFormat,
|
||||
&glyph->fAtlasLocation);
|
||||
if (NULL == atlas) {
|
||||
return false;
|
||||
|
@ -222,6 +222,10 @@ public:
|
||||
SkScalerContext(const SkDescriptor* desc);
|
||||
virtual ~SkScalerContext();
|
||||
|
||||
SkMask::Format getMaskFormat() const {
|
||||
return (SkMask::Format)fRec.fMaskFormat;
|
||||
}
|
||||
|
||||
// remember our glyph offset/base
|
||||
void setBaseGlyphCount(unsigned baseGlyphCount) {
|
||||
fBaseGlyphCount = baseGlyphCount;
|
||||
|
@ -231,7 +231,7 @@ public:
|
||||
SkGrRegionIterator() {}
|
||||
SkGrRegionIterator(const SkRegion& region) { this->reset(region); }
|
||||
|
||||
void reset(const SkRegion& region) {
|
||||
void reset(const SkRegion& region) {
|
||||
fRegion = ®ion;
|
||||
fIter.reset(region);
|
||||
}
|
||||
@ -275,6 +275,7 @@ public:
|
||||
|
||||
// overrides
|
||||
virtual const GrKey* getKey();
|
||||
virtual GrMaskFormat getMaskFormat();
|
||||
virtual bool getPackedGlyphBounds(GrGlyph::PackedID, GrIRect* bounds);
|
||||
virtual bool getPackedGlyphImage(GrGlyph::PackedID, int width, int height,
|
||||
int rowBytes, void* image);
|
||||
|
@ -2,16 +2,16 @@
|
||||
**
|
||||
** Copyright 2006, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
@ -47,17 +47,17 @@ public:
|
||||
*/
|
||||
const SkGlyph& getUnicharAdvance(SkUnichar);
|
||||
const SkGlyph& getGlyphIDAdvance(uint16_t);
|
||||
|
||||
|
||||
/** Returns a glyph with all fields valid except fImage and fPath, which
|
||||
may be null. If they are null, call findImage or findPath for those.
|
||||
If they are not null, then they are valid.
|
||||
|
||||
|
||||
This call is potentially slower than the matching ...Advance call. If
|
||||
you only need the fAdvance/fDevKern fields, call those instead.
|
||||
*/
|
||||
const SkGlyph& getUnicharMetrics(SkUnichar);
|
||||
const SkGlyph& getGlyphIDMetrics(uint16_t);
|
||||
|
||||
|
||||
/** These are variants that take the device position of the glyph. Call
|
||||
these only if you are drawing in subpixel mode. Passing 0, 0 is
|
||||
effectively the same as calling the variants w/o the extra params, tho
|
||||
@ -65,13 +65,13 @@ public:
|
||||
*/
|
||||
const SkGlyph& getUnicharMetrics(SkUnichar, SkFixed x, SkFixed y);
|
||||
const SkGlyph& getGlyphIDMetrics(uint16_t, SkFixed x, SkFixed y);
|
||||
|
||||
|
||||
/** Return the glyphID for the specified Unichar. If the char has already
|
||||
been seen, use the existing cache entry. If not, ask the scalercontext
|
||||
to compute it for us.
|
||||
*/
|
||||
uint16_t unicharToGlyph(SkUnichar);
|
||||
|
||||
|
||||
/** Map the glyph to its Unicode equivalent. Unmappable glyphs map to
|
||||
a character code of zero.
|
||||
*/
|
||||
@ -98,6 +98,10 @@ public:
|
||||
|
||||
const SkDescriptor& getDescriptor() const { return *fDesc; }
|
||||
|
||||
SkMask::Format getMaskFormat() const {
|
||||
return fScalerContext->getMaskFormat();
|
||||
}
|
||||
|
||||
/* AuxProc/Data allow a client to associate data with this cache entry.
|
||||
Multiple clients can use this, as their data is keyed with a function
|
||||
pointer. In addition to serving as a key, the function pointer is called
|
||||
@ -106,7 +110,7 @@ public:
|
||||
this glyphcache in any way, since it may be in the process of being
|
||||
deleted.
|
||||
*/
|
||||
|
||||
|
||||
//! If the proc is found, return true and set *dataPtr to its data
|
||||
bool getAuxProcData(void (*auxProc)(void*), void** dataPtr) const;
|
||||
//! Add a proc/data pair to the glyphcache. proc should be non-null
|
||||
@ -120,7 +124,7 @@ public:
|
||||
deadlock.
|
||||
*/
|
||||
static void VisitAllCaches(bool (*proc)(SkGlyphCache*, void*), void* ctx);
|
||||
|
||||
|
||||
/** Find a matching cache entry, and call proc() with it. If none is found
|
||||
create a new one. If the proc() returns true, detach the cache and
|
||||
return it, otherwise leave it and return NULL.
|
||||
@ -128,7 +132,7 @@ public:
|
||||
static SkGlyphCache* VisitCache(const SkDescriptor* desc,
|
||||
bool (*proc)(const SkGlyphCache*, void*),
|
||||
void* context);
|
||||
|
||||
|
||||
/** Given a strike that was returned by either VisitCache() or DetachCache()
|
||||
add it back into the global cache list (after which the caller should
|
||||
not reference it anymore.
|
||||
@ -184,11 +188,11 @@ public:
|
||||
private:
|
||||
const SkGlyphCache* fCache;
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
SkGlyphCache(const SkDescriptor*);
|
||||
~SkGlyphCache();
|
||||
|
||||
|
||||
enum MetricsType {
|
||||
kJustAdvance_MetricsType,
|
||||
kFull_MetricsType
|
||||
@ -208,7 +212,7 @@ private:
|
||||
}
|
||||
fPrev = fNext = NULL;
|
||||
}
|
||||
|
||||
|
||||
void attachToHead(SkGlyphCache** head) {
|
||||
SkASSERT(NULL == fPrev && NULL == fNext);
|
||||
if (*head) {
|
||||
@ -232,7 +236,7 @@ private:
|
||||
SkTDArray<SkGlyph*> fGlyphArray;
|
||||
SkChunkAlloc fGlyphAlloc;
|
||||
SkChunkAlloc fImageAlloc;
|
||||
|
||||
|
||||
int fMetricsCount, fAdvanceCount;
|
||||
|
||||
struct CharGlyphRec {
|
||||
@ -241,7 +245,7 @@ private:
|
||||
};
|
||||
// no reason to use the same kHashCount as fGlyphHash, but we do for now
|
||||
CharGlyphRec fCharToGlyphHash[kHashCount];
|
||||
|
||||
|
||||
enum {
|
||||
// shift so that the top bits fall into kHashBits region
|
||||
kShiftForHashIndex = SkGlyph::kSubShift +
|
||||
@ -252,7 +256,7 @@ private:
|
||||
static inline unsigned ID2HashIndex(uint32_t id) {
|
||||
return (id ^ (id >> kShiftForHashIndex)) & kHashMask;
|
||||
}
|
||||
|
||||
|
||||
// used to track (approx) how much ram is tied-up in this cache
|
||||
size_t fMemoryUsed;
|
||||
|
||||
@ -302,7 +306,7 @@ public:
|
||||
}
|
||||
private:
|
||||
SkGlyphCache* fCache;
|
||||
|
||||
|
||||
static bool DetachProc(const SkGlyphCache*, void*);
|
||||
};
|
||||
|
||||
|
@ -83,6 +83,19 @@ SkGrFontScaler::~SkGrFontScaler() {
|
||||
GrSafeUnref(fKey);
|
||||
}
|
||||
|
||||
GrMaskFormat SkGrFontScaler::getMaskFormat() {
|
||||
SkMask::Format format = fStrike->getMaskFormat();
|
||||
switch (format) {
|
||||
case SkMask::kA8_Format:
|
||||
return kA8_GrMaskFormat;
|
||||
case SkMask::kLCD16_Format:
|
||||
return kA565_GrMaskFormat;
|
||||
default:
|
||||
GrAssert(!"unsupported SkMask::Format");
|
||||
return kA8_GrMaskFormat;
|
||||
}
|
||||
}
|
||||
|
||||
const GrKey* SkGrFontScaler::getKey() {
|
||||
if (NULL == fKey) {
|
||||
fKey = new SkGrDescKey(fStrike->getDescriptor());
|
||||
@ -117,8 +130,9 @@ bool SkGrFontScaler::getPackedGlyphImage(GrGlyph::PackedID packed,
|
||||
if (srcRB == dstRB) {
|
||||
memcpy(dst, src, dstRB * height);
|
||||
} else {
|
||||
const int bbp = GrMaskFormatBytesPerPixel(this->getMaskFormat());
|
||||
for (int y = 0; y < height; y++) {
|
||||
memcpy(dst, src, width);
|
||||
memcpy(dst, src, width * bbp);
|
||||
src = (const char*)src + srcRB;
|
||||
dst = (char*)dst + dstRB;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user