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:
reed@google.com 2011-03-15 15:40:16 +00:00
parent b7e9aee1ac
commit 98539c607b
10 changed files with 128 additions and 49 deletions

View File

@ -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; }

View File

@ -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;

View File

@ -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*);
};

View File

@ -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.
*/

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -231,7 +231,7 @@ public:
SkGrRegionIterator() {}
SkGrRegionIterator(const SkRegion& region) { this->reset(region); }
void reset(const SkRegion& region) {
void reset(const SkRegion& region) {
fRegion = &region;
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);

View File

@ -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*);
};

View File

@ -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;
}