Font.cpp revision 14c40b47565778b7185de7655836485f3065877a
1/* 2 * Copyright (C) 2012 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#define LOG_TAG "OpenGLRenderer" 18 19#include <cutils/compiler.h> 20 21#include <utils/JenkinsHash.h> 22 23#include <SkGlyph.h> 24#include <SkUtils.h> 25 26#include "Debug.h" 27#include "FontUtil.h" 28#include "Font.h" 29#include "FontRenderer.h" 30#include "Properties.h" 31 32namespace android { 33namespace uirenderer { 34 35/////////////////////////////////////////////////////////////////////////////// 36// Font 37/////////////////////////////////////////////////////////////////////////////// 38 39Font::Font(FontRenderer* state, const Font::FontDescription& desc) : 40 mState(state), mDescription(desc) { 41} 42 43Font::FontDescription::FontDescription(const SkPaint* paint, const mat4& matrix) { 44 mFontId = SkTypeface::UniqueID(paint->getTypeface()); 45 mFontSize = paint->getTextSize(); 46 mFlags = 0; 47 if (paint->isFakeBoldText()) { 48 mFlags |= Font::kFakeBold; 49 } 50 mItalicStyle = paint->getTextSkewX(); 51 mScaleX = paint->getTextScaleX(); 52 mStyle = paint->getStyle(); 53 mStrokeWidth = paint->getStrokeWidth(); 54} 55 56Font::~Font() { 57 mState->removeFont(this); 58 59 for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) { 60 delete mCachedGlyphs.valueAt(i); 61 } 62} 63 64hash_t Font::FontDescription::hash() const { 65 uint32_t hash = JenkinsHashMix(0, mFontId); 66 hash = JenkinsHashMix(hash, android::hash_type(mFontSize)); 67 hash = JenkinsHashMix(hash, android::hash_type(mFlags)); 68 hash = JenkinsHashMix(hash, android::hash_type(mItalicStyle)); 69 hash = JenkinsHashMix(hash, android::hash_type(mScaleX)); 70 hash = JenkinsHashMix(hash, android::hash_type(mStyle)); 71 hash = JenkinsHashMix(hash, android::hash_type(mStrokeWidth)); 72 return JenkinsHashWhiten(hash); 73} 74 75int Font::FontDescription::compare(const Font::FontDescription& lhs, 76 const Font::FontDescription& rhs) { 77 int deltaInt = int(lhs.mFontId) - int(rhs.mFontId); 78 if (deltaInt != 0) return deltaInt; 79 80 if (lhs.mFontSize < rhs.mFontSize) return -1; 81 if (lhs.mFontSize > rhs.mFontSize) return +1; 82 83 if (lhs.mItalicStyle < rhs.mItalicStyle) return -1; 84 if (lhs.mItalicStyle > rhs.mItalicStyle) return +1; 85 86 deltaInt = int(lhs.mFlags) - int(rhs.mFlags); 87 if (deltaInt != 0) return deltaInt; 88 89 if (lhs.mScaleX < rhs.mScaleX) return -1; 90 if (lhs.mScaleX > rhs.mScaleX) return +1; 91 92 deltaInt = int(lhs.mStyle) - int(rhs.mStyle); 93 if (deltaInt != 0) return deltaInt; 94 95 if (lhs.mStrokeWidth < rhs.mStrokeWidth) return -1; 96 if (lhs.mStrokeWidth > rhs.mStrokeWidth) return +1; 97 98 return 0; 99} 100 101void Font::invalidateTextureCache(CacheTexture* cacheTexture) { 102 for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) { 103 CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueAt(i); 104 if (!cacheTexture || cachedGlyph->mCacheTexture == cacheTexture) { 105 cachedGlyph->mIsValid = false; 106 } 107 } 108} 109 110void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y, 111 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) { 112 int nPenX = x + glyph->mBitmapLeft; 113 int nPenY = y + glyph->mBitmapTop; 114 115 int width = (int) glyph->mBitmapWidth; 116 int height = (int) glyph->mBitmapHeight; 117 118 if (bounds->bottom > nPenY) { 119 bounds->bottom = nPenY; 120 } 121 if (bounds->left > nPenX) { 122 bounds->left = nPenX; 123 } 124 if (bounds->right < nPenX + width) { 125 bounds->right = nPenX + width; 126 } 127 if (bounds->top < nPenY + height) { 128 bounds->top = nPenY + height; 129 } 130} 131 132void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, 133 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) { 134 float nPenX = x + glyph->mBitmapLeft; 135 float nPenY = y + (glyph->mBitmapTop + glyph->mBitmapHeight); 136 137 float width = (float) glyph->mBitmapWidth; 138 float height = (float) glyph->mBitmapHeight; 139 140 float u1 = glyph->mBitmapMinU; 141 float u2 = glyph->mBitmapMaxU; 142 float v1 = glyph->mBitmapMinV; 143 float v2 = glyph->mBitmapMaxV; 144 145 mState->appendMeshQuad(nPenX, nPenY, u1, v2, 146 nPenX + width, nPenY, u2, v2, 147 nPenX + width, nPenY - height, u2, v1, 148 nPenX, nPenY - height, u1, v1, glyph->mCacheTexture); 149} 150 151void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, 152 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) { 153 int nPenX = x + glyph->mBitmapLeft; 154 int nPenY = y + glyph->mBitmapTop; 155 156 uint32_t endX = glyph->mStartX + glyph->mBitmapWidth; 157 uint32_t endY = glyph->mStartY + glyph->mBitmapHeight; 158 159 CacheTexture* cacheTexture = glyph->mCacheTexture; 160 uint32_t cacheWidth = cacheTexture->getWidth(); 161 const uint8_t* cacheBuffer = cacheTexture->getTexture(); 162 163 uint32_t cacheX = 0, cacheY = 0; 164 int32_t bX = 0, bY = 0; 165 for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) { 166 for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) { 167#if DEBUG_FONT_RENDERER 168 if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) { 169 ALOGE("Skipping invalid index"); 170 continue; 171 } 172#endif 173 uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX]; 174 bitmap[bY * bitmapW + bX] = tempCol; 175 } 176 } 177} 178 179void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset, 180 SkPathMeasure& measure, SkPoint* position, SkVector* tangent) { 181 const float halfWidth = glyph->mBitmapWidth * 0.5f; 182 const float height = glyph->mBitmapHeight; 183 184 vOffset += glyph->mBitmapTop + height; 185 186 SkPoint destination[4]; 187 measure.getPosTan(x + hOffset + glyph->mBitmapLeft + halfWidth, position, tangent); 188 189 // Move along the tangent and offset by the normal 190 destination[0].set(-tangent->fX * halfWidth - tangent->fY * vOffset, 191 -tangent->fY * halfWidth + tangent->fX * vOffset); 192 destination[1].set(tangent->fX * halfWidth - tangent->fY * vOffset, 193 tangent->fY * halfWidth + tangent->fX * vOffset); 194 destination[2].set(destination[1].fX + tangent->fY * height, 195 destination[1].fY - tangent->fX * height); 196 destination[3].set(destination[0].fX + tangent->fY * height, 197 destination[0].fY - tangent->fX * height); 198 199 const float u1 = glyph->mBitmapMinU; 200 const float u2 = glyph->mBitmapMaxU; 201 const float v1 = glyph->mBitmapMinV; 202 const float v2 = glyph->mBitmapMaxV; 203 204 mState->appendRotatedMeshQuad( 205 position->fX + destination[0].fX, 206 position->fY + destination[0].fY, u1, v2, 207 position->fX + destination[1].fX, 208 position->fY + destination[1].fY, u2, v2, 209 position->fX + destination[2].fX, 210 position->fY + destination[2].fY, u2, v1, 211 position->fX + destination[3].fX, 212 position->fY + destination[3].fY, u1, v1, 213 glyph->mCacheTexture); 214} 215 216CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit, bool precaching) { 217 CachedGlyphInfo* cachedGlyph = NULL; 218 ssize_t index = mCachedGlyphs.indexOfKey(textUnit); 219 if (index >= 0) { 220 cachedGlyph = mCachedGlyphs.valueAt(index); 221 } else { 222 cachedGlyph = cacheGlyph(paint, textUnit, precaching); 223 } 224 225 // Is the glyph still in texture cache? 226 if (!cachedGlyph->mIsValid) { 227 const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit, NULL); 228 updateGlyphCache(paint, skiaGlyph, cachedGlyph, precaching); 229 } 230 231 return cachedGlyph; 232} 233 234void Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len, 235 int numGlyphs, int x, int y, const float* positions) { 236 render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL, 237 0, 0, NULL, positions); 238} 239 240void Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len, 241 int numGlyphs, SkPath* path, float hOffset, float vOffset) { 242 if (numGlyphs == 0 || text == NULL || len == 0) { 243 return; 244 } 245 246 text += start; 247 248 int glyphsCount = 0; 249 SkFixed prevRsbDelta = 0; 250 251 float penX = 0.0f; 252 253 SkPoint position; 254 SkVector tangent; 255 256 SkPathMeasure measure(*path, false); 257 float pathLength = SkScalarToFloat(measure.getLength()); 258 259 if (paint->getTextAlign() != SkPaint::kLeft_Align) { 260 float textWidth = SkScalarToFloat(paint->measureText(text, len)); 261 float pathOffset = pathLength; 262 if (paint->getTextAlign() == SkPaint::kCenter_Align) { 263 textWidth *= 0.5f; 264 pathOffset *= 0.5f; 265 } 266 penX += pathOffset - textWidth; 267 } 268 269 while (glyphsCount < numGlyphs && penX < pathLength) { 270 glyph_t glyph = GET_GLYPH(text); 271 272 if (IS_END_OF_STRING(glyph)) { 273 break; 274 } 275 276 CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph); 277 penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta)); 278 prevRsbDelta = cachedGlyph->mRsbDelta; 279 280 if (cachedGlyph->mIsValid) { 281 drawCachedGlyph(cachedGlyph, penX, hOffset, vOffset, measure, &position, &tangent); 282 } 283 284 penX += SkFixedToFloat(cachedGlyph->mAdvanceX); 285 286 glyphsCount++; 287 } 288} 289 290void Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 291 int numGlyphs, Rect *bounds, const float* positions) { 292 if (bounds == NULL) { 293 ALOGE("No return rectangle provided to measure text"); 294 return; 295 } 296 bounds->set(1e6, -1e6, -1e6, 1e6); 297 render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds, positions); 298} 299 300void Font::precache(SkPaint* paint, const char* text, int numGlyphs) { 301 302 if (numGlyphs == 0 || text == NULL) { 303 return; 304 } 305 int glyphsCount = 0; 306 307 while (glyphsCount < numGlyphs) { 308 glyph_t glyph = GET_GLYPH(text); 309 310 // Reached the end of the string 311 if (IS_END_OF_STRING(glyph)) { 312 break; 313 } 314 315 CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph, true); 316 317 glyphsCount++; 318 } 319} 320 321void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 322 int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap, 323 uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* positions) { 324 if (numGlyphs == 0 || text == NULL || len == 0) { 325 return; 326 } 327 328 static RenderGlyph gRenderGlyph[] = { 329 &android::uirenderer::Font::drawCachedGlyph, 330 &android::uirenderer::Font::drawCachedGlyphBitmap, 331 &android::uirenderer::Font::measureCachedGlyph 332 }; 333 RenderGlyph render = gRenderGlyph[mode]; 334 335 text += start; 336 int glyphsCount = 0; 337 338 const SkPaint::Align align = paint->getTextAlign(); 339 340 while (glyphsCount < numGlyphs) { 341 glyph_t glyph = GET_GLYPH(text); 342 343 // Reached the end of the string 344 if (IS_END_OF_STRING(glyph)) { 345 break; 346 } 347 348 CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph); 349 350 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage 351 if (cachedGlyph->mIsValid) { 352 int penX = x + positions[(glyphsCount << 1)]; 353 int penY = y + positions[(glyphsCount << 1) + 1]; 354 355 switch (align) { 356 case SkPaint::kRight_Align: 357 penX -= SkFixedToFloat(cachedGlyph->mAdvanceX); 358 penY -= SkFixedToFloat(cachedGlyph->mAdvanceY); 359 break; 360 case SkPaint::kCenter_Align: 361 penX -= SkFixedToFloat(cachedGlyph->mAdvanceX >> 1); 362 penY -= SkFixedToFloat(cachedGlyph->mAdvanceY >> 1); 363 default: 364 break; 365 } 366 367 (*this.*render)(cachedGlyph, penX, penY, 368 bitmap, bitmapW, bitmapH, bounds, positions); 369 } 370 371 glyphsCount++; 372 } 373} 374 375void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph, 376 bool precaching) { 377 glyph->mAdvanceX = skiaGlyph.fAdvanceX; 378 glyph->mAdvanceY = skiaGlyph.fAdvanceY; 379 glyph->mBitmapLeft = skiaGlyph.fLeft; 380 glyph->mBitmapTop = skiaGlyph.fTop; 381 glyph->mLsbDelta = skiaGlyph.fLsbDelta; 382 glyph->mRsbDelta = skiaGlyph.fRsbDelta; 383 384 uint32_t startX = 0; 385 uint32_t startY = 0; 386 387 // Get the bitmap for the glyph 388 paint->findImage(skiaGlyph, NULL); 389 mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY, precaching); 390 391 if (!glyph->mIsValid) { 392 return; 393 } 394 395 uint32_t endX = startX + skiaGlyph.fWidth; 396 uint32_t endY = startY + skiaGlyph.fHeight; 397 398 glyph->mStartX = startX; 399 glyph->mStartY = startY; 400 glyph->mBitmapWidth = skiaGlyph.fWidth; 401 glyph->mBitmapHeight = skiaGlyph.fHeight; 402 403 uint32_t cacheWidth = glyph->mCacheTexture->getWidth(); 404 uint32_t cacheHeight = glyph->mCacheTexture->getHeight(); 405 406 glyph->mBitmapMinU = startX / (float) cacheWidth; 407 glyph->mBitmapMinV = startY / (float) cacheHeight; 408 glyph->mBitmapMaxU = endX / (float) cacheWidth; 409 glyph->mBitmapMaxV = endY / (float) cacheHeight; 410 411 mState->setTextureDirty(); 412} 413 414CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph, bool precaching) { 415 CachedGlyphInfo* newGlyph = new CachedGlyphInfo(); 416 mCachedGlyphs.add(glyph, newGlyph); 417 418 const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph, NULL); 419 newGlyph->mGlyphIndex = skiaGlyph.fID; 420 newGlyph->mIsValid = false; 421 422 updateGlyphCache(paint, skiaGlyph, newGlyph, precaching); 423 424 return newGlyph; 425} 426 427Font* Font::create(FontRenderer* state, const SkPaint* paint, const mat4& matrix) { 428 FontDescription description(paint, matrix); 429 Font* font = state->mActiveFonts.get(description); 430 431 if (font) { 432 return font; 433 } 434 435 Font* newFont = new Font(state, description); 436 state->mActiveFonts.put(description, newFont); 437 return newFont; 438} 439 440}; // namespace uirenderer 441}; // namespace android 442