Merge "Add plumbing for better text scaling"

This commit is contained in:
Romain Guy
2013-01-08 15:26:45 -08:00
committed by Android (Google) Code Review
12 changed files with 264 additions and 233 deletions

View File

@ -1775,7 +1775,7 @@ status_t DisplayListRenderer::drawTextOnPath(const char* text, int bytesCount, i
paint->setAntiAlias(true);
SkPaint* addedPaint = addPaint(paint);
FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(addedPaint);
fontRenderer.precache(addedPaint, text, count);
fontRenderer.precache(addedPaint, text, count, *mSnapshot->transform);
return DrawGlInfo::kStatusDone;
}
@ -1789,7 +1789,7 @@ status_t DisplayListRenderer::drawPosText(const char* text, int bytesCount, int
paint->setAntiAlias(true);
SkPaint* addedPaint = addPaint(paint);
FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(addedPaint);
fontRenderer.precache(addedPaint, text, count);
fontRenderer.precache(addedPaint, text, count, *mSnapshot->transform);
return DrawGlInfo::kStatusDone;
}
@ -1823,7 +1823,7 @@ status_t DisplayListRenderer::drawText(const char* text, int bytesCount, int cou
SkPaint* addedPaint = addPaint(paint);
if (!reject) {
FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(addedPaint);
fontRenderer.precache(addedPaint, text, count);
fontRenderer.precache(addedPaint, text, count, *mSnapshot->transform);
}
addFloat(length);
addSkip(location);

View File

@ -36,7 +36,9 @@ namespace uirenderer {
static bool sLogFontRendererCreate = true;
FontRenderer::FontRenderer() {
FontRenderer::FontRenderer() :
mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity) {
if (sLogFontRendererCreate) {
INIT_LOGD("Creating FontRenderer");
}
@ -107,10 +109,11 @@ FontRenderer::~FontRenderer() {
delete[] mTextMesh;
}
Vector<Font*> fontsToDereference = mActiveFonts;
for (uint32_t i = 0; i < fontsToDereference.size(); i++) {
delete fontsToDereference[i];
LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
while (it.next()) {
delete it.value();
}
mActiveFonts.clear();
}
void FontRenderer::flushAllAndInvalidate() {
@ -118,8 +121,9 @@ void FontRenderer::flushAllAndInvalidate() {
issueDrawCommand();
}
for (uint32_t i = 0; i < mActiveFonts.size(); i++) {
mActiveFonts[i]->invalidateTextureCache();
LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
while (it.next()) {
it.value()->invalidateTextureCache();
}
for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
@ -146,8 +150,9 @@ void FontRenderer::flushLargeCaches() {
CacheTexture* cacheTexture = mCacheTextures[i];
if (cacheTexture->getTexture()) {
cacheTexture->init();
for (uint32_t j = 0; j < mActiveFonts.size(); j++) {
mActiveFonts[j]->invalidateTextureCache(cacheTexture);
LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
while (it.next()) {
it.value()->invalidateTextureCache(cacheTexture);
}
cacheTexture->releaseTexture();
}
@ -480,22 +485,8 @@ void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
}
}
void FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) {
int flags = 0;
if (paint->isFakeBoldText()) {
flags |= Font::kFakeBold;
}
const float skewX = paint->getTextSkewX();
uint32_t italicStyle = *(uint32_t*) &skewX;
const float scaleXFloat = paint->getTextScaleX();
uint32_t scaleX = *(uint32_t*) &scaleXFloat;
SkPaint::Style style = paint->getStyle();
const float strokeWidthFloat = paint->getStrokeWidth();
uint32_t strokeWidth = *(uint32_t*) &strokeWidthFloat;
mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle,
scaleX, style, strokeWidth);
void FontRenderer::setFont(SkPaint* paint, const mat4& matrix) {
mCurrentFont = Font::create(this, paint, matrix);
}
FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text,
@ -561,39 +552,11 @@ void FontRenderer::finishRender() {
}
}
void FontRenderer::precache(SkPaint* paint, const char* text, int numGlyphs) {
int flags = 0;
if (paint->isFakeBoldText()) {
flags |= Font::kFakeBold;
}
const float skewX = paint->getTextSkewX();
uint32_t italicStyle = *(uint32_t*) &skewX;
const float scaleXFloat = paint->getTextScaleX();
uint32_t scaleX = *(uint32_t*) &scaleXFloat;
SkPaint::Style style = paint->getStyle();
const float strokeWidthFloat = paint->getStrokeWidth();
uint32_t strokeWidth = *(uint32_t*) &strokeWidthFloat;
float fontSize = paint->getTextSize();
Font* font = Font::create(this, SkTypeface::UniqueID(paint->getTypeface()),
fontSize, flags, italicStyle, scaleX, style, strokeWidth);
void FontRenderer::precache(SkPaint* paint, const char* text, int numGlyphs, const mat4& matrix) {
Font* font = Font::create(this, paint, matrix);
font->precache(paint, text, numGlyphs);
}
bool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text,
uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, Rect* bounds) {
if (!mCurrentFont) {
ALOGE("No font set");
return false;
}
initRender(clip, bounds);
mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y);
finishRender();
return mDrawn;
}
bool FontRenderer::renderPosText(SkPaint* paint, const Rect* clip, const char *text,
uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
const float* positions, Rect* bounds) {
@ -625,12 +588,7 @@ bool FontRenderer::renderTextOnPath(SkPaint* paint, const Rect* clip, const char
}
void FontRenderer::removeFont(const Font* font) {
for (uint32_t ct = 0; ct < mActiveFonts.size(); ct++) {
if (mActiveFonts[ct] == font) {
mActiveFonts.removeAt(ct);
break;
}
}
mActiveFonts.remove(font->getDescription());
if (mCurrentFont == font) {
mCurrentFont = NULL;

View File

@ -17,6 +17,7 @@
#ifndef ANDROID_HWUI_FONT_RENDERER_H
#define ANDROID_HWUI_FONT_RENDERER_H
#include <utils/LruCache.h>
#include <utils/Vector.h>
#include <SkPaint.h>
@ -27,6 +28,7 @@
#include "font/CacheTexture.h"
#include "font/CachedGlyphInfo.h"
#include "font/Font.h"
#include "Matrix.h"
#include "Properties.h"
namespace android {
@ -47,13 +49,10 @@ public:
mGammaTable = gammaTable;
}
void setFont(SkPaint* paint, uint32_t fontId, float fontSize);
void setFont(SkPaint* paint, const mat4& matrix);
void precache(SkPaint* paint, const char* text, int numGlyphs);
void precache(SkPaint* paint, const char* text, int numGlyphs, const mat4& matrix);
// bounds is an out parameter
bool renderText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
uint32_t len, int numGlyphs, int x, int y, Rect* bounds);
// bounds is an out parameter
bool renderPosText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
uint32_t len, int numGlyphs, int x, int y, const float* positions, Rect* bounds);
@ -153,7 +152,7 @@ private:
Vector<CacheTexture*> mCacheTextures;
Font* mCurrentFont;
Vector<Font*> mActiveFonts;
LruCache<Font::FontDescription, Font*> mActiveFonts;
CacheTexture* mCurrentCacheTexture;

View File

@ -67,6 +67,14 @@ void LayerCache::setMaxSize(uint32_t maxSize) {
// Caching
///////////////////////////////////////////////////////////////////////////////
int LayerCache::LayerEntry::compare(const LayerCache::LayerEntry& lhs,
const LayerCache::LayerEntry& rhs) {
int deltaInt = int(lhs.mWidth) - int(rhs.mWidth);
if (deltaInt != 0) return deltaInt;
return int(lhs.mHeight) - int(rhs.mHeight);
}
void LayerCache::deleteLayer(Layer* layer) {
if (layer) {
LAYER_LOGD("Destroying layer %dx%d, fbo %d", layer->getWidth(), layer->getHeight(),

View File

@ -102,9 +102,6 @@ public:
*/
void dump();
private:
void deleteLayer(Layer* layer);
struct LayerEntry {
LayerEntry():
mLayer(NULL), mWidth(0), mHeight(0) {
@ -119,15 +116,14 @@ private:
mLayer(layer), mWidth(layer->getWidth()), mHeight(layer->getHeight()) {
}
bool operator<(const LayerEntry& rhs) const {
if (mWidth == rhs.mWidth) {
return mHeight < rhs.mHeight;
}
return mWidth < rhs.mWidth;
static int compare(const LayerEntry& lhs, const LayerEntry& rhs);
bool operator==(const LayerEntry& other) const {
return compare(*this, other) == 0;
}
bool operator==(const LayerEntry& rhs) const {
return mWidth == rhs.mWidth && mHeight == rhs.mHeight;
bool operator!=(const LayerEntry& other) const {
return compare(*this, other) != 0;
}
Layer* mLayer;
@ -135,12 +131,24 @@ private:
uint32_t mHeight;
}; // struct LayerEntry
private:
void deleteLayer(Layer* layer);
SortedList<LayerEntry> mCache;
uint32_t mSize;
uint32_t mMaxSize;
}; // class LayerCache
inline int strictly_order_type(const LayerCache::LayerEntry& lhs,
const LayerCache::LayerEntry& rhs) {
return LayerCache::LayerEntry::compare(lhs, rhs) < 0;
}
inline int compare_type(const LayerCache::LayerEntry& lhs, const LayerCache::LayerEntry& rhs) {
return LayerCache::LayerEntry::compare(lhs, rhs);
}
}; // namespace uirenderer
}; // namespace android

View File

@ -1716,7 +1716,6 @@ status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int mes
return DrawGlInfo::kStatusDone;
}
// TODO: We should compute the bounding box when recording the display list
float left = FLT_MAX;
float top = FLT_MAX;
float right = FLT_MIN;
@ -1754,7 +1753,6 @@ status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int mes
TextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1);
TextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2);
// TODO: This could be optimized to avoid unnecessary ops
left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx])));
top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy])));
right = fmaxf(right, fmaxf(vertices[ax], fmaxf(vertices[bx], vertices[cx])));
@ -2453,7 +2451,8 @@ status_t OpenGLRenderer::drawArc(float left, float top, float right, float botto
}
// TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 || p->getStrokeCap() != SkPaint::kButt_Cap || useCenter) {
if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 ||
p->getStrokeCap() != SkPaint::kButt_Cap || useCenter) {
mCaches.activeTexture(0);
const PathTexture* texture = mCaches.arcShapeCache.getArc(right - left, bottom - top,
startAngle, sweepAngle, useCenter, p);
@ -2577,16 +2576,15 @@ status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count
}
FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()),
paint->getTextSize());
fontRenderer.setFont(paint, *mSnapshot->transform);
int alpha;
SkXfermode::Mode mode;
getAlphaAndMode(paint, &alpha, &mode);
if (CC_UNLIKELY(mHasShadow)) {
drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer, alpha, mode,
0.0f, 0.0f);
drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
alpha, mode, 0.0f, 0.0f);
}
// Pick the appropriate texture filtering
@ -2655,6 +2653,14 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
return DrawGlInfo::kStatusDone;
}
#if DEBUG_GLYPHS
ALOGD("OpenGLRenderer drawText() with FontID=%d",
SkTypeface::UniqueID(paint->getTypeface()));
#endif
FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
fontRenderer.setFont(paint, *mSnapshot->transform);
const float oldX = x;
const float oldY = y;
const bool pureTranslate = mSnapshot->transform->isPureTranslate();
@ -2663,15 +2669,6 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
}
#if DEBUG_GLYPHS
ALOGD("OpenGLRenderer drawText() with FontID=%d",
SkTypeface::UniqueID(paint->getTypeface()));
#endif
FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()),
paint->getTextSize());
int alpha;
SkXfermode::Mode mode;
getAlphaAndMode(paint, &alpha, &mode);
@ -2744,8 +2741,7 @@ status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int co
}
FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()),
paint->getTextSize());
fontRenderer.setFont(paint, *mSnapshot->transform);
int alpha;
SkXfermode::Mode mode;
@ -2789,7 +2785,6 @@ status_t OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
mCaches.activeTexture(0);
// TODO: Perform early clip test before we rasterize the path
const PathTexture* texture = mCaches.pathCache.get(path, paint);
if (!texture) return DrawGlInfo::kStatusDone;
const AutoTexture autoCleanup(texture);

