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