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