View File

@ -93,9 +93,6 @@ PathTexture* PathCache::get(SkPath* path, SkPaint* paint) {
PathCacheEntry entry(path, paint);
PathTexture* texture = mCache.get(entry);
float left, top, offset;
uint32_t width, height;
if (!texture) {
texture = addTexture(entry, path, paint);
} else if (path->getGenerationID() != texture->generation) {

View File

@ -18,6 +18,8 @@
#include <cutils/compiler.h>
#include <utils/JenkinsHash.h>
#include <SkUtils.h>
#include "Debug.h"
@ -33,14 +35,22 @@ namespace uirenderer {
// Font
///////////////////////////////////////////////////////////////////////////////
Font::Font(FontRenderer* state, uint32_t fontId, float fontSize,
int flags, uint32_t italicStyle, uint32_t scaleX,
SkPaint::Style style, uint32_t strokeWidth) :
mState(state), mFontId(fontId), mFontSize(fontSize),
mFlags(flags), mItalicStyle(italicStyle), mScaleX(scaleX),
mStyle(style), mStrokeWidth(mStrokeWidth) {
Font::Font(FontRenderer* state, const Font::FontDescription& desc) :
mState(state), mDescription(desc) {
}
Font::FontDescription::FontDescription(const SkPaint* paint, const mat4& matrix) {
mFontId = SkTypeface::UniqueID(paint->getTypeface());
mFontSize = paint->getTextSize();
mFlags = 0;
if (paint->isFakeBoldText()) {
mFlags |= Font::kFakeBold;
}
mItalicStyle = paint->getTextSkewX();
mScaleX = paint->getTextScaleX();
mStyle = paint->getStyle();
mStrokeWidth = paint->getStrokeWidth();
}
Font::~Font() {
mState->removeFont(this);
@ -50,6 +60,43 @@ Font::~Font() {
}
}
hash_t Font::FontDescription::hash() const {
uint32_t hash = JenkinsHashMix(0, mFontId);
hash = JenkinsHashMix(hash, android::hash_type(mFontSize));
hash = JenkinsHashMix(hash, android::hash_type(mFlags));
hash = JenkinsHashMix(hash, android::hash_type(mItalicStyle));
hash = JenkinsHashMix(hash, android::hash_type(mScaleX));
hash = JenkinsHashMix(hash, android::hash_type(mStyle));
hash = JenkinsHashMix(hash, android::hash_type(mStrokeWidth));
return JenkinsHashWhiten(hash);
}
int Font::FontDescription::compare(const Font::FontDescription& lhs,
const Font::FontDescription& rhs) {
int deltaInt = int(lhs.mFontId) - int(rhs.mFontId);
if (deltaInt != 0) return deltaInt;
if (lhs.mFontSize < rhs.mFontSize) return -1;
if (lhs.mFontSize > rhs.mFontSize) return +1;
if (lhs.mItalicStyle < rhs.mItalicStyle) return -1;
if (lhs.mItalicStyle > rhs.mItalicStyle) return +1;
deltaInt = int(lhs.mFlags) - int(rhs.mFlags);
if (deltaInt != 0) return deltaInt;
if (lhs.mScaleX < rhs.mScaleX) return -1;
if (lhs.mScaleX > rhs.mScaleX) return +1;
deltaInt = int(lhs.mStyle) - int(rhs.mStyle);
if (deltaInt != 0) return deltaInt;
if (lhs.mStrokeWidth < rhs.mStrokeWidth) return -1;
if (lhs.mStrokeWidth > rhs.mStrokeWidth) return +1;
return 0;
}
void Font::invalidateTextureCache(CacheTexture* cacheTexture) {
for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueAt(i);
@ -83,17 +130,17 @@ void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y,
void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
int nPenX = x + glyph->mBitmapLeft;
int nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight;
float nPenX = x + glyph->mBitmapLeft;
float nPenY = y + (glyph->mBitmapTop + glyph->mBitmapHeight);
float width = (float) glyph->mBitmapWidth;
float height = (float) glyph->mBitmapHeight;
float u1 = glyph->mBitmapMinU;
float u2 = glyph->mBitmapMaxU;
float v1 = glyph->mBitmapMinV;
float v2 = glyph->mBitmapMaxV;
int width = (int) glyph->mBitmapWidth;
int height = (int) glyph->mBitmapHeight;
mState->appendMeshQuad(nPenX, nPenY, u1, v2,
nPenX + width, nPenY, u2, v2,
nPenX + width, nPenY - height, u2, v1,
@ -176,24 +223,13 @@ CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit, bool pre
// Is the glyph still in texture cache?
if (!cachedGlyph->mIsValid) {
const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit);
const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit, NULL);
updateGlyphCache(paint, skiaGlyph, cachedGlyph, precaching);
}
return cachedGlyph;
}
void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
int numGlyphs, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
if (bitmap != NULL && bitmapW > 0 && bitmapH > 0) {
render(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap,
bitmapW, bitmapH, NULL, NULL);
} else {
render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
0, 0, NULL, NULL);
}
}
void Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
int numGlyphs, int x, int y, const float* positions) {
render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
@ -298,38 +334,8 @@ void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len
text += start;
int glyphsCount = 0;
if (CC_LIKELY(positions == NULL)) {
SkFixed prevRsbDelta = 0;
float penX = x + 0.5f;
int penY = y;
while (glyphsCount < numGlyphs) {
glyph_t glyph = GET_GLYPH(text);
// Reached the end of the string
if (IS_END_OF_STRING(glyph)) {
break;
}
CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta));
prevRsbDelta = cachedGlyph->mRsbDelta;
// If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
if (cachedGlyph->mIsValid) {
(*this.*render)(cachedGlyph, (int) floorf(penX), penY,
bitmap, bitmapW, bitmapH, bounds, positions);
}
penX += SkFixedToFloat(cachedGlyph->mAdvanceX);
glyphsCount++;
}
} else {
const SkPaint::Align align = paint->getTextAlign();
// This is for renderPosText()
while (glyphsCount < numGlyphs) {
glyph_t glyph = GET_GLYPH(text);
@ -364,7 +370,6 @@ void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len
glyphsCount++;
}
}
}
void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph,
bool precaching) {
@ -379,7 +384,7 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp
uint32_t startY = 0;
// Get the bitmap for the glyph
paint->findImage(skiaGlyph);
paint->findImage(skiaGlyph, NULL);
mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY, precaching);
if (!glyph->mIsValid) {
@ -409,7 +414,7 @@ CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph, bool precaching
CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
mCachedGlyphs.add(glyph, newGlyph);
const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph);
const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph, NULL);
newGlyph->mGlyphIndex = skiaGlyph.fID;
newGlyph->mIsValid = false;
@ -418,24 +423,16 @@ CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph, bool precaching
return newGlyph;
}
Font* Font::create(FontRenderer* state, uint32_t fontId, float fontSize,
int flags, uint32_t italicStyle, uint32_t scaleX,
SkPaint::Style style, uint32_t strokeWidth) {
Vector<Font*> &activeFonts = state->mActiveFonts;
Font* Font::create(FontRenderer* state, const SkPaint* paint, const mat4& matrix) {
FontDescription description(paint, matrix);
Font* font = state->mActiveFonts.get(description);
for (uint32_t i = 0; i < activeFonts.size(); i++) {
Font* font = activeFonts[i];
if (font->mFontId == fontId && font->mFontSize == fontSize &&
font->mFlags == flags && font->mItalicStyle == italicStyle &&
font->mScaleX == scaleX && font->mStyle == style &&
(style == SkPaint::kFill_Style || font->mStrokeWidth == strokeWidth)) {
if (font) {
return font;
}
}
Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle,
scaleX, style, strokeWidth);
activeFonts.push(newFont);
Font* newFont = new Font(state, description);
state->mActiveFonts.put(description, newFont);
return newFont;
}

View File

@ -25,6 +25,7 @@
#include "CachedGlyphInfo.h"
#include "../Rect.h"
#include "../Matrix.h"
namespace android {
namespace uirenderer {
@ -45,15 +46,31 @@ public:
kFakeBold = 1
};
~Font();
struct FontDescription {
FontDescription(const SkPaint* paint, const mat4& matrix);
/**
* Renders the specified string of text.
* If bitmap is specified, it will be used as the render target
*/
void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
int numGlyphs, int x, int y, uint8_t *bitmap = NULL,
uint32_t bitmapW = 0, uint32_t bitmapH = 0);
static int compare(const FontDescription& lhs, const FontDescription& rhs);
hash_t hash() const;
bool operator==(const FontDescription& other) const {
return compare(*this, other) == 0;
}
bool operator!=(const FontDescription& other) const {
return compare(*this, other) != 0;
}
SkFontID mFontId;
float mFontSize;
int mFlags;
float mItalicStyle;
float mScaleX;
uint8_t mStyle;
float mStrokeWidth;
};
~Font();
void render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
int numGlyphs, int x, int y, const float* positions);
@ -61,15 +78,20 @@ public:
void render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
int numGlyphs, SkPath* path, float hOffset, float vOffset);
const Font::FontDescription& getDescription() const {
return mDescription;
}
/**
* Creates a new font associated with the specified font state.
*/
static Font* create(FontRenderer* state, uint32_t fontId, float fontSize,
int flags, uint32_t italicStyle, uint32_t scaleX, SkPaint::Style style,
uint32_t strokeWidth);
static Font* create(FontRenderer* state, const SkPaint* paint, const mat4& matrix);
private:
friend class FontRenderer;
Font(FontRenderer* state, const Font::FontDescription& desc);
typedef void (Font::*RenderGlyph)(CachedGlyphInfo*, int, int, uint8_t*,
uint32_t, uint32_t, Rect*, const float*);
@ -88,12 +110,6 @@ private:
void measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
int numGlyphs, Rect *bounds, const float* positions);
Font(FontRenderer* state, uint32_t fontId, float fontSize, int flags, uint32_t italicStyle,
uint32_t scaleX, SkPaint::Style style, uint32_t strokeWidth);
// Cache of glyphs
DefaultKeyedVector<glyph_t, CachedGlyphInfo*> mCachedGlyphs;
void invalidateTextureCache(CacheTexture* cacheTexture = NULL);
CachedGlyphInfo* cacheGlyph(SkPaint* paint, glyph_t glyph, bool precaching);
@ -115,15 +131,25 @@ private:
CachedGlyphInfo* getCachedGlyph(SkPaint* paint, glyph_t textUnit, bool precaching = false);
FontRenderer* mState;
uint32_t mFontId;
float mFontSize;
int mFlags;
uint32_t mItalicStyle;
uint32_t mScaleX;
SkPaint::Style mStyle;
uint32_t mStrokeWidth;
FontDescription mDescription;
// Cache of glyphs
DefaultKeyedVector<glyph_t, CachedGlyphInfo*> mCachedGlyphs;
};
inline int strictly_order_type(const Font::FontDescription& lhs,
const Font::FontDescription& rhs) {
return Font::FontDescription::compare(lhs, rhs) < 0;
}
inline int compare_type(const Font::FontDescription& lhs, const Font::FontDescription& rhs) {
return Font::FontDescription::compare(lhs, rhs);
}
inline hash_t hash_type(const Font::FontDescription& entry) {
return entry.hash();
}
}; // namespace uirenderer
}; // namespace android

