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