1694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/*
2694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * Copyright (C) 2010 The Android Open Source Project
3694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *
4694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * Licensed under the Apache License, Version 2.0 (the "License");
5694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * you may not use this file except in compliance with the License.
6694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * You may obtain a copy of the License at
7694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *
8694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *      http://www.apache.org/licenses/LICENSE-2.0
9694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *
10694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * Unless required by applicable law or agreed to in writing, software
11694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * distributed under the License is distributed on an "AS IS" BASIS,
12694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * See the License for the specific language governing permissions and
14694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * limitations under the License.
15694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy */
16694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
1796a5c4c7bab6718524de7253da8309143ab48befChris Craik#include "FontRenderer.h"
1896a5c4c7bab6718524de7253da8309143ab48befChris Craik
1996a5c4c7bab6718524de7253da8309143ab48befChris Craik#include "Caches.h"
2096a5c4c7bab6718524de7253da8309143ab48befChris Craik#include "Debug.h"
2196a5c4c7bab6718524de7253da8309143ab48befChris Craik#include "Extensions.h"
22e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik#include "Glop.h"
23e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik#include "GlopBuilder.h"
2496a5c4c7bab6718524de7253da8309143ab48befChris Craik#include "PixelBuffer.h"
2596a5c4c7bab6718524de7253da8309143ab48befChris Craik#include "Rect.h"
2696a5c4c7bab6718524de7253da8309143ab48befChris Craik#include "renderstate/RenderState.h"
2796a5c4c7bab6718524de7253da8309143ab48befChris Craik#include "utils/Blur.h"
2896a5c4c7bab6718524de7253da8309143ab48befChris Craik#include "utils/Timing.h"
29694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
30a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik
31a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik#if HWUI_NEW_OPS
329e7fcfda28fde747ba4e026772007cea77374e16Chris Craik#include "BakedOpDispatcher.h"
33a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik#include "BakedOpRenderer.h"
349e7fcfda28fde747ba4e026772007cea77374e16Chris Craik#include "BakedOpState.h"
35a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik#else
36a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik#include "OpenGLRenderer.h"
37a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik#endif
38a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik
399db58c031f8ffa102a6d585cb585bed3bdb911a9Chris Craik#include <algorithm>
409db58c031f8ffa102a6d585cb585bed3bdb911a9Chris Craik#include <cutils/properties.h>
41ca79cf69d09efa0c327e9b1237d86a119aea5da7Derek Sollenberger#include <SkGlyph.h>
42694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy#include <SkUtils.h>
4351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#include <utils/Log.h>
4451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
45e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrill#ifdef ANDROID_ENABLE_RENDERSCRIPT
466e2004089305cf2cd958b52b234459a49a4e5c83Romain Guy#include <RenderScript.h>
47e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrill#endif
48f2d8ccc15d7272b3416f73605c1f31d1d346bd40Chris Craik
49694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guynamespace android {
50694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guynamespace uirenderer {
51694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
52f2d8ccc15d7272b3416f73605c1f31d1d346bd40Chris Craik// blur inputs smaller than this constant will bypass renderscript
53f2d8ccc15d7272b3416f73605c1f31d1d346bd40Chris Craik#define RS_MIN_INPUT_CUTOFF 10000
54f2d8ccc15d7272b3416f73605c1f31d1d346bd40Chris Craik
55694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy///////////////////////////////////////////////////////////////////////////////
561e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease// TextSetupFunctor
571e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease///////////////////////////////////////////////////////////////////////////////
581e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease
59828407356dd5c34a3e441604aaf895cbec7c7e66Chris Craikvoid TextDrawFunctor::draw(CacheTexture& texture, bool linearFiltering) {
6053e51e4aa933f9603587e1780f446c18816bf9beChris Craik    int textureFillFlags = TextureFillFlags::None;
6153e51e4aa933f9603587e1780f446c18816bf9beChris Craik    if (texture.getFormat() == GL_ALPHA) {
6253e51e4aa933f9603587e1780f446c18816bf9beChris Craik        textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture;
6353e51e4aa933f9603587e1780f446c18816bf9beChris Craik    }
64e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik    if (linearFiltering) {
6553e51e4aa933f9603587e1780f446c18816bf9beChris Craik        textureFillFlags |= TextureFillFlags::ForceFilter;
66e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik    }
6753e51e4aa933f9603587e1780f446c18816bf9beChris Craik    int transformFlags = pureTranslate
6853e51e4aa933f9603587e1780f446c18816bf9beChris Craik            ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
69e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik    Glop glop;
70a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik#if HWUI_NEW_OPS
71a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    GlopBuilder(renderer->renderState(), renderer->caches(), &glop)
72a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            .setRoundRectClipState(bakedState->roundRectClipState)
73a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
74a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, bakedState->alpha)
75a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            .setTransform(bakedState->computedState.transform, transformFlags)
76f09ff5aa57bff01cb17595fb7ca8e48d238a6acdChris Craik            .setModelViewIdentityEmptyBounds()
77a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            .build();
7815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // Note: don't pass dirty bounds here, so user must manage passing dirty bounds to renderer
7915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    renderer->renderGlop(nullptr, clip, glop);
80a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik#else
81e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik    GlopBuilder(renderer->mRenderState, renderer->mCaches, &glop)
82a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            .setRoundRectClipState(renderer->currentSnapshot()->roundRectClipState)
83e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik            .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
84e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik            .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, renderer->currentSnapshot()->alpha)
8553e51e4aa933f9603587e1780f446c18816bf9beChris Craik            .setTransform(*(renderer->currentSnapshot()), transformFlags)
865430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik            .setModelViewOffsetRect(0, 0, Rect())
87e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik            .build();
88e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik    renderer->renderGlop(glop);
89a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik#endif
901e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease}
911e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease
921e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease///////////////////////////////////////////////////////////////////////////////
93694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// FontRenderer
94694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy///////////////////////////////////////////////////////////////////////////////
95694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
96514fb18827186591d66973c2362c859b64b63556Romain Guystatic bool sLogFontRendererCreate = true;
97514fb18827186591d66973c2362c859b64b63556Romain Guy
98c08820f587ad94698691a6657e87712de07e484cChris CraikFontRenderer::FontRenderer(const uint8_t* gammaTable)
99c08820f587ad94698691a6657e87712de07e484cChris Craik        : mGammaTable(gammaTable)
100083e733e8223a7d416d6c139f318e61864b28ad6Chris Craik        , mCurrentFont(nullptr)
101083e733e8223a7d416d6c139f318e61864b28ad6Chris Craik        , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity)
102083e733e8223a7d416d6c139f318e61864b28ad6Chris Craik        , mCurrentCacheTexture(nullptr)
103083e733e8223a7d416d6c139f318e61864b28ad6Chris Craik        , mUploadTexture(false)
104083e733e8223a7d416d6c139f318e61864b28ad6Chris Craik        , mFunctor(nullptr)
105083e733e8223a7d416d6c139f318e61864b28ad6Chris Craik        , mClip(nullptr)
106083e733e8223a7d416d6c139f318e61864b28ad6Chris Craik        , mBounds(nullptr)
107083e733e8223a7d416d6c139f318e61864b28ad6Chris Craik        , mDrawn(false)
108083e733e8223a7d416d6c139f318e61864b28ad6Chris Craik        , mInitialized(false)
109083e733e8223a7d416d6c139f318e61864b28ad6Chris Craik        , mLinearFiltering(false) {
110e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy
111c9855a53edfac818dc68714557185977556f849dRomain Guy    if (sLogFontRendererCreate) {
112c9855a53edfac818dc68714557185977556f849dRomain Guy        INIT_LOGD("Creating FontRenderer");
113c9855a53edfac818dc68714557185977556f849dRomain Guy    }
11451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
115c08820f587ad94698691a6657e87712de07e484cChris Craik    mSmallCacheWidth = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_WIDTH,
116c08820f587ad94698691a6657e87712de07e484cChris Craik            DEFAULT_TEXT_SMALL_CACHE_WIDTH);
117c08820f587ad94698691a6657e87712de07e484cChris Craik    mSmallCacheHeight = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_HEIGHT,
118c08820f587ad94698691a6657e87712de07e484cChris Craik            DEFAULT_TEXT_SMALL_CACHE_HEIGHT);
11951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
120c08820f587ad94698691a6657e87712de07e484cChris Craik    mLargeCacheWidth = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_WIDTH,
121c08820f587ad94698691a6657e87712de07e484cChris Craik            DEFAULT_TEXT_LARGE_CACHE_WIDTH);
122c08820f587ad94698691a6657e87712de07e484cChris Craik    mLargeCacheHeight = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_HEIGHT,
123c08820f587ad94698691a6657e87712de07e484cChris Craik            DEFAULT_TEXT_LARGE_CACHE_HEIGHT);
1249f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1259f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
126083e733e8223a7d416d6c139f318e61864b28ad6Chris Craik
1279db58c031f8ffa102a6d585cb585bed3bdb911a9Chris Craik    mSmallCacheWidth = std::min(mSmallCacheWidth, maxTextureSize);
1289db58c031f8ffa102a6d585cb585bed3bdb911a9Chris Craik    mSmallCacheHeight = std::min(mSmallCacheHeight, maxTextureSize);
1299db58c031f8ffa102a6d585cb585bed3bdb911a9Chris Craik    mLargeCacheWidth = std::min(mLargeCacheWidth, maxTextureSize);
1309db58c031f8ffa102a6d585cb585bed3bdb911a9Chris Craik    mLargeCacheHeight = std::min(mLargeCacheHeight, maxTextureSize);
1319f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
132eb32a499194119b3783b86c925172df02e5d2685Chet Haase    if (sLogFontRendererCreate) {
133eb32a499194119b3783b86c925172df02e5d2685Chet Haase        INIT_LOGD("  Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
134eb32a499194119b3783b86c925172df02e5d2685Chet Haase                mSmallCacheWidth, mSmallCacheHeight,
135eb32a499194119b3783b86c925172df02e5d2685Chet Haase                mLargeCacheWidth, mLargeCacheHeight >> 1,
136eb32a499194119b3783b86c925172df02e5d2685Chet Haase                mLargeCacheWidth, mLargeCacheHeight >> 1,
137eb32a499194119b3783b86c925172df02e5d2685Chet Haase                mLargeCacheWidth, mLargeCacheHeight);
13851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    }
139514fb18827186591d66973c2362c859b64b63556Romain Guy
140514fb18827186591d66973c2362c859b64b63556Romain Guy    sLogFontRendererCreate = false;
141694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
142694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
143272a685f17cc4828257e521a6f62b7b17870f75eJohn Reckvoid clearCacheTextures(std::vector<CacheTexture*>& cacheTextures) {
1441e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
1451e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        delete cacheTextures[i];
146694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
1471e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    cacheTextures.clear();
1481e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease}
1491e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease
1501e546815bbb736c50679a8aefc25f48561026fc5Victoria LeaseFontRenderer::~FontRenderer() {
1511e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    clearCacheTextures(mACacheTextures);
1521e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    clearCacheTextures(mRGBACacheTextures);
153694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
154e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy    LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
155e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy    while (it.next()) {
156e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy        delete it.value();
157694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
158e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy    mActiveFonts.clear();
159694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
160694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
161694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::flushAllAndInvalidate() {
162661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    issueDrawCommand();
1639d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
164e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy    LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
165e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy    while (it.next()) {
166e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy        it.value()->invalidateTextureCache();
167694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
1689d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
1691e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
1701e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        mACacheTextures[i]->init();
1711e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    }
1721e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease
1731e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
1741e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        mRGBACacheTextures[i]->init();
175e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase    }
1761f61b1911e03ef3fc51c3db64798071f3a7477ecchaochen
1771f61b1911e03ef3fc51c3db64798071f3a7477ecchaochen    mDrawn = false;
178694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
179694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
180272a685f17cc4828257e521a6f62b7b17870f75eJohn Reckvoid FontRenderer::flushLargeCaches(std::vector<CacheTexture*>& cacheTextures) {
181378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase    // Start from 1; don't deallocate smallest/default texture
1821e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    for (uint32_t i = 1; i < cacheTextures.size(); i++) {
1831e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        CacheTexture* cacheTexture = cacheTextures[i];
184cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy        if (cacheTexture->getPixelBuffer()) {
185378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase            cacheTexture->init();
186e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy            LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
187e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy            while (it.next()) {
188e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy                it.value()->invalidateTextureCache(cacheTexture);
1899a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase            }
190e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik            cacheTexture->releasePixelBuffer();
1919a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase        }
1929a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase    }
1939a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase}
1949a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase
1951e546815bbb736c50679a8aefc25f48561026fc5Victoria Leasevoid FontRenderer::flushLargeCaches() {
1961e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    flushLargeCaches(mACacheTextures);
1971e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    flushLargeCaches(mRGBACacheTextures);
1981e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease}
1991e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease
200272a685f17cc4828257e521a6f62b7b17870f75eJohn ReckCacheTexture* FontRenderer::cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures,
2011e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
2021e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
2031e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
2041e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            return cacheTextures[i];
205378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase        }
206378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase    }
207378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase    // Could not fit glyph into current cache textures
208d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    return nullptr;
209378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase}
210378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase
2117de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasevoid FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
212f942cf10e04567f6b9456f6258e29c803b8bfb41Chet Haase        uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
2132efd5c5886d9acf747bc92f888d731ed558aabccChet Haase    checkInit();
214a4adcf0239039eb8f005be252409901c41b28839Romain Guy
215a4adcf0239039eb8f005be252409901c41b28839Romain Guy    // If the glyph bitmap is empty let's assum the glyph is valid
216a4adcf0239039eb8f005be252409901c41b28839Romain Guy    // so we can avoid doing extra work later on
217a4adcf0239039eb8f005be252409901c41b28839Romain Guy    if (glyph.fWidth == 0 || glyph.fHeight == 0) {
218a4adcf0239039eb8f005be252409901c41b28839Romain Guy        cachedGlyph->mIsValid = true;
219d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik        cachedGlyph->mCacheTexture = nullptr;
220a4adcf0239039eb8f005be252409901c41b28839Romain Guy        return;
221a4adcf0239039eb8f005be252409901c41b28839Romain Guy    }
222a4adcf0239039eb8f005be252409901c41b28839Romain Guy
2237de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    cachedGlyph->mIsValid = false;
224a4adcf0239039eb8f005be252409901c41b28839Romain Guy
2251e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    // choose an appropriate cache texture list for this glyph format
2261e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
227272a685f17cc4828257e521a6f62b7b17870f75eJohn Reck    std::vector<CacheTexture*>* cacheTextures = nullptr;
2281e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    switch (format) {
2291e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        case SkMask::kA8_Format:
230723b2feb929b96b1dde40a865c49ea18bc42f055Victoria Lease        case SkMask::kBW_Format:
2311e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            cacheTextures = &mACacheTextures;
2321e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            break;
2331e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        case SkMask::kARGB32_Format:
2341e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            cacheTextures = &mRGBACacheTextures;
2351e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            break;
2361e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        default:
2371e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease#if DEBUG_FONT_RENDERER
2381e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
2391e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease#endif
2401e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        return;
2411e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    }
2421e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease
243694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // If the glyph is too tall, don't cache it
244378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase    if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
2451e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease                (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
2462efd5c5886d9acf747bc92f888d731ed558aabccChet Haase        ALOGE("Font size too large to fit in cache. width, height = %i, %i",
2472efd5c5886d9acf747bc92f888d731ed558aabccChet Haase                (int) glyph.fWidth, (int) glyph.fHeight);
2487de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        return;
249694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
250694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
251694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    // Now copy the bitmap into the cache texture
252694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startX = 0;
253694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t startY = 0;
254694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
2551e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
256694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
257378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase    if (!cacheTexture) {
258f942cf10e04567f6b9456f6258e29c803b8bfb41Chet Haase        if (!precaching) {
259f942cf10e04567f6b9456f6258e29c803b8bfb41Chet Haase            // If the new glyph didn't fit and we are not just trying to precache it,
260f942cf10e04567f6b9456f6258e29c803b8bfb41Chet Haase            // clear out the cache and try again
261f942cf10e04567f6b9456f6258e29c803b8bfb41Chet Haase            flushAllAndInvalidate();
2621e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
263f942cf10e04567f6b9456f6258e29c803b8bfb41Chet Haase        }
264694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
265378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase        if (!cacheTexture) {
266f942cf10e04567f6b9456f6258e29c803b8bfb41Chet Haase            // either the glyph didn't fit or we're precaching and will cache it when we draw
2677de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase            return;
268694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
269694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
270694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
271378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase    cachedGlyph->mCacheTexture = cacheTexture;
2727de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
273694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    *retOriginX = startX;
274694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    *retOriginY = startY;
275694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
276694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endX = startX + glyph.fWidth;
277694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    uint32_t endY = startY + glyph.fHeight;
278694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
2798087246d9964b11de8ce116bc63b156faa4197e0Romain Guy    uint32_t cacheWidth = cacheTexture->getWidth();
280694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
281cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    if (!cacheTexture->getPixelBuffer()) {
28244eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik        Caches::getInstance().textureState().activateTexture(0);
2837de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        // Large-glyph texture memory is allocated only as needed
284e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        cacheTexture->allocatePixelBuffer();
2857de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    }
286661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    if (!cacheTexture->mesh()) {
287661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        cacheTexture->allocateMesh();
288661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    }
2899d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
290cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
291b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy    uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
2921e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    int srcStride = glyph.rowBytes();
2930b58a3deab66c30a8d35072e55aac6279dd367ccRomain Guy
2941e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    // Copy the glyph image, taking the mask format into account
295b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy    switch (format) {
296b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy        case SkMask::kA8_Format: {
2971e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
2981e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
2991e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease                    - TEXTURE_BORDER_SIZE;
3001e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            // write leading border line
3011e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
3021e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            // write glyph data
303b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy            if (mGammaTable) {
3041e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease                for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
3050b58a3deab66c30a8d35072e55aac6279dd367ccRomain Guy                    row = cacheY * cacheWidth;
3060b58a3deab66c30a8d35072e55aac6279dd367ccRomain Guy                    cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
307b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy                    for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
308b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy                        uint8_t tempCol = bitmapBuffer[bY + bX];
3090b58a3deab66c30a8d35072e55aac6279dd367ccRomain Guy                        cacheBuffer[row + cacheX] = mGammaTable[tempCol];
310b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy                    }
3110b58a3deab66c30a8d35072e55aac6279dd367ccRomain Guy                    cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
312b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy                }
313b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy            } else {
3141e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease                for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
3150b58a3deab66c30a8d35072e55aac6279dd367ccRomain Guy                    row = cacheY * cacheWidth;
3160b58a3deab66c30a8d35072e55aac6279dd367ccRomain Guy                    memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
3170b58a3deab66c30a8d35072e55aac6279dd367ccRomain Guy                    cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
3180b58a3deab66c30a8d35072e55aac6279dd367ccRomain Guy                    cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
319b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy                }
320b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy            }
3211e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            // write trailing border line
3221e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
3231e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
3241e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            break;
3251e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        }
3261e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        case SkMask::kARGB32_Format: {
3271e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            // prep data lengths
3281e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
3291e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
3301e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            size_t rowSize = formatSize * glyph.fWidth;
3311e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            // prep advances
3321e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            size_t dstStride = formatSize * cacheWidth;
3331e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            // prep indices
3341e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            // - we actually start one row early, and then increment before first copy
3351e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            uint8_t* src = &bitmapBuffer[0 - srcStride];
3361e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
3371e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
3381e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            uint8_t* dstL = dst - borderSize;
3391e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            uint8_t* dstR = dst + rowSize;
3401e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            // write leading border line
3411e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            memset(dstL, 0, rowSize + 2 * borderSize);
3421e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            // write glyph data
3431e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            while (dst < dstEnd) {
3441e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease                memset(dstL += dstStride, 0, borderSize); // leading border column
3451e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease                memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
3461e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease                memset(dstR += dstStride, 0, borderSize); // trailing border column
3471e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            }
3481e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            // write trailing border line
34916c84069a4cc0c0d3c35e798dc5e4b0130d4a26fVictoria Lease            memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
350b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy            break;
351b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy        }
352b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy        case SkMask::kBW_Format: {
3531e19674107e1aa2224c2b8c7d12bfa057efe80eaAndreas Gampe            uint32_t cacheX = 0, cacheY = 0;
3541e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
3551e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease                    - TEXTURE_BORDER_SIZE;
356b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy            static const uint8_t COLORS[2] = { 0, 255 };
3571e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            // write leading border line
3581e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
3591e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            // write glyph data
360b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy            for (cacheY = startY; cacheY < endY; cacheY++) {
361b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy                cacheX = startX;
3621e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease                int rowBytes = srcStride;
363b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy                uint8_t* buffer = bitmapBuffer;
364b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy
3650b58a3deab66c30a8d35072e55aac6279dd367ccRomain Guy                row = cacheY * cacheWidth;
3660b58a3deab66c30a8d35072e55aac6279dd367ccRomain Guy                cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
367b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy                while (--rowBytes >= 0) {
368b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy                    uint8_t b = *buffer++;
369b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy                    for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
370b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy                        cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
371b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy                    }
372b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy                }
3730b58a3deab66c30a8d35072e55aac6279dd367ccRomain Guy                cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
374b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy
3751e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease                bitmapBuffer += srcStride;
376b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy            }
3771e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            // write trailing border line
3781e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
3791e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
380b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy            break;
381694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
382b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy        default:
3831e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            ALOGW("Unknown glyph format: 0x%x", format);
384b969a0de65730b071d846f8302e751e2637e6dbeRomain Guy            break;
385694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
3869777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
3877de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    cachedGlyph->mIsValid = true;
388694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
389694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
3901e546815bbb736c50679a8aefc25f48561026fc5Victoria LeaseCacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
3911e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        bool allocate) {
39296a5c4c7bab6718524de7253da8309143ab48befChris Craik    CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
3939d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
3942a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    if (allocate) {
39544eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik        Caches::getInstance().textureState().activateTexture(0);
396e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        cacheTexture->allocatePixelBuffer();
397661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        cacheTexture->allocateMesh();
3982a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    }
3999d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
4002a47c14e2a6f152496b43104bc785c488583fd59Chet Haase    return cacheTexture;
4017de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase}
4027de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase
4037de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasevoid FontRenderer::initTextTexture() {
4041e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    clearCacheTextures(mACacheTextures);
4051e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    clearCacheTextures(mRGBACacheTextures);
4069d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy
4077de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    mUploadTexture = false;
408272a685f17cc4828257e521a6f62b7b17870f75eJohn Reck    mACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
4091e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            GL_ALPHA, true));
410272a685f17cc4828257e521a6f62b7b17870f75eJohn Reck    mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
4111e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            GL_ALPHA, false));
412272a685f17cc4828257e521a6f62b7b17870f75eJohn Reck    mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
4131e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            GL_ALPHA, false));
414272a685f17cc4828257e521a6f62b7b17870f75eJohn Reck    mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
4151e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            GL_ALPHA, false));
416272a685f17cc4828257e521a6f62b7b17870f75eJohn Reck    mRGBACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
4171e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            GL_RGBA, false));
418272a685f17cc4828257e521a6f62b7b17870f75eJohn Reck    mRGBACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
4191e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            GL_RGBA, false));
4201e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    mCurrentCacheTexture = mACacheTextures[0];
421694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
422694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
423694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// We don't want to allocate anything unless we actually draw text
424694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::checkInit() {
425694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    if (mInitialized) {
426694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return;
427694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
428694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
429694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    initTextTexture();
430694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
431694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    mInitialized = true;
432694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
433694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
434272a685f17cc4828257e521a6f62b7b17870f75eJohn Reckvoid checkTextureUpdateForCache(Caches& caches, std::vector<CacheTexture*>& cacheTextures,
4351e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        bool& resetPixelStore, GLuint& lastTextureId) {
4361e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
4371e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        CacheTexture* cacheTexture = cacheTextures[i];
438cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy        if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
4398087246d9964b11de8ce116bc63b156faa4197e0Romain Guy            if (cacheTexture->getTextureId() != lastTextureId) {
4408087246d9964b11de8ce116bc63b156faa4197e0Romain Guy                lastTextureId = cacheTexture->getTextureId();
44144eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik                caches.textureState().activateTexture(0);
44244eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik                caches.textureState().bindTexture(lastTextureId);
4430908764b2b3cf5075df4178a5f0a8547dcb7b317Romain Guy            }
4440908764b2b3cf5075df4178a5f0a8547dcb7b317Romain Guy
445cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy            if (cacheTexture->upload()) {
446cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy                resetPixelStore = true;
4472d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy            }
4489b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        }
449694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
4501e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease}
4511e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease
4521e546815bbb736c50679a8aefc25f48561026fc5Victoria Leasevoid FontRenderer::checkTextureUpdate() {
4531e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    if (!mUploadTexture) {
4541e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        return;
4551e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    }
4561e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease
4571e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    Caches& caches = Caches::getInstance();
4581e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    GLuint lastTextureId = 0;
4591e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease
4601e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    bool resetPixelStore = false;
4611e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease
4621e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    // Iterate over all the cache textures and see which ones need to be updated
4631e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
4641e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
465694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
466cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    // Unbind any PBO we might have used to update textures
46744eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    caches.pixelBufferState().unbind();
468cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
4690908764b2b3cf5075df4178a5f0a8547dcb7b317Romain Guy    // Reset to default unpack row length to avoid affecting texture
4700908764b2b3cf5075df4178a5f0a8547dcb7b317Romain Guy    // uploads in other parts of the renderer
471cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    if (resetPixelStore) {
4720908764b2b3cf5075df4178a5f0a8547dcb7b317Romain Guy        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
4730908764b2b3cf5075df4178a5f0a8547dcb7b317Romain Guy    }
4740908764b2b3cf5075df4178a5f0a8547dcb7b317Romain Guy
4759b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    mUploadTexture = false;
4769b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk}
4779b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
478272a685f17cc4828257e521a6f62b7b17870f75eJohn Reckvoid FontRenderer::issueDrawCommand(std::vector<CacheTexture*>& cacheTextures) {
47996a5c4c7bab6718524de7253da8309143ab48befChris Craik    if (!mFunctor) return;
48096a5c4c7bab6718524de7253da8309143ab48befChris Craik
481661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    bool first = true;
4821e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
4831e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        CacheTexture* texture = cacheTextures[i];
484661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        if (texture->canDraw()) {
485661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy            if (first) {
486e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik                checkTextureUpdate();
487661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy                first = false;
488083e733e8223a7d416d6c139f318e61864b28ad6Chris Craik                mDrawn = true;
489661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy            }
4907bb3cfe1cca4016ce95d3ef059761f4bb2d668bbSangkyu Lee
491828407356dd5c34a3e441604aaf895cbec7c7e66Chris Craik            mFunctor->draw(*texture, mLinearFiltering);
492661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
493661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy            texture->resetMesh();
494661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        }
4957bb3cfe1cca4016ce95d3ef059761f4bb2d668bbSangkyu Lee    }
4961e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease}
4971e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease
4981e546815bbb736c50679a8aefc25f48561026fc5Victoria Leasevoid FontRenderer::issueDrawCommand() {
4991e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    issueDrawCommand(mACacheTextures);
5001e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    issueDrawCommand(mRGBACacheTextures);
501694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
502694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
5039777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
5049777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
5057de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        float x4, float y4, float u4, float v4, CacheTexture* texture) {
5067de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    if (texture != mCurrentCacheTexture) {
5077de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        // Now use the new texture id
5087de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase        mCurrentCacheTexture = texture;
5097de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase    }
51009147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy
511661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
512661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy            x3, y3, u3, v3, x4, y4, u4, v4);
5139777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy}
5149777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
5159777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
5169777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
5179777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float x4, float y4, float u4, float v4, CacheTexture* texture) {
5189777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
5199777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (mClip &&
5209777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
5219777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        return;
5229777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
5239777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
5249777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
525694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
5265b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    if (mBounds) {
527e6a15ee3d0c78eb3f2551d73a7d238c3d8d2f075Chris Craik        mBounds->left = std::min(mBounds->left, x1);
528e6a15ee3d0c78eb3f2551d73a7d238c3d8d2f075Chris Craik        mBounds->top = std::min(mBounds->top, y3);
529e6a15ee3d0c78eb3f2551d73a7d238c3d8d2f075Chris Craik        mBounds->right = std::max(mBounds->right, x3);
530e6a15ee3d0c78eb3f2551d73a7d238c3d8d2f075Chris Craik        mBounds->bottom = std::max(mBounds->bottom, y1);
5315b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    }
5325b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
533661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    if (mCurrentCacheTexture->endOfMesh()) {
534694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        issueDrawCommand();
535694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
536694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
537694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
5389777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
5399777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
5409777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        float x4, float y4, float u4, float v4, CacheTexture* texture) {
5419777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
5429777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
5439777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
5449777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (mBounds) {
545e6a15ee3d0c78eb3f2551d73a7d238c3d8d2f075Chris Craik        mBounds->left = std::min(mBounds->left, std::min(x1, std::min(x2, std::min(x3, x4))));
546e6a15ee3d0c78eb3f2551d73a7d238c3d8d2f075Chris Craik        mBounds->top = std::min(mBounds->top, std::min(y1, std::min(y2, std::min(y3, y4))));
547e6a15ee3d0c78eb3f2551d73a7d238c3d8d2f075Chris Craik        mBounds->right = std::max(mBounds->right, std::max(x1, std::max(x2, std::max(x3, x4))));
548e6a15ee3d0c78eb3f2551d73a7d238c3d8d2f075Chris Craik        mBounds->bottom = std::max(mBounds->bottom, std::max(y1, std::max(y2, std::max(y3, y4))));
5499777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
5509777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
551661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    if (mCurrentCacheTexture->endOfMesh()) {
5529777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        issueDrawCommand();
5539777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
5549777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy}
5559777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
55659744b79ec302000802cd56d30a1bf70f0183c80Chris Craikvoid FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
557e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy    mCurrentFont = Font::create(this, paint, matrix);
558694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
5597975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy
560e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris CraikFontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const glyph_t *glyphs,
561a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        int numGlyphs, float radius, const float* positions) {
5621e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    checkInit();
5631e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
564cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    DropShadow image;
565cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    image.width = 0;
566cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    image.height = 0;
567d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    image.image = nullptr;
568cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    image.penX = 0;
569cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    image.penY = 0;
570cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
5711e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    if (!mCurrentFont) {
5721e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        return image;
5731e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    }
574f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
5752d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy    mDrawn = false;
576d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    mClip = nullptr;
577d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    mBounds = nullptr;
578ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy
579f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    Rect bounds;
580e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik    mCurrentFont->measure(paint, glyphs, numGlyphs, &bounds, positions);
581ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy
582e392c81f6b8f9ace0c0a48c9d4df117fda31fd13Derek Sollenberger    uint32_t intRadius = Blur::convertRadiusToInt(radius);
583e392c81f6b8f9ace0c0a48c9d4df117fda31fd13Derek Sollenberger    uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
584e392c81f6b8f9ace0c0a48c9d4df117fda31fd13Derek Sollenberger    uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
585ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy
586cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    uint32_t maxSize = Caches::getInstance().maxTextureSize;
587cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    if (paddedWidth > maxSize || paddedHeight > maxSize) {
588cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy        return image;
589cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    }
590cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
591e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrill#ifdef ANDROID_ENABLE_RENDERSCRIPT
592f2d8ccc15d7272b3416f73605c1f31d1d346bd40Chris Craik    // Align buffers for renderscript usage
593f2d8ccc15d7272b3416f73605c1f31d1d346bd40Chris Craik    if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
594f2d8ccc15d7272b3416f73605c1f31d1d346bd40Chris Craik        paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
595f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
596f2d8ccc15d7272b3416f73605c1f31d1d346bd40Chris Craik    int size = paddedWidth * paddedHeight;
5976e2004089305cf2cd958b52b234459a49a4e5c83Romain Guy    uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
598e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrill#else
599e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrill    int size = paddedWidth * paddedHeight;
600e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrill    uint8_t* dataBuffer = (uint8_t*) malloc(size);
601e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrill#endif
602e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrill
603f2d8ccc15d7272b3416f73605c1f31d1d346bd40Chris Craik    memset(dataBuffer, 0, size);
604f2d8ccc15d7272b3416f73605c1f31d1d346bd40Chris Craik
605e392c81f6b8f9ace0c0a48c9d4df117fda31fd13Derek Sollenberger    int penX = intRadius - bounds.left;
606e392c81f6b8f9ace0c0a48c9d4df117fda31fd13Derek Sollenberger    int penY = intRadius - bounds.bottom;
607f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
608dd8697c095272f19ddad214834a490b00f11a477Chris Craik    if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
609dd8697c095272f19ddad214834a490b00f11a477Chris Craik        // text has non-whitespace, so draw and blur to create the shadow
610dd8697c095272f19ddad214834a490b00f11a477Chris Craik        // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
611dd8697c095272f19ddad214834a490b00f11a477Chris Craik        // TODO: don't draw pure whitespace in the first place, and avoid needing this check
612e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik        mCurrentFont->render(paint, glyphs, numGlyphs, penX, penY,
613d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik                Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
614dd8697c095272f19ddad214834a490b00f11a477Chris Craik
615cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy        // Unbind any PBO we might have used
61644eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik        Caches::getInstance().pixelBufferState().unbind();
617cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
618dd8697c095272f19ddad214834a490b00f11a477Chris Craik        blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
619dd8697c095272f19ddad214834a490b00f11a477Chris Craik    }
620f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
621f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.width = paddedWidth;
622f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.height = paddedHeight;
623f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.image = dataBuffer;
624f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.penX = penX;
625f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    image.penY = penY;
6262d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy
627f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    return image;
628f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk}
629694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
630828407356dd5c34a3e441604aaf895cbec7c7e66Chris Craikvoid FontRenderer::initRender(const Rect* clip, Rect* bounds, TextDrawFunctor* functor) {
631694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    checkInit();
632694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
6335b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    mDrawn = false;
6345b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    mBounds = bounds;
635257ae3502cfad43df681b1783528d645bdabc63fRomain Guy    mFunctor = functor;
63609147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy    mClip = clip;
637671d6cf460531825a321edb200523d0faa7792c9Romain Guy}
638ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy
639671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid FontRenderer::finishRender() {
640d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    mBounds = nullptr;
641d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    mClip = nullptr;
642694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
643661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    issueDrawCommand();
644671d6cf460531825a321edb200523d0faa7792c9Romain Guy}
645671d6cf460531825a321edb200523d0faa7792c9Romain Guy
646e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craikvoid FontRenderer::precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
64759744b79ec302000802cd56d30a1bf70f0183c80Chris Craik        const SkMatrix& matrix) {
648e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy    Font* font = Font::create(this, paint, matrix);
649e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik    font->precache(paint, glyphs, numGlyphs);
650e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase}
651e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase
652cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guyvoid FontRenderer::endPrecaching() {
653cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    checkTextureUpdate();
654cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy}
655cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
656e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craikbool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
657a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        int numGlyphs, int x, int y, const float* positions,
658a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        Rect* bounds, TextDrawFunctor* functor, bool forceFinish) {
659671d6cf460531825a321edb200523d0faa7792c9Romain Guy    if (!mCurrentFont) {
660671d6cf460531825a321edb200523d0faa7792c9Romain Guy        ALOGE("No font set");
661671d6cf460531825a321edb200523d0faa7792c9Romain Guy        return false;
662671d6cf460531825a321edb200523d0faa7792c9Romain Guy    }
663671d6cf460531825a321edb200523d0faa7792c9Romain Guy
664257ae3502cfad43df681b1783528d645bdabc63fRomain Guy    initRender(clip, bounds, functor);
665e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik    mCurrentFont->render(paint, glyphs, numGlyphs, x, y, positions);
666527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik
667527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    if (forceFinish) {
668527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik        finishRender();
669527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    }
6705b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
6715b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    return mDrawn;
6729777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy}
6739777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
674e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craikbool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
675a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        int numGlyphs, const SkPath* path, float hOffset, float vOffset,
676a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        Rect* bounds, TextDrawFunctor* functor) {
6779777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (!mCurrentFont) {
6789777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        ALOGE("No font set");
6799777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        return false;
6809777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
6819777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
6821e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    initRender(clip, bounds, functor);
683e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik    mCurrentFont->render(paint, glyphs, numGlyphs, path, hOffset, vOffset);
6849777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    finishRender();
6859777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
6869777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    return mDrawn;
687694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
688694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
689e392c81f6b8f9ace0c0a48c9d4df117fda31fd13Derek Sollenbergervoid FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
690e392c81f6b8f9ace0c0a48c9d4df117fda31fd13Derek Sollenberger    uint32_t intRadius = Blur::convertRadiusToInt(radius);
691e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrill#ifdef ANDROID_ENABLE_RENDERSCRIPT
692f3754a84289680782b2c7caac30fda18207a5c23Chris Craik    if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF && radius <= 25.0f) {
693e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrill        uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
694e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrill
695d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik        if (mRs == nullptr) {
696e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrill            mRs = new RSC::RS();
697abe55e92241fd9a19885f7b11db8d3043ab60c61Tim Murray            // a null path is OK because there are no custom kernels used
698abe55e92241fd9a19885f7b11db8d3043ab60c61Tim Murray            // hence nothing gets cached by RS
699abe55e92241fd9a19885f7b11db8d3043ab60c61Tim Murray            if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
700ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua                mRs.clear();
701e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrill                ALOGE("blur RS failed to init");
702ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua            } else {
703ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua                mRsElement = RSC::Element::A_8(mRs);
704ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua                mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
705e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrill            }
706e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrill        }
707d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik        if (mRs != nullptr) {
708ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua            RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
709ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua            RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
710ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua                    RS_ALLOCATION_MIPMAP_NONE,
711ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua                    RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
712ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua                    *image);
713ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua            RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
714ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua                    RS_ALLOCATION_MIPMAP_NONE,
715ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua                    RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
716ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua                    outImage);
717ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua
718ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua            mRsScript->setRadius(radius);
719ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua            mRsScript->setInput(ain);
720ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua            mRsScript->forEach(aout);
721ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua
722ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua            // replace the original image's pointer, avoiding a copy back to the original buffer
723ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua            free(*image);
724ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua            *image = outImage;
725f2d8ccc15d7272b3416f73605c1f31d1d346bd40Chris Craik
726ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua            return;
727ea42e015277687cef168f960252b9d7596ff1160Lu, Shenghua        }
728f2d8ccc15d7272b3416f73605c1f31d1d346bd40Chris Craik    }
729e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrill#endif
730d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy
73151d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik    std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
732a46ca5ec732a884c78d3e98f8b4eb8de03bc23f8huanhuan.x.wang    Blur::generateGaussianWeights(gaussian.get(), radius);
733d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy
73451d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik    std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
73551d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik    Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
73651d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik    Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
73789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk}
73889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
739272a685f17cc4828257e521a6f62b7b17870f75eJohn Reckstatic uint32_t calculateCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
740cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    uint32_t size = 0;
7411e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    for (uint32_t i = 0; i < cacheTextures.size(); i++) {
7421e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        CacheTexture* cacheTexture = cacheTextures[i];
743cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy        if (cacheTexture && cacheTexture->getPixelBuffer()) {
744cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy            size += cacheTexture->getPixelBuffer()->getSize();
745cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy        }
746cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    }
747cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    return size;
748cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy}
749cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
7501e546815bbb736c50679a8aefc25f48561026fc5Victoria Leaseuint32_t FontRenderer::getCacheSize(GLenum format) const {
7511e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    switch (format) {
7521e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        case GL_ALPHA: {
7531e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            return calculateCacheSize(mACacheTextures);
7541e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        }
7551e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        case GL_RGBA: {
7561e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            return calculateCacheSize(mRGBACacheTextures);
7571e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        }
7581e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        default: {
7591e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            return 0;
7601e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        }
7611e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    }
7621e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease}
7631e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease
764694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace uirenderer
765694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace android
766