Merge "Add plumbing for better text scaling"
This commit is contained in:
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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(),
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user