View File

@ -37,7 +37,7 @@
#if RENDER_TEXT_AS_GLYPHS
typedef uint16_t glyph_t;
#define TO_GLYPH(g) g
#define GET_METRICS(paint, glyph) paint->getGlyphMetrics(glyph)
#define GET_METRICS(paint, glyph, matrix) paint->getGlyphMetrics(glyph, matrix)
#define GET_GLYPH(text) nextGlyph((const uint16_t**) &text)
#define IS_END_OF_STRING(glyph) false
@ -50,7 +50,7 @@
#else
typedef SkUnichar glyph_t;
#define TO_GLYPH(g) ((SkUnichar) g)
#define GET_METRICS(paint, glyph) paint->getUnicharMetrics(glyph)
#define GET_METRICS(paint, glyph, matrix) paint->getUnicharMetrics(glyph, matrix)
#define GET_GLYPH(text) SkUTF16_NextUnichar((const uint16_t**) &text)
#define IS_END_OF_STRING(glyph) glyph < 0
#endif

View File

@ -21,6 +21,7 @@ import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Bundle;
import android.view.View;
@ -43,15 +44,27 @@ public class ScaledTextActivity extends Activity {
}
public static class ScaledTextView extends View {
private static final String TEXT = "Hello libhwui! ";
private final Paint mPaint;
private final Paint mShadowPaint;
private final Path mPath;
private float mScale = 1.0f;
public ScaledTextView(Context c) {
super(c);
mPath = makePath();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setTextSize(20.0f);
mShadowPaint = new Paint();
mShadowPaint.setAntiAlias(true);
mShadowPaint.setShadowLayer(3.0f, 0.0f, 3.0f, 0xff000000);
mShadowPaint.setTextSize(20.0f);
}
public float getTextScale() {
@ -63,17 +76,47 @@ public class ScaledTextActivity extends Activity {
invalidate();
}
private static Path makePath() {
Path path = new Path();
buildPath(path);
return path;
}
private static void buildPath(Path path) {
path.moveTo(0.0f, 0.0f);
path.cubicTo(0.0f, 0.0f, 100.0f, 150.0f, 100.0f, 200.0f);
path.cubicTo(100.0f, 200.0f, 50.0f, 300.0f, -80.0f, 200.0f);
path.cubicTo(-80.0f, 200.0f, 100.0f, 200.0f, 200.0f, 0.0f);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawARGB(255, 255, 255, 255);
canvas.drawText("Hello libhwui!", 30.0f, 30.0f, mPaint);
canvas.drawText(TEXT, 30.0f, 30.0f, mPaint);
canvas.translate(0.0f, 50.0f);
canvas.save();
canvas.scale(mScale, mScale);
canvas.drawText("Hello libhwui!", 30.0f, 30.0f, mPaint);
canvas.drawText(TEXT, 30.0f, 30.0f, mPaint);
canvas.restore();
canvas.translate(0.0f, 250.0f);
canvas.save();
canvas.scale(3.0f, 3.0f);
canvas.drawText(TEXT, 30.0f, 30.0f, mShadowPaint);
canvas.translate(100.0f, 0.0f);
// canvas.drawTextOnPath(TEXT + TEXT + TEXT, mPath, 0.0f, 0.0f, mPaint);
canvas.restore();
float width = mPaint.measureText(TEXT);
canvas.translate(500.0f, 0.0f);
canvas.rotate(45.0f, width * 3.0f / 2.0f, 0.0f);
canvas.scale(3.0f, 3.0f);
canvas.drawText(TEXT, 30.0f, 30.0f, mPaint);
}
}
}

View File

@ -41,26 +41,26 @@ public class TextOnPathActivity extends Activity {
setContentView(view);
}
private Path makePath() {
private static Path makePath() {
Path path = new Path();
buildPath(path);
return path;
}
private void buildPath(Path path) {
private static void buildPath(Path path) {
path.moveTo(0.0f, 0.0f);
path.cubicTo(0.0f, 0.0f, 100.0f, 150.0f, 100.0f, 200.0f);
path.cubicTo(100.0f, 200.0f, 50.0f, 300.0f, -80.0f, 200.0f);
path.cubicTo(-80.0f, 200.0f, 100.0f, 200.0f, 200.0f, 0.0f);
}
private Path makeStraightPath() {
private static Path makeStraightPath() {
Path path = new Path();
buildStraightPath(path);
return path;
}
private void buildStraightPath(Path path) {
private static void buildStraightPath(Path path) {
path.moveTo(0.0f, 0.0f);
path.lineTo(400.0f, 0.0f);
}