Home | History | Annotate | Download | only in font
      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