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