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 <SkSurfaceProps.h> 23 #include <SkGlyph.h> 24 #include <SkGlyphCache.h> 25 #include <SkUtils.h> 26 27 #include "FontUtil.h" 28 #include "Font.h" 29 #include "../Debug.h" 30 #include "../FontRenderer.h" 31 #include "../PixelBuffer.h" 32 #include "../Properties.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] < 114 rhs.mLookupTransform[SkMatrix::kMScaleX]) return -1; 115 if (lhs.mLookupTransform[SkMatrix::kMScaleX] > 116 rhs.mLookupTransform[SkMatrix::kMScaleX]) return +1; 117 118 if (lhs.mLookupTransform[SkMatrix::kMScaleY] < 119 rhs.mLookupTransform[SkMatrix::kMScaleY]) return -1; 120 if (lhs.mLookupTransform[SkMatrix::kMScaleY] > 121 rhs.mLookupTransform[SkMatrix::kMScaleY]) 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, 136 uint8_t* bitmap, 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, 158 uint8_t* bitmap, uint32_t bitmapW, 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, 171 nPenX + width, nPenY, u2, v2, 172 nPenX + width, nPenY - height, u2, v1, 173 nPenX, nPenY - height, u1, v1, glyph->mCacheTexture); 174 } 175 176 void Font::drawCachedGlyphTransformed(CachedGlyphInfo* glyph, int x, int y, 177 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, 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( 200 p[0].x(), p[0].y(), u1, v2, 201 p[1].x(), p[1].y(), u2, v2, 202 p[2].x(), p[2].y(), u2, v1, 203 p[3].x(), p[3].y(), u1, v1, glyph->mCacheTexture); 204 } 205 206 void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap, 207 uint32_t bitmapWidth, uint32_t bitmapHeight, Rect* bounds, const float* pos) { 208 int dstX = x + glyph->mBitmapLeft; 209 int dstY = y + glyph->mBitmapTop; 210 211 CacheTexture* cacheTexture = glyph->mCacheTexture; 212 PixelBuffer* pixelBuffer = cacheTexture->getPixelBuffer(); 213 214 uint32_t formatSize = PixelBuffer::formatSize(pixelBuffer->getFormat()); 215 uint32_t alpha_channel_offset = PixelBuffer::formatAlphaOffset(pixelBuffer->getFormat()); 216 uint32_t cacheWidth = cacheTexture->getWidth(); 217 uint32_t srcStride = formatSize * cacheWidth; 218 uint32_t startY = glyph->mStartY * srcStride; 219 uint32_t endY = startY + (glyph->mBitmapHeight * srcStride); 220 221 const uint8_t* cacheBuffer = pixelBuffer->map(); 222 223 for (uint32_t cacheY = startY, bitmapY = dstY * bitmapWidth; cacheY < endY; 224 cacheY += srcStride, bitmapY += bitmapWidth) { 225 226 for (uint32_t i = 0; i < glyph->mBitmapWidth; ++i) { 227 uint8_t* dst = &(bitmap[bitmapY + dstX + i]); 228 const uint8_t& src = cacheBuffer[ 229 cacheY + (glyph->mStartX + i)*formatSize + alpha_channel_offset]; 230 // Add alpha values to a max of 255, full opacity. This is done to handle 231 // fonts/strings where glyphs overlap. 232 *dst = std::min(*dst + src, 255); 233 } 234 } 235 } 236 237 void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset, 238 SkPathMeasure& measure, SkPoint* position, SkVector* tangent) { 239 const float halfWidth = glyph->mBitmapWidth * 0.5f; 240 const float height = glyph->mBitmapHeight; 241 242 vOffset += glyph->mBitmapTop + height; 243 244 SkPoint destination[4]; 245 bool ok = measure.getPosTan(x + hOffset + glyph->mBitmapLeft + halfWidth, position, tangent); 246 if (!ok) { 247 ALOGW("The path for drawTextOnPath is empty or null"); 248 } 249 250 // Move along the tangent and offset by the normal 251 destination[0].set(-tangent->fX * halfWidth - tangent->fY * vOffset, 252 -tangent->fY * halfWidth + tangent->fX * vOffset); 253 destination[1].set(tangent->fX * halfWidth - tangent->fY * vOffset, 254 tangent->fY * halfWidth + tangent->fX * vOffset); 255 destination[2].set(destination[1].fX + tangent->fY * height, 256 destination[1].fY - tangent->fX * height); 257 destination[3].set(destination[0].fX + tangent->fY * height, 258 destination[0].fY - tangent->fX * height); 259 260 const float u1 = glyph->mBitmapMinU; 261 const float u2 = glyph->mBitmapMaxU; 262 const float v1 = glyph->mBitmapMinV; 263 const float v2 = glyph->mBitmapMaxV; 264 265 mState->appendRotatedMeshQuad( 266 position->x() + destination[0].x(), 267 position->y() + destination[0].y(), u1, v2, 268 position->x() + destination[1].x(), 269 position->y() + destination[1].y(), u2, v2, 270 position->x() + destination[2].x(), 271 position->y() + destination[2].y(), u2, v1, 272 position->x() + destination[3].x(), 273 position->y() + destination[3].y(), u1, v1, 274 glyph->mCacheTexture); 275 } 276 277 CachedGlyphInfo* Font::getCachedGlyph(const SkPaint* paint, glyph_t textUnit, bool precaching) { 278 CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueFor(textUnit); 279 if (cachedGlyph) { 280 // Is the glyph still in texture cache? 281 if (!cachedGlyph->mIsValid) { 282 SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry); 283 SkAutoGlyphCacheNoGamma autoCache(*paint, &surfaceProps, &mDescription.mLookupTransform); 284 const SkGlyph& skiaGlyph = GET_METRICS(autoCache.getCache(), textUnit); 285 updateGlyphCache(paint, skiaGlyph, autoCache.getCache(), cachedGlyph, precaching); 286 } 287 } else { 288 cachedGlyph = cacheGlyph(paint, textUnit, precaching); 289 } 290 291 return cachedGlyph; 292 } 293 294 void Font::render(const SkPaint* paint, const glyph_t* glyphs, 295 int numGlyphs, int x, int y, const float* positions) { 296 render(paint, glyphs, numGlyphs, x, y, FRAMEBUFFER, nullptr, 297 0, 0, nullptr, positions); 298 } 299 300 void Font::render(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, 301 const SkPath* path, float hOffset, float vOffset) { 302 if (numGlyphs == 0 || glyphs == nullptr) { 303 return; 304 } 305 306 int glyphsCount = 0; 307 int prevRsbDelta = 0; 308 309 float penX = 0.0f; 310 311 SkPoint position; 312 SkVector tangent; 313 314 SkPathMeasure measure(*path, false); 315 float pathLength = SkScalarToFloat(measure.getLength()); 316 317 if (paint->getTextAlign() != SkPaint::kLeft_Align) { 318 float textWidth = SkScalarToFloat(paint->measureText(glyphs, numGlyphs * 2)); 319 float pathOffset = pathLength; 320 if (paint->getTextAlign() == SkPaint::kCenter_Align) { 321 textWidth *= 0.5f; 322 pathOffset *= 0.5f; 323 } 324 penX += pathOffset - textWidth; 325 } 326 327 while (glyphsCount < numGlyphs && penX < pathLength) { 328 glyph_t glyph = *(glyphs++); 329 330 if (IS_END_OF_STRING(glyph)) { 331 break; 332 } 333 334 CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph); 335 penX += AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta); 336 prevRsbDelta = cachedGlyph->mRsbDelta; 337 338 if (cachedGlyph->mIsValid && cachedGlyph->mCacheTexture) { 339 drawCachedGlyph(cachedGlyph, penX, hOffset, vOffset, measure, &position, &tangent); 340 } 341 342 penX += cachedGlyph->mAdvanceX; 343 344 glyphsCount++; 345 } 346 } 347 348 void Font::measure(const SkPaint* paint, const glyph_t* glyphs, 349 int numGlyphs, Rect *bounds, const float* positions) { 350 if (bounds == nullptr) { 351 ALOGE("No return rectangle provided to measure text"); 352 return; 353 } 354 bounds->set(1e6, -1e6, -1e6, 1e6); 355 render(paint, glyphs, numGlyphs, 0, 0, MEASURE, nullptr, 0, 0, bounds, positions); 356 } 357 358 void Font::precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs) { 359 if (numGlyphs == 0 || glyphs == nullptr) { 360 return; 361 } 362 363 int glyphsCount = 0; 364 while (glyphsCount < numGlyphs) { 365 glyph_t glyph = *(glyphs++); 366 367 // Reached the end of the string 368 if (IS_END_OF_STRING(glyph)) { 369 break; 370 } 371 372 getCachedGlyph(paint, glyph, true); 373 glyphsCount++; 374 } 375 } 376 377 void Font::render(const SkPaint* paint, const glyph_t* glyphs, 378 int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap, 379 uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* positions) { 380 if (numGlyphs == 0 || glyphs == nullptr) { 381 return; 382 } 383 384 static RenderGlyph gRenderGlyph[] = { 385 &android::uirenderer::Font::drawCachedGlyph, 386 &android::uirenderer::Font::drawCachedGlyphTransformed, 387 &android::uirenderer::Font::drawCachedGlyphBitmap, 388 &android::uirenderer::Font::drawCachedGlyphBitmap, 389 &android::uirenderer::Font::measureCachedGlyph, 390 &android::uirenderer::Font::measureCachedGlyph 391 }; 392 RenderGlyph render = gRenderGlyph[(mode << 1) + !mIdentityTransform]; 393 394 int glyphsCount = 0; 395 396 while (glyphsCount < numGlyphs) { 397 glyph_t glyph = *(glyphs++); 398 399 // Reached the end of the string 400 if (IS_END_OF_STRING(glyph)) { 401 break; 402 } 403 404 CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph); 405 406 // If it's still not valid, we couldn't cache it, so we shouldn't 407 // draw garbage; also skip empty glyphs (spaces) 408 if (cachedGlyph->mIsValid && cachedGlyph->mCacheTexture) { 409 int penX = x + (int) roundf(positions[(glyphsCount << 1)]); 410 int penY = y + (int) roundf(positions[(glyphsCount << 1) + 1]); 411 #ifdef BUGREPORT_FONT_CACHE_USAGE 412 mState->historyTracker().glyphRendered(cachedGlyph, penX, penY); 413 #endif 414 (*this.*render)(cachedGlyph, penX, penY, 415 bitmap, bitmapW, bitmapH, bounds, positions); 416 } else { 417 #ifdef BUGREPORT_FONT_CACHE_USAGE 418 mState->historyTracker().glyphRendered(cachedGlyph, -1, -1); 419 #endif 420 } 421 422 glyphsCount++; 423 } 424 } 425 426 void Font::updateGlyphCache(const SkPaint* paint, const SkGlyph& skiaGlyph, 427 SkGlyphCache* skiaGlyphCache, CachedGlyphInfo* glyph, bool precaching) { 428 glyph->mAdvanceX = skiaGlyph.fAdvanceX; 429 glyph->mAdvanceY = skiaGlyph.fAdvanceY; 430 glyph->mBitmapLeft = skiaGlyph.fLeft; 431 glyph->mBitmapTop = skiaGlyph.fTop; 432 glyph->mLsbDelta = skiaGlyph.fLsbDelta; 433 glyph->mRsbDelta = skiaGlyph.fRsbDelta; 434 435 uint32_t startX = 0; 436 uint32_t startY = 0; 437 438 // Get the bitmap for the glyph 439 if (!skiaGlyph.fImage) { 440 skiaGlyphCache->findImage(skiaGlyph); 441 } 442 mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY, precaching); 443 444 if (!glyph->mIsValid) { 445 return; 446 } 447 448 uint32_t endX = startX + skiaGlyph.fWidth; 449 uint32_t endY = startY + skiaGlyph.fHeight; 450 451 glyph->mStartX = startX; 452 glyph->mStartY = startY; 453 glyph->mBitmapWidth = skiaGlyph.fWidth; 454 glyph->mBitmapHeight = skiaGlyph.fHeight; 455 456 bool empty = skiaGlyph.fWidth == 0 || skiaGlyph.fHeight == 0; 457 if (!empty) { 458 uint32_t cacheWidth = glyph->mCacheTexture->getWidth(); 459 uint32_t cacheHeight = glyph->mCacheTexture->getHeight(); 460 461 glyph->mBitmapMinU = startX / (float) cacheWidth; 462 glyph->mBitmapMinV = startY / (float) cacheHeight; 463 glyph->mBitmapMaxU = endX / (float) cacheWidth; 464 glyph->mBitmapMaxV = endY / (float) cacheHeight; 465 466 mState->setTextureDirty(); 467 } 468 } 469 470 CachedGlyphInfo* Font::cacheGlyph(const SkPaint* paint, glyph_t glyph, bool precaching) { 471 CachedGlyphInfo* newGlyph = new CachedGlyphInfo(); 472 mCachedGlyphs.add(glyph, newGlyph); 473 474 SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry); 475 SkAutoGlyphCacheNoGamma autoCache(*paint, &surfaceProps, &mDescription.mLookupTransform); 476 const SkGlyph& skiaGlyph = GET_METRICS(autoCache.getCache(), glyph); 477 newGlyph->mIsValid = false; 478 newGlyph->mGlyphIndex = skiaGlyph.fID; 479 480 updateGlyphCache(paint, skiaGlyph, autoCache.getCache(), newGlyph, precaching); 481 482 return newGlyph; 483 } 484 485 Font* Font::create(FontRenderer* state, const SkPaint* paint, const SkMatrix& matrix) { 486 FontDescription description(paint, matrix); 487 Font* font = state->mActiveFonts.get(description); 488 489 if (!font) { 490 font = new Font(state, description); 491 state->mActiveFonts.put(description, font); 492 } 493 font->mIdentityTransform = matrix.isIdentity(); 494 495 return font; 496 } 497 498 }; // namespace uirenderer 499 }; // namespace android 500