19f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy/*
29f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * Copyright (C) 2012 The Android Open Source Project
39f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy *
49f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * Licensed under the Apache License, Version 2.0 (the "License");
59f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * you may not use this file except in compliance with the License.
69f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * You may obtain a copy of the License at
79f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy *
89f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy *      http://www.apache.org/licenses/LICENSE-2.0
99f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy *
109f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * Unless required by applicable law or agreed to in writing, software
119f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * distributed under the License is distributed on an "AS IS" BASIS,
129f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * See the License for the specific language governing permissions and
149f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * limitations under the License.
159f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy */
169f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
17a3dc55f83ab583e0a66b893c71b849afa046770aRomain Guy#define LOG_TAG "OpenGLRenderer"
18a3dc55f83ab583e0a66b893c71b849afa046770aRomain Guy
199f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#include <cutils/compiler.h>
209f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
219f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#include <SkUtils.h>
229f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
239f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#include "Debug.h"
249f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#include "FontUtil.h"
259f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#include "Font.h"
269f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#include "FontRenderer.h"
279f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#include "Properties.h"
289f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
299f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guynamespace android {
309f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guynamespace uirenderer {
319f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
329f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy///////////////////////////////////////////////////////////////////////////////
339f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy// Font
349f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy///////////////////////////////////////////////////////////////////////////////
359f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
369f5dab3fc228fa11c32b483e6101ec086895a32bRomain GuyFont::Font(FontRenderer* state, uint32_t fontId, float fontSize,
379f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        int flags, uint32_t italicStyle, uint32_t scaleX,
389f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        SkPaint::Style style, uint32_t strokeWidth) :
399f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        mState(state), mFontId(fontId), mFontSize(fontSize),
409f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        mFlags(flags), mItalicStyle(italicStyle), mScaleX(scaleX),
419f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        mStyle(style), mStrokeWidth(mStrokeWidth) {
429f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
439f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
449f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
459f5dab3fc228fa11c32b483e6101ec086895a32bRomain GuyFont::~Font() {
469b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy    mState->removeFont(this);
479f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
489f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
499f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        delete mCachedGlyphs.valueAt(i);
509f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
519f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
529f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
538087246d9964b11de8ce116bc63b156faa4197e0Romain Guyvoid Font::invalidateTextureCache(CacheTexture* cacheTexture) {
549f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
559f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueAt(i);
56521dc51fd411285f900c083a4fe560d2ed7c3f8aRomain Guy        if (!cacheTexture || cachedGlyph->mCacheTexture == cacheTexture) {
579f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            cachedGlyph->mIsValid = false;
589f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        }
599f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
609f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
619f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
629f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guyvoid Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y,
639f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
649f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    int nPenX = x + glyph->mBitmapLeft;
659f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    int nPenY = y + glyph->mBitmapTop;
669f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
679f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    int width = (int) glyph->mBitmapWidth;
689f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    int height = (int) glyph->mBitmapHeight;
699f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
709f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (bounds->bottom > nPenY) {
719f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        bounds->bottom = nPenY;
729f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
739f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (bounds->left > nPenX) {
749f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        bounds->left = nPenX;
759f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
769f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (bounds->right < nPenX + width) {
779f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        bounds->right = nPenX + width;
789f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
799f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (bounds->top < nPenY + height) {
809f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        bounds->top = nPenY + height;
819f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
829f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
839f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
849f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guyvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
859f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
869f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    int nPenX = x + glyph->mBitmapLeft;
879f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    int nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight;
889f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
899f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    float u1 = glyph->mBitmapMinU;
909f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    float u2 = glyph->mBitmapMaxU;
919f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    float v1 = glyph->mBitmapMinV;
929f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    float v2 = glyph->mBitmapMaxV;
939f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
949f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    int width = (int) glyph->mBitmapWidth;
959f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    int height = (int) glyph->mBitmapHeight;
969f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
979f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    mState->appendMeshQuad(nPenX, nPenY, u1, v2,
989f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            nPenX + width, nPenY, u2, v2,
999f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            nPenX + width, nPenY - height, u2, v1,
1009f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            nPenX, nPenY - height, u1, v1, glyph->mCacheTexture);
1019f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
1029f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1039f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guyvoid Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y,
1049f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
1059f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    int nPenX = x + glyph->mBitmapLeft;
1069f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    int nPenY = y + glyph->mBitmapTop;
1079f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1089f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint32_t endX = glyph->mStartX + glyph->mBitmapWidth;
1099f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint32_t endY = glyph->mStartY + glyph->mBitmapHeight;
1109f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1118087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    CacheTexture* cacheTexture = glyph->mCacheTexture;
1128087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    uint32_t cacheWidth = cacheTexture->getWidth();
1138087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    const uint8_t* cacheBuffer = cacheTexture->getTexture();
1149f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1159f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint32_t cacheX = 0, cacheY = 0;
1169f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    int32_t bX = 0, bY = 0;
1179f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
1189f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
1199f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#if DEBUG_FONT_RENDERER
1209f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
1219f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                ALOGE("Skipping invalid index");
1229f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                continue;
1239f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            }
1249f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif
1259f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
1269f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            bitmap[bY * bitmapW + bX] = tempCol;
1279f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        }
1289f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
1299f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
1309f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1319f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guyvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset,
1329f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        SkPathMeasure& measure, SkPoint* position, SkVector* tangent) {
1339f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    const float halfWidth = glyph->mBitmapWidth * 0.5f;
1349f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    const float height = glyph->mBitmapHeight;
1359f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1369f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    vOffset += glyph->mBitmapTop + height;
1379f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1389f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    SkPoint destination[4];
1399f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    measure.getPosTan(x + hOffset +  glyph->mBitmapLeft + halfWidth, position, tangent);
1409f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1419f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    // Move along the tangent and offset by the normal
1429f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    destination[0].set(-tangent->fX * halfWidth - tangent->fY * vOffset,
1439f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            -tangent->fY * halfWidth + tangent->fX * vOffset);
1449f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    destination[1].set(tangent->fX * halfWidth - tangent->fY * vOffset,
1459f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            tangent->fY * halfWidth + tangent->fX * vOffset);
1469f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    destination[2].set(destination[1].fX + tangent->fY * height,
1479f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            destination[1].fY - tangent->fX * height);
1489f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    destination[3].set(destination[0].fX + tangent->fY * height,
1499f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            destination[0].fY - tangent->fX * height);
1509f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1519f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    const float u1 = glyph->mBitmapMinU;
1529f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    const float u2 = glyph->mBitmapMaxU;
1539f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    const float v1 = glyph->mBitmapMinV;
1549f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    const float v2 = glyph->mBitmapMaxV;
1559f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1569f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    mState->appendRotatedMeshQuad(
1579f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            position->fX + destination[0].fX,
1589f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            position->fY + destination[0].fY, u1, v2,
1599f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            position->fX + destination[1].fX,
1609f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            position->fY + destination[1].fY, u2, v2,
1619f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            position->fX + destination[2].fX,
1629f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            position->fY + destination[2].fY, u2, v1,
1639f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            position->fX + destination[3].fX,
1649f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            position->fY + destination[3].fY, u1, v1,
1659f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            glyph->mCacheTexture);
1669f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
1679f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1689f5dab3fc228fa11c32b483e6101ec086895a32bRomain GuyCachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit, bool precaching) {
1699f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    CachedGlyphInfo* cachedGlyph = NULL;
1709f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    ssize_t index = mCachedGlyphs.indexOfKey(textUnit);
1719f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (index >= 0) {
1729f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        cachedGlyph = mCachedGlyphs.valueAt(index);
1739f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    } else {
1749f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        cachedGlyph = cacheGlyph(paint, textUnit, precaching);
1759f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
1769f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1779f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    // Is the glyph still in texture cache?
1789f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (!cachedGlyph->mIsValid) {
1799f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit);
1809f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        updateGlyphCache(paint, skiaGlyph, cachedGlyph, precaching);
1819f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
1829f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1839f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    return cachedGlyph;
1849f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
1859f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1869f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guyvoid Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
1879f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        int numGlyphs, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
1889f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (bitmap != NULL && bitmapW > 0 && bitmapH > 0) {
1899f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        render(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap,
1909f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                bitmapW, bitmapH, NULL, NULL);
1919f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    } else {
1929f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
1939f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                0, 0, NULL, NULL);
1949f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
1959f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
1969f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1979f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guyvoid Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
1989f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            int numGlyphs, int x, int y, const float* positions) {
1999f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
2009f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            0, 0, NULL, positions);
2019f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
2029f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2039f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guyvoid Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
2049f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        int numGlyphs, SkPath* path, float hOffset, float vOffset) {
2059f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (numGlyphs == 0 || text == NULL || len == 0) {
2069f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        return;
2079f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
2089f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2099f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    text += start;
2109f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2119f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    int glyphsCount = 0;
2129f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    SkFixed prevRsbDelta = 0;
2139f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2149f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    float penX = 0.0f;
2159f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2169f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    SkPoint position;
2179f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    SkVector tangent;
2189f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2199f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    SkPathMeasure measure(*path, false);
2209f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    float pathLength = SkScalarToFloat(measure.getLength());
2219f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2229f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (paint->getTextAlign() != SkPaint::kLeft_Align) {
2239f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        float textWidth = SkScalarToFloat(paint->measureText(text, len));
2249f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        float pathOffset = pathLength;
2259f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        if (paint->getTextAlign() == SkPaint::kCenter_Align) {
2269f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            textWidth *= 0.5f;
2279f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            pathOffset *= 0.5f;
2289f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        }
2299f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        penX += pathOffset - textWidth;
2309f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
2319f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2329f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    while (glyphsCount < numGlyphs && penX < pathLength) {
2339f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        glyph_t glyph = GET_GLYPH(text);
2349f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2359f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        if (IS_END_OF_STRING(glyph)) {
2369f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            break;
2379f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        }
2389f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2399f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
2409f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta));
2419f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        prevRsbDelta = cachedGlyph->mRsbDelta;
2429f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2439f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        if (cachedGlyph->mIsValid) {
2449f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            drawCachedGlyph(cachedGlyph, penX, hOffset, vOffset, measure, &position, &tangent);
2459f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        }
2469f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2479f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        penX += SkFixedToFloat(cachedGlyph->mAdvanceX);
2489f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2499f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        glyphsCount++;
2509f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
2519f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
2529f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2539f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guyvoid Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
2549f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        int numGlyphs, Rect *bounds, const float* positions) {
2559f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (bounds == NULL) {
2569f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        ALOGE("No return rectangle provided to measure text");
2579f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        return;
2589f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
2599f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    bounds->set(1e6, -1e6, -1e6, 1e6);
2609f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds, positions);
2619f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
2629f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2639f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guyvoid Font::precache(SkPaint* paint, const char* text, int numGlyphs) {
2649f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2659f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (numGlyphs == 0 || text == NULL) {
2669f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        return;
2679f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
2689f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    int glyphsCount = 0;
2699f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2709f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    while (glyphsCount < numGlyphs) {
2719f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        glyph_t glyph = GET_GLYPH(text);
2729f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2739f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        // Reached the end of the string
2749f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        if (IS_END_OF_STRING(glyph)) {
2759f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            break;
2769f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        }
2779f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2789f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph, true);
2799f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2809f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        glyphsCount++;
2819f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
2829f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
2839f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2849f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guyvoid Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
2859f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
2869f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* positions) {
2879f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (numGlyphs == 0 || text == NULL || len == 0) {
2889f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        return;
2899f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
2909f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2919f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    static RenderGlyph gRenderGlyph[] = {
2929f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            &android::uirenderer::Font::drawCachedGlyph,
2939f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            &android::uirenderer::Font::drawCachedGlyphBitmap,
2949f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            &android::uirenderer::Font::measureCachedGlyph
2959f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    };
2969f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    RenderGlyph render = gRenderGlyph[mode];
2979f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2989f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    text += start;
2999f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    int glyphsCount = 0;
3009f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3019f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (CC_LIKELY(positions == NULL)) {
3029f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        SkFixed prevRsbDelta = 0;
3039f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3049f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        float penX = x + 0.5f;
3059f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        int penY = y;
3069f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3079f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        while (glyphsCount < numGlyphs) {
3089f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            glyph_t glyph = GET_GLYPH(text);
3099f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3109f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            // Reached the end of the string
3119f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            if (IS_END_OF_STRING(glyph)) {
3129f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                break;
3139f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            }
3149f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3159f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
3169f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta));
3179f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            prevRsbDelta = cachedGlyph->mRsbDelta;
3189f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3199f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
3209f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            if (cachedGlyph->mIsValid) {
3219f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                (*this.*render)(cachedGlyph, (int) floorf(penX), penY,
3229f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                        bitmap, bitmapW, bitmapH, bounds, positions);
3239f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            }
3249f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3259f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            penX += SkFixedToFloat(cachedGlyph->mAdvanceX);
3269f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3279f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            glyphsCount++;
3289f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        }
3299f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    } else {
3309f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        const SkPaint::Align align = paint->getTextAlign();
3319f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3329f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        // This is for renderPosText()
3339f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        while (glyphsCount < numGlyphs) {
3349f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            glyph_t glyph = GET_GLYPH(text);
3359f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3369f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            // Reached the end of the string
3379f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            if (IS_END_OF_STRING(glyph)) {
3389f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                break;
3399f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            }
3409f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3419f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
3429f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3439f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
3449f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            if (cachedGlyph->mIsValid) {
3459f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                int penX = x + positions[(glyphsCount << 1)];
3469f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                int penY = y + positions[(glyphsCount << 1) + 1];
3479f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3489f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                switch (align) {
3499f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                    case SkPaint::kRight_Align:
3509f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                        penX -= SkFixedToFloat(cachedGlyph->mAdvanceX);
3519f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                        penY -= SkFixedToFloat(cachedGlyph->mAdvanceY);
3529f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                        break;
3539f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                    case SkPaint::kCenter_Align:
3549f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                        penX -= SkFixedToFloat(cachedGlyph->mAdvanceX >> 1);
3559f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                        penY -= SkFixedToFloat(cachedGlyph->mAdvanceY >> 1);
3569f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                    default:
3579f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                        break;
3589f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                }
3599f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3609f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                (*this.*render)(cachedGlyph, penX, penY,
3619f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                        bitmap, bitmapW, bitmapH, bounds, positions);
3629f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            }
3639f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3649f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            glyphsCount++;
3659f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        }
3669f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
3679f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
3689f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3699f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guyvoid Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph,
3709f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        bool precaching) {
3719f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    glyph->mAdvanceX = skiaGlyph.fAdvanceX;
3729f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    glyph->mAdvanceY = skiaGlyph.fAdvanceY;
3739f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    glyph->mBitmapLeft = skiaGlyph.fLeft;
3749f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    glyph->mBitmapTop = skiaGlyph.fTop;
3759f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    glyph->mLsbDelta = skiaGlyph.fLsbDelta;
3769f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    glyph->mRsbDelta = skiaGlyph.fRsbDelta;
3779f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3789f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint32_t startX = 0;
3799f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint32_t startY = 0;
3809f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3819f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    // Get the bitmap for the glyph
3829f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    paint->findImage(skiaGlyph);
3839f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY, precaching);
3849f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3859f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (!glyph->mIsValid) {
3869f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        return;
3879f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
3889f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3899f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint32_t endX = startX + skiaGlyph.fWidth;
3909f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint32_t endY = startY + skiaGlyph.fHeight;
3919f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3929f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    glyph->mStartX = startX;
3939f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    glyph->mStartY = startY;
3949f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    glyph->mBitmapWidth = skiaGlyph.fWidth;
3959f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    glyph->mBitmapHeight = skiaGlyph.fHeight;
3969f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3978087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    uint32_t cacheWidth = glyph->mCacheTexture->getWidth();
3988087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    uint32_t cacheHeight = glyph->mCacheTexture->getHeight();
3999f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
4009f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    glyph->mBitmapMinU = startX / (float) cacheWidth;
4019f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    glyph->mBitmapMinV = startY / (float) cacheHeight;
4029f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    glyph->mBitmapMaxU = endX / (float) cacheWidth;
4039f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    glyph->mBitmapMaxV = endY / (float) cacheHeight;
4049f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
4059b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy    mState->setTextureDirty();
4069f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
4079f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
4089f5dab3fc228fa11c32b483e6101ec086895a32bRomain GuyCachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph, bool precaching) {
4099f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
4109f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    mCachedGlyphs.add(glyph, newGlyph);
4119f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
4129f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph);
4139f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    newGlyph->mGlyphIndex = skiaGlyph.fID;
4149f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    newGlyph->mIsValid = false;
4159f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
4169f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    updateGlyphCache(paint, skiaGlyph, newGlyph, precaching);
4179f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
4189f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    return newGlyph;
4199f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
4209f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
4219f5dab3fc228fa11c32b483e6101ec086895a32bRomain GuyFont* Font::create(FontRenderer* state, uint32_t fontId, float fontSize,
4229f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        int flags, uint32_t italicStyle, uint32_t scaleX,
4239f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        SkPaint::Style style, uint32_t strokeWidth) {
4249f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    Vector<Font*> &activeFonts = state->mActiveFonts;
4259f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
4269f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    for (uint32_t i = 0; i < activeFonts.size(); i++) {
4279f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        Font* font = activeFonts[i];
4289f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        if (font->mFontId == fontId && font->mFontSize == fontSize &&
4299f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                font->mFlags == flags && font->mItalicStyle == italicStyle &&
4309f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                font->mScaleX == scaleX && font->mStyle == style &&
4319f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                (style == SkPaint::kFill_Style || font->mStrokeWidth == strokeWidth)) {
4329f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            return font;
4339f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        }
4349f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
4359f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
4369f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle,
4379f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            scaleX, style, strokeWidth);
4389f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    activeFonts.push(newFont);
4399f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    return newFont;
4409f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
4419f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
4429f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}; // namespace uirenderer
4439f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}; // namespace android
444