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     mDeviceProperties = SkDeviceProperties::Make(SkDeviceProperties::Geometry::MakeDefault(), 1.0f);
     46 }
     47 
     48 Font::FontDescription::FontDescription(const SkPaint* paint, const SkMatrix& rasterMatrix)
     49         : mLookupTransform(rasterMatrix) {
     50     mFontId = SkTypeface::UniqueID(paint->getTypeface());
     51     mFontSize = paint->getTextSize();
     52     mFlags = 0;
     53     if (paint->isFakeBoldText()) {
     54         mFlags |= Font::kFakeBold;
     55     }
     56     mItalicStyle = paint->getTextSkewX();
     57     mScaleX = paint->getTextScaleX();
     58     mStyle = paint->getStyle();
     59     mStrokeWidth = paint->getStrokeWidth();
     60     mAntiAliasing = paint->isAntiAlias();
     61     mHinting = paint->getHinting();
     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 width = (int) glyph->mBitmapWidth;
    144     int height = (int) glyph->mBitmapHeight;
    145 
    146     int nPenX = x + glyph->mBitmapLeft;
    147     int nPenY = y + glyph->mBitmapTop;
    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 width = (float) glyph->mBitmapWidth;
    166     float height = (float) glyph->mBitmapHeight;
    167 
    168     float nPenX = x + glyph->mBitmapLeft;
    169     float nPenY = y + glyph->mBitmapTop + height;
    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     float width = (float) glyph->mBitmapWidth;
    185     float height = (float) glyph->mBitmapHeight;
    186 
    187     SkPoint p[4];
    188     p[0].iset(glyph->mBitmapLeft, glyph->mBitmapTop + height);
    189     p[1].iset(glyph->mBitmapLeft + width, glyph->mBitmapTop + height);
    190     p[2].iset(glyph->mBitmapLeft + width, glyph->mBitmapTop);
    191     p[3].iset(glyph->mBitmapLeft, glyph->mBitmapTop);
    192 
    193     mDescription.mInverseLookupTransform.mapPoints(p, 4);
    194 
    195     p[0].offset(x, y);
    196     p[1].offset(x, y);
    197     p[2].offset(x, y);
    198     p[3].offset(x, y);
    199 
    200     float u1 = glyph->mBitmapMinU;
    201     float u2 = glyph->mBitmapMaxU;
    202     float v1 = glyph->mBitmapMinV;
    203     float v2 = glyph->mBitmapMaxV;
    204 
    205     mState->appendRotatedMeshQuad(
    206             p[0].x(), p[0].y(), u1, v2,
    207             p[1].x(), p[1].y(), u2, v2,
    208             p[2].x(), p[2].y(), u2, v1,
    209             p[3].x(), p[3].y(), u1, v1, glyph->mCacheTexture);
    210 }
    211 
    212 void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap,
    213         uint32_t bitmapWidth, uint32_t bitmapHeight, Rect* bounds, const float* pos) {
    214     int dstX = x + glyph->mBitmapLeft;
    215     int dstY = y + glyph->mBitmapTop;
    216 
    217     CacheTexture* cacheTexture = glyph->mCacheTexture;
    218     PixelBuffer* pixelBuffer = cacheTexture->getPixelBuffer();
    219 
    220     uint32_t formatSize = PixelBuffer::formatSize(pixelBuffer->getFormat());
    221     uint32_t alpha_channel_offset = PixelBuffer::formatAlphaOffset(pixelBuffer->getFormat());
    222     uint32_t cacheWidth = cacheTexture->getWidth();
    223     uint32_t srcStride = formatSize * cacheWidth;
    224     uint32_t startY = glyph->mStartY * srcStride;
    225     uint32_t endY = startY + (glyph->mBitmapHeight * srcStride);
    226 
    227     const uint8_t* cacheBuffer = pixelBuffer->map();
    228 
    229     for (uint32_t cacheY = startY, bitmapY = dstY * bitmapWidth; cacheY < endY;
    230             cacheY += srcStride, bitmapY += bitmapWidth) {
    231 
    232         if (formatSize == 1) {
    233             memcpy(&bitmap[bitmapY + dstX], &cacheBuffer[cacheY + glyph->mStartX], glyph->mBitmapWidth);
    234         } else {
    235             for (uint32_t i = 0; i < glyph->mBitmapWidth; ++i) {
    236                 bitmap[bitmapY + dstX + i] = cacheBuffer[cacheY + (glyph->mStartX + i)*formatSize + alpha_channel_offset];
    237             }
    238         }
    239     }
    240 
    241 }
    242 
    243 void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset,
    244         SkPathMeasure& measure, SkPoint* position, SkVector* tangent) {
    245     const float halfWidth = glyph->mBitmapWidth * 0.5f;
    246     const float height = glyph->mBitmapHeight;
    247 
    248     vOffset += glyph->mBitmapTop + height;
    249 
    250     SkPoint destination[4];
    251     bool ok = measure.getPosTan(x + hOffset + glyph->mBitmapLeft + halfWidth, position, tangent);
    252     if (!ok) {
    253         ALOGW("The path for drawTextOnPath is empty or null");
    254     }
    255 
    256     // Move along the tangent and offset by the normal
    257     destination[0].set(-tangent->fX * halfWidth - tangent->fY * vOffset,
    258             -tangent->fY * halfWidth + tangent->fX * vOffset);
    259     destination[1].set(tangent->fX * halfWidth - tangent->fY * vOffset,
    260             tangent->fY * halfWidth + tangent->fX * vOffset);
    261     destination[2].set(destination[1].fX + tangent->fY * height,
    262             destination[1].fY - tangent->fX * height);
    263     destination[3].set(destination[0].fX + tangent->fY * height,
    264             destination[0].fY - tangent->fX * height);
    265 
    266     const float u1 = glyph->mBitmapMinU;
    267     const float u2 = glyph->mBitmapMaxU;
    268     const float v1 = glyph->mBitmapMinV;
    269     const float v2 = glyph->mBitmapMaxV;
    270 
    271     mState->appendRotatedMeshQuad(
    272             position->x() + destination[0].x(),
    273             position->y() + destination[0].y(), u1, v2,
    274             position->x() + destination[1].x(),
    275             position->y() + destination[1].y(), u2, v2,
    276             position->x() + destination[2].x(),
    277             position->y() + destination[2].y(), u2, v1,
    278             position->x() + destination[3].x(),
    279             position->y() + destination[3].y(), u1, v1,
    280             glyph->mCacheTexture);
    281 }
    282 
    283 CachedGlyphInfo* Font::getCachedGlyph(const SkPaint* paint, glyph_t textUnit, bool precaching) {
    284     CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueFor(textUnit);
    285     if (cachedGlyph) {
    286         // Is the glyph still in texture cache?
    287         if (!cachedGlyph->mIsValid) {
    288             SkAutoGlyphCache autoCache(*paint, &mDeviceProperties, &mDescription.mLookupTransform);
    289             const SkGlyph& skiaGlyph = GET_METRICS(autoCache.getCache(), textUnit);
    290             updateGlyphCache(paint, skiaGlyph, autoCache.getCache(), cachedGlyph, precaching);
    291         }
    292     } else {
    293         cachedGlyph = cacheGlyph(paint, textUnit, precaching);
    294     }
    295 
    296     return cachedGlyph;
    297 }
    298 
    299 void Font::render(const SkPaint* paint, const char *text, uint32_t start, uint32_t len,
    300             int numGlyphs, int x, int y, const float* positions) {
    301     render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
    302             0, 0, NULL, positions);
    303 }
    304 
    305 void Font::render(const SkPaint* paint, const char *text, uint32_t start, uint32_t len,
    306         int numGlyphs, const SkPath* path, float hOffset, float vOffset) {
    307     if (numGlyphs == 0 || text == NULL || len == 0) {
    308         return;
    309     }
    310 
    311     text += start;
    312 
    313     int glyphsCount = 0;
    314     SkFixed prevRsbDelta = 0;
    315 
    316     float penX = 0.0f;
    317 
    318     SkPoint position;
    319     SkVector tangent;
    320 
    321     SkPathMeasure measure(*path, false);
    322     float pathLength = SkScalarToFloat(measure.getLength());
    323 
    324     if (paint->getTextAlign() != SkPaint::kLeft_Align) {
    325         float textWidth = SkScalarToFloat(paint->measureText(text, len));
    326         float pathOffset = pathLength;
    327         if (paint->getTextAlign() == SkPaint::kCenter_Align) {
    328             textWidth *= 0.5f;
    329             pathOffset *= 0.5f;
    330         }
    331         penX += pathOffset - textWidth;
    332     }
    333 
    334     while (glyphsCount < numGlyphs && penX < pathLength) {
    335         glyph_t glyph = GET_GLYPH(text);
    336 
    337         if (IS_END_OF_STRING(glyph)) {
    338             break;
    339         }
    340 
    341         CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
    342         penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta));
    343         prevRsbDelta = cachedGlyph->mRsbDelta;
    344 
    345         if (cachedGlyph->mIsValid && cachedGlyph->mCacheTexture) {
    346             drawCachedGlyph(cachedGlyph, penX, hOffset, vOffset, measure, &position, &tangent);
    347         }
    348 
    349         penX += SkFixedToFloat(cachedGlyph->mAdvanceX);
    350 
    351         glyphsCount++;
    352     }
    353 }
    354 
    355 void Font::measure(const SkPaint* paint, const char* text, uint32_t start, uint32_t len,
    356         int numGlyphs, Rect *bounds, const float* positions) {
    357     if (bounds == NULL) {
    358         ALOGE("No return rectangle provided to measure text");
    359         return;
    360     }
    361     bounds->set(1e6, -1e6, -1e6, 1e6);
    362     render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds, positions);
    363 }
    364 
    365 void Font::precache(const SkPaint* paint, const char* text, int numGlyphs) {
    366     ATRACE_NAME("Precache Glyphs");
    367 
    368     if (numGlyphs == 0 || text == NULL) {
    369         return;
    370     }
    371 
    372     int glyphsCount = 0;
    373     while (glyphsCount < numGlyphs) {
    374         glyph_t glyph = GET_GLYPH(text);
    375 
    376         // Reached the end of the string
    377         if (IS_END_OF_STRING(glyph)) {
    378             break;
    379         }
    380 
    381         CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph, true);
    382         glyphsCount++;
    383     }
    384 }
    385 
    386 void Font::render(const SkPaint* paint, const char* text, uint32_t start, uint32_t len,
    387         int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
    388         uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* positions) {
    389     if (numGlyphs == 0 || text == NULL || len == 0) {
    390         return;
    391     }
    392 
    393     static RenderGlyph gRenderGlyph[] = {
    394             &android::uirenderer::Font::drawCachedGlyph,
    395             &android::uirenderer::Font::drawCachedGlyphTransformed,
    396             &android::uirenderer::Font::drawCachedGlyphBitmap,
    397             &android::uirenderer::Font::drawCachedGlyphBitmap,
    398             &android::uirenderer::Font::measureCachedGlyph,
    399             &android::uirenderer::Font::measureCachedGlyph
    400     };
    401     RenderGlyph render = gRenderGlyph[(mode << 1) + !mIdentityTransform];
    402 
    403     text += start;
    404     int glyphsCount = 0;
    405 
    406     const SkPaint::Align align = paint->getTextAlign();
    407 
    408     while (glyphsCount < numGlyphs) {
    409         glyph_t glyph = GET_GLYPH(text);
    410 
    411         // Reached the end of the string
    412         if (IS_END_OF_STRING(glyph)) {
    413             break;
    414         }
    415 
    416         CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
    417 
    418         // If it's still not valid, we couldn't cache it, so we shouldn't
    419         // draw garbage; also skip empty glyphs (spaces)
    420         if (cachedGlyph->mIsValid && cachedGlyph->mCacheTexture) {
    421             int penX = x + (int) roundf(positions[(glyphsCount << 1)]);
    422             int penY = y + (int) roundf(positions[(glyphsCount << 1) + 1]);
    423 
    424             (*this.*render)(cachedGlyph, penX, penY,
    425                     bitmap, bitmapW, bitmapH, bounds, positions);
    426         }
    427 
    428         glyphsCount++;
    429     }
    430 }
    431 
    432 void Font::updateGlyphCache(const SkPaint* paint, const SkGlyph& skiaGlyph,
    433         SkGlyphCache* skiaGlyphCache, CachedGlyphInfo* glyph, bool precaching) {
    434     glyph->mAdvanceX = skiaGlyph.fAdvanceX;
    435     glyph->mAdvanceY = skiaGlyph.fAdvanceY;
    436     glyph->mBitmapLeft = skiaGlyph.fLeft;
    437     glyph->mBitmapTop = skiaGlyph.fTop;
    438     glyph->mLsbDelta = skiaGlyph.fLsbDelta;
    439     glyph->mRsbDelta = skiaGlyph.fRsbDelta;
    440 
    441     uint32_t startX = 0;
    442     uint32_t startY = 0;
    443 
    444     // Get the bitmap for the glyph
    445     if (!skiaGlyph.fImage) {
    446         skiaGlyphCache->findImage(skiaGlyph);
    447     }
    448     mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY, precaching);
    449 
    450     if (!glyph->mIsValid) {
    451         return;
    452     }
    453 
    454     uint32_t endX = startX + skiaGlyph.fWidth;
    455     uint32_t endY = startY + skiaGlyph.fHeight;
    456 
    457     glyph->mStartX = startX;
    458     glyph->mStartY = startY;
    459     glyph->mBitmapWidth = skiaGlyph.fWidth;
    460     glyph->mBitmapHeight = skiaGlyph.fHeight;
    461 
    462     bool empty = skiaGlyph.fWidth == 0 || skiaGlyph.fHeight == 0;
    463     if (!empty) {
    464         uint32_t cacheWidth = glyph->mCacheTexture->getWidth();
    465         uint32_t cacheHeight = glyph->mCacheTexture->getHeight();
    466 
    467         glyph->mBitmapMinU = startX / (float) cacheWidth;
    468         glyph->mBitmapMinV = startY / (float) cacheHeight;
    469         glyph->mBitmapMaxU = endX / (float) cacheWidth;
    470         glyph->mBitmapMaxV = endY / (float) cacheHeight;
    471 
    472         mState->setTextureDirty();
    473     }
    474 }
    475 
    476 CachedGlyphInfo* Font::cacheGlyph(const SkPaint* paint, glyph_t glyph, bool precaching) {
    477     CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
    478     mCachedGlyphs.add(glyph, newGlyph);
    479 
    480     SkAutoGlyphCache autoCache(*paint, &mDeviceProperties, &mDescription.mLookupTransform);
    481     const SkGlyph& skiaGlyph = GET_METRICS(autoCache.getCache(), glyph);
    482     newGlyph->mIsValid = false;
    483     newGlyph->mGlyphIndex = skiaGlyph.fID;
    484 
    485     updateGlyphCache(paint, skiaGlyph, autoCache.getCache(), newGlyph, precaching);
    486 
    487     return newGlyph;
    488 }
    489 
    490 Font* Font::create(FontRenderer* state, const SkPaint* paint, const SkMatrix& matrix) {
    491     FontDescription description(paint, matrix);
    492     Font* font = state->mActiveFonts.get(description);
    493 
    494     if (!font) {
    495         font = new Font(state, description);
    496         state->mActiveFonts.put(description, font);
    497     }
    498     font->mIdentityTransform = matrix.isIdentity();
    499 
    500     return font;
    501 }
    502 
    503 }; // namespace uirenderer
    504 }; // namespace android
    505