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