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