FontRenderer.h revision e816baea651476aca4407200d4a5e629b9ab8dfa
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#ifndef ANDROID_HWUI_FONT_RENDERER_H 18#define ANDROID_HWUI_FONT_RENDERER_H 19 20#include <utils/String8.h> 21#include <utils/String16.h> 22#include <utils/Vector.h> 23#include <utils/KeyedVector.h> 24 25#include <SkScalerContext.h> 26#include <SkPaint.h> 27#include <SkPathMeasure.h> 28#include <SkPoint.h> 29 30#include <GLES2/gl2.h> 31 32#include "Rect.h" 33#include "Properties.h" 34 35namespace android { 36namespace uirenderer { 37 38/////////////////////////////////////////////////////////////////////////////// 39// Defines 40/////////////////////////////////////////////////////////////////////////////// 41 42#if RENDER_TEXT_AS_GLYPHS 43 typedef uint16_t glyph_t; 44 #define TO_GLYPH(g) g 45 #define GET_METRICS(paint, glyph) paint->getGlyphMetrics(glyph) 46 #define GET_GLYPH(text) nextGlyph((const uint16_t**) &text) 47 #define IS_END_OF_STRING(glyph) false 48#else 49 typedef SkUnichar glyph_t; 50 #define TO_GLYPH(g) ((SkUnichar) g) 51 #define GET_METRICS(paint, glyph) paint->getUnicharMetrics(glyph) 52 #define GET_GLYPH(text) SkUTF16_NextUnichar((const uint16_t**) &text) 53 #define IS_END_OF_STRING(glyph) glyph < 0 54#endif 55 56#define TEXTURE_BORDER_SIZE 1 57 58/////////////////////////////////////////////////////////////////////////////// 59// Declarations 60/////////////////////////////////////////////////////////////////////////////// 61 62class FontRenderer; 63 64class CacheTexture { 65public: 66 CacheTexture(uint16_t width, uint16_t height) : 67 mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height), 68 mLinearFiltering(false) { } 69 ~CacheTexture() { 70 if (mTexture) { 71 delete[] mTexture; 72 } 73 if (mTextureId) { 74 glDeleteTextures(1, &mTextureId); 75 } 76 } 77 78 uint8_t* mTexture; 79 GLuint mTextureId; 80 uint16_t mWidth; 81 uint16_t mHeight; 82 bool mLinearFiltering; 83}; 84 85/** 86 * CacheBlock is a noce in a linked list of current free space areas in a CacheTextureLine. 87 * Using CacheBlocks enables us to pack the cache line from top to bottom as well as left to right. 88 * When we add a glyph to the cache, we see if it fits within one of the existing columns that 89 * have already been started (this is the case if the glyph fits vertically as well as 90 * horizontally, and if its width is sufficiently close to the column width to avoid 91 * sub-optimal packing of small glyphs into wide columns). If there is no column in which the 92 * glyph fits, we check the final node, which is the remaining space in the cache line, creating 93 * a new column as appropriate. 94 * 95 * As columns fill up, we remove their CacheBlock from the list to avoid having to check 96 * small blocks in the future. 97 */ 98struct CacheBlock { 99 uint16_t mX; 100 uint16_t mY; 101 uint16_t mWidth; 102 uint16_t mHeight; 103 CacheBlock* mNext; 104 CacheBlock* mPrev; 105 106 CacheBlock(uint16_t x, uint16_t y, uint16_t width, uint16_t height, bool empty = false): 107 mX(x), mY(y), mWidth(width), mHeight(height), mNext(NULL), mPrev(NULL) 108 { 109 } 110 111 static CacheBlock* insertBlock(CacheBlock* head, CacheBlock *newBlock); 112 113 static CacheBlock* removeBlock(CacheBlock* head, CacheBlock *blockToRemove); 114 115 void output() { 116 CacheBlock *currBlock = this; 117 while (currBlock) { 118 ALOGD("Block: this, x, y, w, h = %p, %d, %d, %d, %d", 119 currBlock, currBlock->mX, currBlock->mY, currBlock->mWidth, currBlock->mHeight); 120 currBlock = currBlock->mNext; 121 } 122 } 123}; 124 125class CacheTextureLine { 126public: 127 CacheTextureLine(uint16_t maxWidth, uint16_t maxHeight, uint32_t currentRow, 128 CacheTexture* cacheTexture): 129 mMaxHeight(maxHeight), 130 mMaxWidth(maxWidth), 131 mCurrentRow(currentRow), 132 mDirty(false), 133 mNumGlyphs(0), 134 mCacheTexture(cacheTexture) { 135 mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE, 136 maxWidth - TEXTURE_BORDER_SIZE, maxHeight - TEXTURE_BORDER_SIZE, true); 137 } 138 139 ~CacheTextureLine() { 140 reset(); 141 } 142 143 void reset() { 144 // Delete existing cache blocks 145 while (mCacheBlocks != NULL) { 146 CacheBlock* tmpBlock = mCacheBlocks; 147 mCacheBlocks = mCacheBlocks->mNext; 148 delete tmpBlock; 149 } 150 mNumGlyphs = 0; 151 } 152 153 void init() { 154 // reset, then create a new remainder space to start again 155 reset(); 156 mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE, 157 mMaxWidth - TEXTURE_BORDER_SIZE, mMaxHeight - TEXTURE_BORDER_SIZE, true); 158 } 159 160 bool fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY); 161 162 uint16_t mMaxHeight; 163 uint16_t mMaxWidth; 164 uint32_t mCurrentRow; 165 bool mDirty; 166 uint16_t mNumGlyphs; 167 CacheTexture* mCacheTexture; 168 CacheBlock* mCacheBlocks; 169}; 170 171struct CachedGlyphInfo { 172 // Has the cache been invalidated? 173 bool mIsValid; 174 // Location of the cached glyph in the bitmap 175 // in case we need to resize the texture or 176 // render to bitmap 177 uint32_t mStartX; 178 uint32_t mStartY; 179 uint32_t mBitmapWidth; 180 uint32_t mBitmapHeight; 181 // Also cache texture coords for the quad 182 float mBitmapMinU; 183 float mBitmapMinV; 184 float mBitmapMaxU; 185 float mBitmapMaxV; 186 // Minimize how much we call freetype 187 uint32_t mGlyphIndex; 188 uint32_t mAdvanceX; 189 uint32_t mAdvanceY; 190 // Values below contain a glyph's origin in the bitmap 191 int32_t mBitmapLeft; 192 int32_t mBitmapTop; 193 // Auto-kerning 194 SkFixed mLsbDelta; 195 SkFixed mRsbDelta; 196 CacheTextureLine* mCachedTextureLine; 197}; 198 199 200/////////////////////////////////////////////////////////////////////////////// 201// Font 202/////////////////////////////////////////////////////////////////////////////// 203 204/** 205 * Represents a font, defined by a Skia font id and a font size. A font is used 206 * to generate glyphs and cache them in the FontState. 207 */ 208class Font { 209public: 210 enum Style { 211 kFakeBold = 1 212 }; 213 214 ~Font(); 215 216 /** 217 * Renders the specified string of text. 218 * If bitmap is specified, it will be used as the render target 219 */ 220 void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len, 221 int numGlyphs, int x, int y, uint8_t *bitmap = NULL, 222 uint32_t bitmapW = 0, uint32_t bitmapH = 0); 223 224 void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len, 225 int numGlyphs, int x, int y, const float* positions); 226 227 void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len, 228 int numGlyphs, SkPath* path, float hOffset, float vOffset); 229 230 /** 231 * Creates a new font associated with the specified font state. 232 */ 233 static Font* create(FontRenderer* state, uint32_t fontId, float fontSize, 234 int flags, uint32_t italicStyle, uint32_t scaleX, SkPaint::Style style, 235 uint32_t strokeWidth); 236 237protected: 238 friend class FontRenderer; 239 typedef void (Font::*RenderGlyph)(CachedGlyphInfo*, int, int, uint8_t*, 240 uint32_t, uint32_t, Rect*, const float*); 241 242 enum RenderMode { 243 FRAMEBUFFER, 244 BITMAP, 245 MEASURE, 246 }; 247 248 void precache(SkPaint* paint, const char* text, int numGlyphs); 249 250 void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len, 251 int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap, 252 uint32_t bitmapW, uint32_t bitmapH, Rect *bounds, const float* positions); 253 254 void measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 255 int numGlyphs, Rect *bounds, const float* positions); 256 257 Font(FontRenderer* state, uint32_t fontId, float fontSize, int flags, uint32_t italicStyle, 258 uint32_t scaleX, SkPaint::Style style, uint32_t strokeWidth); 259 260 // Cache of glyphs 261 DefaultKeyedVector<glyph_t, CachedGlyphInfo*> mCachedGlyphs; 262 263 void invalidateTextureCache(CacheTextureLine *cacheLine = NULL); 264 265 CachedGlyphInfo* cacheGlyph(SkPaint* paint, glyph_t glyph); 266 void updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph); 267 268 void measureCachedGlyph(CachedGlyphInfo* glyph, int x, int y, 269 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH, 270 Rect* bounds, const float* pos); 271 void drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, 272 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH, 273 Rect* bounds, const float* pos); 274 void drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, 275 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH, 276 Rect* bounds, const float* pos); 277 void drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset, 278 SkPathMeasure& measure, SkPoint* position, SkVector* tangent); 279 280 CachedGlyphInfo* getCachedGlyph(SkPaint* paint, glyph_t textUnit); 281 282 static glyph_t nextGlyph(const uint16_t** srcPtr) { 283 const uint16_t* src = *srcPtr; 284 glyph_t g = *src++; 285 *srcPtr = src; 286 return g; 287 } 288 289 FontRenderer* mState; 290 uint32_t mFontId; 291 float mFontSize; 292 int mFlags; 293 uint32_t mItalicStyle; 294 uint32_t mScaleX; 295 SkPaint::Style mStyle; 296 uint32_t mStrokeWidth; 297}; 298 299/////////////////////////////////////////////////////////////////////////////// 300// Renderer 301/////////////////////////////////////////////////////////////////////////////// 302 303class FontRenderer { 304public: 305 FontRenderer(); 306 ~FontRenderer(); 307 308 void flushLargeCaches(); 309 310 void setGammaTable(const uint8_t* gammaTable) { 311 mGammaTable = gammaTable; 312 } 313 314 void setFont(SkPaint* paint, uint32_t fontId, float fontSize); 315 316 void precache(SkPaint* paint, const char* text, int numGlyphs); 317 318 // bounds is an out parameter 319 bool renderText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex, 320 uint32_t len, int numGlyphs, int x, int y, Rect* bounds); 321 // bounds is an out parameter 322 bool renderPosText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex, 323 uint32_t len, int numGlyphs, int x, int y, const float* positions, Rect* bounds); 324 // bounds is an out parameter 325 bool renderTextOnPath(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex, 326 uint32_t len, int numGlyphs, SkPath* path, float hOffset, float vOffset, Rect* bounds); 327 328 struct DropShadow { 329 DropShadow() { }; 330 331 DropShadow(const DropShadow& dropShadow): 332 width(dropShadow.width), height(dropShadow.height), 333 image(dropShadow.image), penX(dropShadow.penX), 334 penY(dropShadow.penY) { 335 } 336 337 uint32_t width; 338 uint32_t height; 339 uint8_t* image; 340 int32_t penX; 341 int32_t penY; 342 }; 343 344 // After renderDropShadow returns, the called owns the memory in DropShadow.image 345 // and is responsible for releasing it when it's done with it 346 DropShadow renderDropShadow(SkPaint* paint, const char *text, uint32_t startIndex, 347 uint32_t len, int numGlyphs, uint32_t radius, const float* positions); 348 349 GLuint getTexture(bool linearFiltering = false) { 350 checkInit(); 351 352 if (linearFiltering != mCurrentCacheTexture->mLinearFiltering) { 353 mCurrentCacheTexture->mLinearFiltering = linearFiltering; 354 mLinearFiltering = linearFiltering; 355 const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST; 356 357 glBindTexture(GL_TEXTURE_2D, mCurrentCacheTexture->mTextureId); 358 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); 359 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); 360 } 361 362 return mCurrentCacheTexture->mTextureId; 363 } 364 365 uint32_t getCacheSize() const { 366 uint32_t size = 0; 367 if (mCacheTextureSmall != NULL && mCacheTextureSmall->mTexture != NULL) { 368 size += mCacheTextureSmall->mWidth * mCacheTextureSmall->mHeight; 369 } 370 if (mCacheTexture128 != NULL && mCacheTexture128->mTexture != NULL) { 371 size += mCacheTexture128->mWidth * mCacheTexture128->mHeight; 372 } 373 if (mCacheTexture256 != NULL && mCacheTexture256->mTexture != NULL) { 374 size += mCacheTexture256->mWidth * mCacheTexture256->mHeight; 375 } 376 if (mCacheTexture512 != NULL && mCacheTexture512->mTexture != NULL) { 377 size += mCacheTexture512->mWidth * mCacheTexture512->mHeight; 378 } 379 return size; 380 } 381 382protected: 383 friend class Font; 384 385 const uint8_t* mGammaTable; 386 387 void allocateTextureMemory(CacheTexture* cacheTexture); 388 void deallocateTextureMemory(CacheTexture* cacheTexture); 389 void initTextTexture(); 390 CacheTexture* createCacheTexture(int width, int height, bool allocate); 391 void cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph, 392 uint32_t *retOriginX, uint32_t *retOriginY); 393 394 void flushAllAndInvalidate(); 395 void initVertexArrayBuffers(); 396 397 void checkInit(); 398 void initRender(const Rect* clip, Rect* bounds); 399 void finishRender(); 400 401 void issueDrawCommand(); 402 void appendMeshQuadNoClip(float x1, float y1, float u1, float v1, 403 float x2, float y2, float u2, float v2, 404 float x3, float y3, float u3, float v3, 405 float x4, float y4, float u4, float v4, CacheTexture* texture); 406 void appendMeshQuad(float x1, float y1, float u1, float v1, 407 float x2, float y2, float u2, float v2, 408 float x3, float y3, float u3, float v3, 409 float x4, float y4, float u4, float v4, CacheTexture* texture); 410 void appendRotatedMeshQuad(float x1, float y1, float u1, float v1, 411 float x2, float y2, float u2, float v2, 412 float x3, float y3, float u3, float v3, 413 float x4, float y4, float u4, float v4, CacheTexture* texture); 414 415 uint32_t mSmallCacheWidth; 416 uint32_t mSmallCacheHeight; 417 418 Vector<CacheTextureLine*> mCacheLines; 419 420 Font* mCurrentFont; 421 Vector<Font*> mActiveFonts; 422 423 CacheTexture* mCurrentCacheTexture; 424 CacheTexture* mLastCacheTexture; 425 CacheTexture* mCacheTextureSmall; 426 CacheTexture* mCacheTexture128; 427 CacheTexture* mCacheTexture256; 428 CacheTexture* mCacheTexture512; 429 430 void checkTextureUpdate(); 431 bool mUploadTexture; 432 433 // Pointer to vertex data to speed up frame to frame work 434 float *mTextMeshPtr; 435 uint32_t mCurrentQuadIndex; 436 uint32_t mMaxNumberOfQuads; 437 438 uint32_t mIndexBufferID; 439 440 const Rect* mClip; 441 Rect* mBounds; 442 bool mDrawn; 443 444 bool mInitialized; 445 446 bool mLinearFiltering; 447 448 void computeGaussianWeights(float* weights, int32_t radius); 449 void horizontalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest, 450 int32_t width, int32_t height); 451 void verticalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest, 452 int32_t width, int32_t height); 453 void blurImage(uint8_t* image, int32_t width, int32_t height, int32_t radius); 454}; 455 456}; // namespace uirenderer 457}; // namespace android 458 459#endif // ANDROID_HWUI_FONT_RENDERER_H 460