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