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);
|
paint->setAntiAlias(true);
|
||||||
SkPaint* addedPaint = addPaint(paint);
|
SkPaint* addedPaint = addPaint(paint);
|
||||||
FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(addedPaint);
|
FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(addedPaint);
|
||||||
fontRenderer.precache(addedPaint, text, count);
|
fontRenderer.precache(addedPaint, text, count, *mSnapshot->transform);
|
||||||
return DrawGlInfo::kStatusDone;
|
return DrawGlInfo::kStatusDone;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1789,7 +1789,7 @@ status_t DisplayListRenderer::drawPosText(const char* text, int bytesCount, int
|
|||||||
paint->setAntiAlias(true);
|
paint->setAntiAlias(true);
|
||||||
SkPaint* addedPaint = addPaint(paint);
|
SkPaint* addedPaint = addPaint(paint);
|
||||||
FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(addedPaint);
|
FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(addedPaint);
|
||||||
fontRenderer.precache(addedPaint, text, count);
|
fontRenderer.precache(addedPaint, text, count, *mSnapshot->transform);
|
||||||
return DrawGlInfo::kStatusDone;
|
return DrawGlInfo::kStatusDone;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1823,7 +1823,7 @@ status_t DisplayListRenderer::drawText(const char* text, int bytesCount, int cou
|
|||||||
SkPaint* addedPaint = addPaint(paint);
|
SkPaint* addedPaint = addPaint(paint);
|
||||||
if (!reject) {
|
if (!reject) {
|
||||||
FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(addedPaint);
|
FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(addedPaint);
|
||||||
fontRenderer.precache(addedPaint, text, count);
|
fontRenderer.precache(addedPaint, text, count, *mSnapshot->transform);
|
||||||
}
|
}
|
||||||
addFloat(length);
|
addFloat(length);
|
||||||
addSkip(location);
|
addSkip(location);
|
||||||
|
@ -36,7 +36,9 @@ namespace uirenderer {
|
|||||||
|
|
||||||
static bool sLogFontRendererCreate = true;
|
static bool sLogFontRendererCreate = true;
|
||||||
|
|
||||||
FontRenderer::FontRenderer() {
|
FontRenderer::FontRenderer() :
|
||||||
|
mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity) {
|
||||||
|
|
||||||
if (sLogFontRendererCreate) {
|
if (sLogFontRendererCreate) {
|
||||||
INIT_LOGD("Creating FontRenderer");
|
INIT_LOGD("Creating FontRenderer");
|
||||||
}
|
}
|
||||||
@ -107,10 +109,11 @@ FontRenderer::~FontRenderer() {
|
|||||||
delete[] mTextMesh;
|
delete[] mTextMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<Font*> fontsToDereference = mActiveFonts;
|
LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
|
||||||
for (uint32_t i = 0; i < fontsToDereference.size(); i++) {
|
while (it.next()) {
|
||||||
delete fontsToDereference[i];
|
delete it.value();
|
||||||
}
|
}
|
||||||
|
mActiveFonts.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FontRenderer::flushAllAndInvalidate() {
|
void FontRenderer::flushAllAndInvalidate() {
|
||||||
@ -118,8 +121,9 @@ void FontRenderer::flushAllAndInvalidate() {
|
|||||||
issueDrawCommand();
|
issueDrawCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < mActiveFonts.size(); i++) {
|
LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
|
||||||
mActiveFonts[i]->invalidateTextureCache();
|
while (it.next()) {
|
||||||
|
it.value()->invalidateTextureCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
|
for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
|
||||||
@ -146,8 +150,9 @@ void FontRenderer::flushLargeCaches() {
|
|||||||
CacheTexture* cacheTexture = mCacheTextures[i];
|
CacheTexture* cacheTexture = mCacheTextures[i];
|
||||||
if (cacheTexture->getTexture()) {
|
if (cacheTexture->getTexture()) {
|
||||||
cacheTexture->init();
|
cacheTexture->init();
|
||||||
for (uint32_t j = 0; j < mActiveFonts.size(); j++) {
|
LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
|
||||||
mActiveFonts[j]->invalidateTextureCache(cacheTexture);
|
while (it.next()) {
|
||||||
|
it.value()->invalidateTextureCache(cacheTexture);
|
||||||
}
|
}
|
||||||
cacheTexture->releaseTexture();
|
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) {
|
void FontRenderer::setFont(SkPaint* paint, const mat4& matrix) {
|
||||||
int flags = 0;
|
mCurrentFont = Font::create(this, paint, matrix);
|
||||||
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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text,
|
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) {
|
void FontRenderer::precache(SkPaint* paint, const char* text, int numGlyphs, const mat4& matrix) {
|
||||||
int flags = 0;
|
Font* font = Font::create(this, paint, matrix);
|
||||||
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);
|
|
||||||
|
|
||||||
font->precache(paint, text, numGlyphs);
|
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,
|
bool FontRenderer::renderPosText(SkPaint* paint, const Rect* clip, const char *text,
|
||||||
uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
|
uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
|
||||||
const float* positions, Rect* bounds) {
|
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) {
|
void FontRenderer::removeFont(const Font* font) {
|
||||||
for (uint32_t ct = 0; ct < mActiveFonts.size(); ct++) {
|
mActiveFonts.remove(font->getDescription());
|
||||||
if (mActiveFonts[ct] == font) {
|
|
||||||
mActiveFonts.removeAt(ct);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mCurrentFont == font) {
|
if (mCurrentFont == font) {
|
||||||
mCurrentFont = NULL;
|
mCurrentFont = NULL;
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#ifndef ANDROID_HWUI_FONT_RENDERER_H
|
#ifndef ANDROID_HWUI_FONT_RENDERER_H
|
||||||
#define ANDROID_HWUI_FONT_RENDERER_H
|
#define ANDROID_HWUI_FONT_RENDERER_H
|
||||||
|
|
||||||
|
#include <utils/LruCache.h>
|
||||||
#include <utils/Vector.h>
|
#include <utils/Vector.h>
|
||||||
|
|
||||||
#include <SkPaint.h>
|
#include <SkPaint.h>
|
||||||
@ -27,6 +28,7 @@
|
|||||||
#include "font/CacheTexture.h"
|
#include "font/CacheTexture.h"
|
||||||
#include "font/CachedGlyphInfo.h"
|
#include "font/CachedGlyphInfo.h"
|
||||||
#include "font/Font.h"
|
#include "font/Font.h"
|
||||||
|
#include "Matrix.h"
|
||||||
#include "Properties.h"
|
#include "Properties.h"
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
@ -47,13 +49,10 @@ public:
|
|||||||
mGammaTable = gammaTable;
|
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
|
// bounds is an out parameter
|
||||||
bool renderPosText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
|
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);
|
uint32_t len, int numGlyphs, int x, int y, const float* positions, Rect* bounds);
|
||||||
@ -153,7 +152,7 @@ private:
|
|||||||
Vector<CacheTexture*> mCacheTextures;
|
Vector<CacheTexture*> mCacheTextures;
|
||||||
|
|
||||||
Font* mCurrentFont;
|
Font* mCurrentFont;
|
||||||
Vector<Font*> mActiveFonts;
|
LruCache<Font::FontDescription, Font*> mActiveFonts;
|
||||||
|
|
||||||
CacheTexture* mCurrentCacheTexture;
|
CacheTexture* mCurrentCacheTexture;
|
||||||
|
|
||||||
|
@ -67,6 +67,14 @@ void LayerCache::setMaxSize(uint32_t maxSize) {
|
|||||||
// Caching
|
// 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) {
|
void LayerCache::deleteLayer(Layer* layer) {
|
||||||
if (layer) {
|
if (layer) {
|
||||||
LAYER_LOGD("Destroying layer %dx%d, fbo %d", layer->getWidth(), layer->getHeight(),
|
LAYER_LOGD("Destroying layer %dx%d, fbo %d", layer->getWidth(), layer->getHeight(),
|
||||||
|
@ -102,9 +102,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
void dump();
|
void dump();
|
||||||
|
|
||||||
private:
|
|
||||||
void deleteLayer(Layer* layer);
|
|
||||||
|
|
||||||
struct LayerEntry {
|
struct LayerEntry {
|
||||||
LayerEntry():
|
LayerEntry():
|
||||||
mLayer(NULL), mWidth(0), mHeight(0) {
|
mLayer(NULL), mWidth(0), mHeight(0) {
|
||||||
@ -119,15 +116,14 @@ private:
|
|||||||
mLayer(layer), mWidth(layer->getWidth()), mHeight(layer->getHeight()) {
|
mLayer(layer), mWidth(layer->getWidth()), mHeight(layer->getHeight()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator<(const LayerEntry& rhs) const {
|
static int compare(const LayerEntry& lhs, const LayerEntry& rhs);
|
||||||
if (mWidth == rhs.mWidth) {
|
|
||||||
return mHeight < rhs.mHeight;
|
bool operator==(const LayerEntry& other) const {
|
||||||
}
|
return compare(*this, other) == 0;
|
||||||
return mWidth < rhs.mWidth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const LayerEntry& rhs) const {
|
bool operator!=(const LayerEntry& other) const {
|
||||||
return mWidth == rhs.mWidth && mHeight == rhs.mHeight;
|
return compare(*this, other) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Layer* mLayer;
|
Layer* mLayer;
|
||||||
@ -135,12 +131,24 @@ private:
|
|||||||
uint32_t mHeight;
|
uint32_t mHeight;
|
||||||
}; // struct LayerEntry
|
}; // struct LayerEntry
|
||||||
|
|
||||||
|
private:
|
||||||
|
void deleteLayer(Layer* layer);
|
||||||
|
|
||||||
SortedList<LayerEntry> mCache;
|
SortedList<LayerEntry> mCache;
|
||||||
|
|
||||||
uint32_t mSize;
|
uint32_t mSize;
|
||||||
uint32_t mMaxSize;
|
uint32_t mMaxSize;
|
||||||
}; // class LayerCache
|
}; // 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 uirenderer
|
||||||
}; // namespace android
|
}; // namespace android
|
||||||
|
|
||||||
|
@ -1716,7 +1716,6 @@ status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int mes
|
|||||||
return DrawGlInfo::kStatusDone;
|
return DrawGlInfo::kStatusDone;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: We should compute the bounding box when recording the display list
|
|
||||||
float left = FLT_MAX;
|
float left = FLT_MAX;
|
||||||
float top = FLT_MAX;
|
float top = FLT_MAX;
|
||||||
float right = FLT_MIN;
|
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[cx], vertices[cy], u2, v1);
|
||||||
TextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2);
|
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])));
|
left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx])));
|
||||||
top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy])));
|
top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy])));
|
||||||
right = fmaxf(right, fmaxf(vertices[ax], fmaxf(vertices[bx], vertices[cx])));
|
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)
|
// 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);
|
mCaches.activeTexture(0);
|
||||||
const PathTexture* texture = mCaches.arcShapeCache.getArc(right - left, bottom - top,
|
const PathTexture* texture = mCaches.arcShapeCache.getArc(right - left, bottom - top,
|
||||||
startAngle, sweepAngle, useCenter, p);
|
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& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
|
||||||
fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()),
|
fontRenderer.setFont(paint, *mSnapshot->transform);
|
||||||
paint->getTextSize());
|
|
||||||
|
|
||||||
int alpha;
|
int alpha;
|
||||||
SkXfermode::Mode mode;
|
SkXfermode::Mode mode;
|
||||||
getAlphaAndMode(paint, &alpha, &mode);
|
getAlphaAndMode(paint, &alpha, &mode);
|
||||||
|
|
||||||
if (CC_UNLIKELY(mHasShadow)) {
|
if (CC_UNLIKELY(mHasShadow)) {
|
||||||
drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer, alpha, mode,
|
drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
|
||||||
0.0f, 0.0f);
|
alpha, mode, 0.0f, 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pick the appropriate texture filtering
|
// Pick the appropriate texture filtering
|
||||||
@ -2655,6 +2653,14 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
|
|||||||
return DrawGlInfo::kStatusDone;
|
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 oldX = x;
|
||||||
const float oldY = y;
|
const float oldY = y;
|
||||||
const bool pureTranslate = mSnapshot->transform->isPureTranslate();
|
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);
|
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;
|
int alpha;
|
||||||
SkXfermode::Mode mode;
|
SkXfermode::Mode mode;
|
||||||
getAlphaAndMode(paint, &alpha, &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& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
|
||||||
fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()),
|
fontRenderer.setFont(paint, *mSnapshot->transform);
|
||||||
paint->getTextSize());
|
|
||||||
|
|
||||||
int alpha;
|
int alpha;
|
||||||
SkXfermode::Mode mode;
|
SkXfermode::Mode mode;
|
||||||
@ -2789,7 +2785,6 @@ status_t OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
|
|||||||
|
|
||||||
mCaches.activeTexture(0);
|
mCaches.activeTexture(0);
|
||||||
|
|
||||||
// TODO: Perform early clip test before we rasterize the path
|
|
||||||
const PathTexture* texture = mCaches.pathCache.get(path, paint);
|
const PathTexture* texture = mCaches.pathCache.get(path, paint);
|
||||||
if (!texture) return DrawGlInfo::kStatusDone;
|
if (!texture) return DrawGlInfo::kStatusDone;
|
||||||
const AutoTexture autoCleanup(texture);
|
const AutoTexture autoCleanup(texture);
|
||||||
|
@ -93,9 +93,6 @@ PathTexture* PathCache::get(SkPath* path, SkPaint* paint) {
|
|||||||
PathCacheEntry entry(path, paint);
|
PathCacheEntry entry(path, paint);
|
||||||
PathTexture* texture = mCache.get(entry);
|
PathTexture* texture = mCache.get(entry);
|
||||||
|
|
||||||
float left, top, offset;
|
|
||||||
uint32_t width, height;
|
|
||||||
|
|
||||||
if (!texture) {
|
if (!texture) {
|
||||||
texture = addTexture(entry, path, paint);
|
texture = addTexture(entry, path, paint);
|
||||||
} else if (path->getGenerationID() != texture->generation) {
|
} else if (path->getGenerationID() != texture->generation) {
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
#include <cutils/compiler.h>
|
#include <cutils/compiler.h>
|
||||||
|
|
||||||
|
#include <utils/JenkinsHash.h>
|
||||||
|
|
||||||
#include <SkUtils.h>
|
#include <SkUtils.h>
|
||||||
|
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
@ -33,14 +35,22 @@ namespace uirenderer {
|
|||||||
// Font
|
// Font
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Font::Font(FontRenderer* state, uint32_t fontId, float fontSize,
|
Font::Font(FontRenderer* state, const Font::FontDescription& desc) :
|
||||||
int flags, uint32_t italicStyle, uint32_t scaleX,
|
mState(state), mDescription(desc) {
|
||||||
SkPaint::Style style, uint32_t strokeWidth) :
|
|
||||||
mState(state), mFontId(fontId), mFontSize(fontSize),
|
|
||||||
mFlags(flags), mItalicStyle(italicStyle), mScaleX(scaleX),
|
|
||||||
mStyle(style), mStrokeWidth(mStrokeWidth) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
Font::~Font() {
|
||||||
mState->removeFont(this);
|
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) {
|
void Font::invalidateTextureCache(CacheTexture* cacheTexture) {
|
||||||
for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
|
for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
|
||||||
CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueAt(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,
|
void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
|
||||||
uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
|
uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
|
||||||
int nPenX = x + glyph->mBitmapLeft;
|
float nPenX = x + glyph->mBitmapLeft;
|
||||||
int nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight;
|
float nPenY = y + (glyph->mBitmapTop + glyph->mBitmapHeight);
|
||||||
|
|
||||||
|
float width = (float) glyph->mBitmapWidth;
|
||||||
|
float height = (float) glyph->mBitmapHeight;
|
||||||
|
|
||||||
float u1 = glyph->mBitmapMinU;
|
float u1 = glyph->mBitmapMinU;
|
||||||
float u2 = glyph->mBitmapMaxU;
|
float u2 = glyph->mBitmapMaxU;
|
||||||
float v1 = glyph->mBitmapMinV;
|
float v1 = glyph->mBitmapMinV;
|
||||||
float v2 = glyph->mBitmapMaxV;
|
float v2 = glyph->mBitmapMaxV;
|
||||||
|
|
||||||
int width = (int) glyph->mBitmapWidth;
|
|
||||||
int height = (int) glyph->mBitmapHeight;
|
|
||||||
|
|
||||||
mState->appendMeshQuad(nPenX, nPenY, u1, v2,
|
mState->appendMeshQuad(nPenX, nPenY, u1, v2,
|
||||||
nPenX + width, nPenY, u2, v2,
|
nPenX + width, nPenY, u2, v2,
|
||||||
nPenX + width, nPenY - height, u2, v1,
|
nPenX + width, nPenY - height, u2, v1,
|
||||||
@ -136,7 +183,7 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float
|
|||||||
vOffset += glyph->mBitmapTop + height;
|
vOffset += glyph->mBitmapTop + height;
|
||||||
|
|
||||||
SkPoint destination[4];
|
SkPoint destination[4];
|
||||||
measure.getPosTan(x + hOffset + glyph->mBitmapLeft + halfWidth, position, tangent);
|
measure.getPosTan(x + hOffset + glyph->mBitmapLeft + halfWidth, position, tangent);
|
||||||
|
|
||||||
// Move along the tangent and offset by the normal
|
// Move along the tangent and offset by the normal
|
||||||
destination[0].set(-tangent->fX * halfWidth - tangent->fY * vOffset,
|
destination[0].set(-tangent->fX * halfWidth - tangent->fY * vOffset,
|
||||||
@ -176,24 +223,13 @@ CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit, bool pre
|
|||||||
|
|
||||||
// Is the glyph still in texture cache?
|
// Is the glyph still in texture cache?
|
||||||
if (!cachedGlyph->mIsValid) {
|
if (!cachedGlyph->mIsValid) {
|
||||||
const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit);
|
const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit, NULL);
|
||||||
updateGlyphCache(paint, skiaGlyph, cachedGlyph, precaching);
|
updateGlyphCache(paint, skiaGlyph, cachedGlyph, precaching);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cachedGlyph;
|
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,
|
void Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
|
||||||
int numGlyphs, int x, int y, const float* positions) {
|
int numGlyphs, int x, int y, const float* positions) {
|
||||||
render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
|
render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
|
||||||
@ -298,71 +334,40 @@ void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len
|
|||||||
text += start;
|
text += start;
|
||||||
int glyphsCount = 0;
|
int glyphsCount = 0;
|
||||||
|
|
||||||
if (CC_LIKELY(positions == NULL)) {
|
const SkPaint::Align align = paint->getTextAlign();
|
||||||
SkFixed prevRsbDelta = 0;
|
|
||||||
|
|
||||||
float penX = x + 0.5f;
|
while (glyphsCount < numGlyphs) {
|
||||||
int penY = y;
|
glyph_t glyph = GET_GLYPH(text);
|
||||||
|
|
||||||
while (glyphsCount < numGlyphs) {
|
// Reached the end of the string
|
||||||
glyph_t glyph = GET_GLYPH(text);
|
if (IS_END_OF_STRING(glyph)) {
|
||||||
|
break;
|
||||||
// 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()
|
CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
|
||||||
while (glyphsCount < numGlyphs) {
|
|
||||||
glyph_t glyph = GET_GLYPH(text);
|
|
||||||
|
|
||||||
// Reached the end of the string
|
// If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
|
||||||
if (IS_END_OF_STRING(glyph)) {
|
if (cachedGlyph->mIsValid) {
|
||||||
break;
|
int penX = x + positions[(glyphsCount << 1)];
|
||||||
|
int penY = y + positions[(glyphsCount << 1) + 1];
|
||||||
|
|
||||||
|
switch (align) {
|
||||||
|
case SkPaint::kRight_Align:
|
||||||
|
penX -= SkFixedToFloat(cachedGlyph->mAdvanceX);
|
||||||
|
penY -= SkFixedToFloat(cachedGlyph->mAdvanceY);
|
||||||
|
break;
|
||||||
|
case SkPaint::kCenter_Align:
|
||||||
|
penX -= SkFixedToFloat(cachedGlyph->mAdvanceX >> 1);
|
||||||
|
penY -= SkFixedToFloat(cachedGlyph->mAdvanceY >> 1);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
|
(*this.*render)(cachedGlyph, penX, penY,
|
||||||
|
bitmap, bitmapW, bitmapH, bounds, positions);
|
||||||
// If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
|
|
||||||
if (cachedGlyph->mIsValid) {
|
|
||||||
int penX = x + positions[(glyphsCount << 1)];
|
|
||||||
int penY = y + positions[(glyphsCount << 1) + 1];
|
|
||||||
|
|
||||||
switch (align) {
|
|
||||||
case SkPaint::kRight_Align:
|
|
||||||
penX -= SkFixedToFloat(cachedGlyph->mAdvanceX);
|
|
||||||
penY -= SkFixedToFloat(cachedGlyph->mAdvanceY);
|
|
||||||
break;
|
|
||||||
case SkPaint::kCenter_Align:
|
|
||||||
penX -= SkFixedToFloat(cachedGlyph->mAdvanceX >> 1);
|
|
||||||
penY -= SkFixedToFloat(cachedGlyph->mAdvanceY >> 1);
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*this.*render)(cachedGlyph, penX, penY,
|
|
||||||
bitmap, bitmapW, bitmapH, bounds, positions);
|
|
||||||
}
|
|
||||||
|
|
||||||
glyphsCount++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glyphsCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,7 +384,7 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp
|
|||||||
uint32_t startY = 0;
|
uint32_t startY = 0;
|
||||||
|
|
||||||
// Get the bitmap for the glyph
|
// Get the bitmap for the glyph
|
||||||
paint->findImage(skiaGlyph);
|
paint->findImage(skiaGlyph, NULL);
|
||||||
mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY, precaching);
|
mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY, precaching);
|
||||||
|
|
||||||
if (!glyph->mIsValid) {
|
if (!glyph->mIsValid) {
|
||||||
@ -409,7 +414,7 @@ CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph, bool precaching
|
|||||||
CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
|
CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
|
||||||
mCachedGlyphs.add(glyph, newGlyph);
|
mCachedGlyphs.add(glyph, newGlyph);
|
||||||
|
|
||||||
const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph);
|
const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph, NULL);
|
||||||
newGlyph->mGlyphIndex = skiaGlyph.fID;
|
newGlyph->mGlyphIndex = skiaGlyph.fID;
|
||||||
newGlyph->mIsValid = false;
|
newGlyph->mIsValid = false;
|
||||||
|
|
||||||
@ -418,24 +423,16 @@ CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph, bool precaching
|
|||||||
return newGlyph;
|
return newGlyph;
|
||||||
}
|
}
|
||||||
|
|
||||||
Font* Font::create(FontRenderer* state, uint32_t fontId, float fontSize,
|
Font* Font::create(FontRenderer* state, const SkPaint* paint, const mat4& matrix) {
|
||||||
int flags, uint32_t italicStyle, uint32_t scaleX,
|
FontDescription description(paint, matrix);
|
||||||
SkPaint::Style style, uint32_t strokeWidth) {
|
Font* font = state->mActiveFonts.get(description);
|
||||||
Vector<Font*> &activeFonts = state->mActiveFonts;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < activeFonts.size(); i++) {
|
if (font) {
|
||||||
Font* font = activeFonts[i];
|
return font;
|
||||||
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)) {
|
|
||||||
return font;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle,
|
Font* newFont = new Font(state, description);
|
||||||
scaleX, style, strokeWidth);
|
state->mActiveFonts.put(description, newFont);
|
||||||
activeFonts.push(newFont);
|
|
||||||
return newFont;
|
return newFont;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include "CachedGlyphInfo.h"
|
#include "CachedGlyphInfo.h"
|
||||||
#include "../Rect.h"
|
#include "../Rect.h"
|
||||||
|
#include "../Matrix.h"
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
namespace uirenderer {
|
namespace uirenderer {
|
||||||
@ -45,31 +46,52 @@ public:
|
|||||||
kFakeBold = 1
|
kFakeBold = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FontDescription {
|
||||||
|
FontDescription(const SkPaint* paint, const mat4& matrix);
|
||||||
|
|
||||||
|
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();
|
~Font();
|
||||||
|
|
||||||
/**
|
void render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
|
||||||
* 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);
|
|
||||||
|
|
||||||
void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
|
|
||||||
int numGlyphs, int x, int y, const float* positions);
|
int numGlyphs, int x, int y, const float* positions);
|
||||||
|
|
||||||
void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
|
void render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
|
||||||
int numGlyphs, SkPath* path, float hOffset, float vOffset);
|
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.
|
* Creates a new font associated with the specified font state.
|
||||||
*/
|
*/
|
||||||
static Font* create(FontRenderer* state, uint32_t fontId, float fontSize,
|
static Font* create(FontRenderer* state, const SkPaint* paint, const mat4& matrix);
|
||||||
int flags, uint32_t italicStyle, uint32_t scaleX, SkPaint::Style style,
|
|
||||||
uint32_t strokeWidth);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class FontRenderer;
|
friend class FontRenderer;
|
||||||
|
|
||||||
|
Font(FontRenderer* state, const Font::FontDescription& desc);
|
||||||
|
|
||||||
typedef void (Font::*RenderGlyph)(CachedGlyphInfo*, int, int, uint8_t*,
|
typedef void (Font::*RenderGlyph)(CachedGlyphInfo*, int, int, uint8_t*,
|
||||||
uint32_t, uint32_t, Rect*, const float*);
|
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,
|
void measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
|
||||||
int numGlyphs, Rect *bounds, const float* positions);
|
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);
|
void invalidateTextureCache(CacheTexture* cacheTexture = NULL);
|
||||||
|
|
||||||
CachedGlyphInfo* cacheGlyph(SkPaint* paint, glyph_t glyph, bool precaching);
|
CachedGlyphInfo* cacheGlyph(SkPaint* paint, glyph_t glyph, bool precaching);
|
||||||
@ -115,15 +131,25 @@ private:
|
|||||||
CachedGlyphInfo* getCachedGlyph(SkPaint* paint, glyph_t textUnit, bool precaching = false);
|
CachedGlyphInfo* getCachedGlyph(SkPaint* paint, glyph_t textUnit, bool precaching = false);
|
||||||
|
|
||||||
FontRenderer* mState;
|
FontRenderer* mState;
|
||||||
uint32_t mFontId;
|
FontDescription mDescription;
|
||||||
float mFontSize;
|
|
||||||
int mFlags;
|
// Cache of glyphs
|
||||||
uint32_t mItalicStyle;
|
DefaultKeyedVector<glyph_t, CachedGlyphInfo*> mCachedGlyphs;
|
||||||
uint32_t mScaleX;
|
|
||||||
SkPaint::Style mStyle;
|
|
||||||
uint32_t mStrokeWidth;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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 uirenderer
|
||||||
}; // namespace android
|
}; // namespace android
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
#if RENDER_TEXT_AS_GLYPHS
|
#if RENDER_TEXT_AS_GLYPHS
|
||||||
typedef uint16_t glyph_t;
|
typedef uint16_t glyph_t;
|
||||||
#define TO_GLYPH(g) g
|
#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 GET_GLYPH(text) nextGlyph((const uint16_t**) &text)
|
||||||
#define IS_END_OF_STRING(glyph) false
|
#define IS_END_OF_STRING(glyph) false
|
||||||
|
|
||||||
@ -50,7 +50,7 @@
|
|||||||
#else
|
#else
|
||||||
typedef SkUnichar glyph_t;
|
typedef SkUnichar glyph_t;
|
||||||
#define TO_GLYPH(g) ((SkUnichar) g)
|
#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 GET_GLYPH(text) SkUTF16_NextUnichar((const uint16_t**) &text)
|
||||||
#define IS_END_OF_STRING(glyph) glyph < 0
|
#define IS_END_OF_STRING(glyph) glyph < 0
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,6 +21,7 @@ import android.app.Activity;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Path;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
@ -43,15 +44,27 @@ public class ScaledTextActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class ScaledTextView extends View {
|
public static class ScaledTextView extends View {
|
||||||
|
private static final String TEXT = "Hello libhwui! ";
|
||||||
|
|
||||||
private final Paint mPaint;
|
private final Paint mPaint;
|
||||||
|
private final Paint mShadowPaint;
|
||||||
|
private final Path mPath;
|
||||||
|
|
||||||
private float mScale = 1.0f;
|
private float mScale = 1.0f;
|
||||||
|
|
||||||
public ScaledTextView(Context c) {
|
public ScaledTextView(Context c) {
|
||||||
super(c);
|
super(c);
|
||||||
|
|
||||||
|
mPath = makePath();
|
||||||
|
|
||||||
mPaint = new Paint();
|
mPaint = new Paint();
|
||||||
mPaint.setAntiAlias(true);
|
mPaint.setAntiAlias(true);
|
||||||
mPaint.setTextSize(20.0f);
|
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() {
|
public float getTextScale() {
|
||||||
@ -63,17 +76,47 @@ public class ScaledTextActivity extends Activity {
|
|||||||
invalidate();
|
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
|
@Override
|
||||||
protected void onDraw(Canvas canvas) {
|
protected void onDraw(Canvas canvas) {
|
||||||
super.onDraw(canvas);
|
super.onDraw(canvas);
|
||||||
canvas.drawARGB(255, 255, 255, 255);
|
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.translate(0.0f, 50.0f);
|
||||||
|
|
||||||
canvas.save();
|
canvas.save();
|
||||||
canvas.scale(mScale, mScale);
|
canvas.scale(mScale, mScale);
|
||||||
canvas.drawText("Hello libhwui!", 30.0f, 30.0f, mPaint);
|
canvas.drawText(TEXT, 30.0f, 30.0f, mPaint);
|
||||||
canvas.restore();
|
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);
|
setContentView(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Path makePath() {
|
private static Path makePath() {
|
||||||
Path path = new Path();
|
Path path = new Path();
|
||||||
buildPath(path);
|
buildPath(path);
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildPath(Path path) {
|
private static void buildPath(Path path) {
|
||||||
path.moveTo(0.0f, 0.0f);
|
path.moveTo(0.0f, 0.0f);
|
||||||
path.cubicTo(0.0f, 0.0f, 100.0f, 150.0f, 100.0f, 200.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(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);
|
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();
|
Path path = new Path();
|
||||||
buildStraightPath(path);
|
buildStraightPath(path);
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildStraightPath(Path path) {
|
private static void buildStraightPath(Path path) {
|
||||||
path.moveTo(0.0f, 0.0f);
|
path.moveTo(0.0f, 0.0f);
|
||||||
path.lineTo(400.0f, 0.0f);
|
path.lineTo(400.0f, 0.0f);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user