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 <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