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