blob: 6dcd3e1433cee8a88e9b50121c0cf4362e26689d [file] [log] [blame]
Romain Guy694b5192010-07-21 21:33:20 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Chris Craik96a5c4c2015-01-27 15:46:35 -080017#include "FontRenderer.h"
18
19#include "Caches.h"
20#include "Debug.h"
21#include "Extensions.h"
22#include "OpenGLRenderer.h"
23#include "PixelBuffer.h"
24#include "Rect.h"
25#include "renderstate/RenderState.h"
26#include "utils/Blur.h"
27#include "utils/Timing.h"
Romain Guy694b5192010-07-21 21:33:20 -070028
Derek Sollenbergerca79cf62012-08-14 16:44:52 -040029#include <SkGlyph.h>
Romain Guy694b5192010-07-21 21:33:20 -070030#include <SkUtils.h>
31
Romain Guy51769a62010-07-23 00:28:00 -070032#include <cutils/properties.h>
Romain Guye2d345e2010-09-24 18:39:22 -070033
Romain Guy51769a62010-07-23 00:28:00 -070034#include <utils/Log.h>
35
Dan Morrille4d9a012013-03-28 18:10:43 -070036#ifdef ANDROID_ENABLE_RENDERSCRIPT
Romain Guy6e200402013-03-08 11:28:22 -080037#include <RenderScript.h>
Dan Morrille4d9a012013-03-28 18:10:43 -070038#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -080039
Romain Guy694b5192010-07-21 21:33:20 -070040namespace android {
41namespace uirenderer {
42
Chris Craikf2d8ccc2013-02-13 16:14:17 -080043// blur inputs smaller than this constant will bypass renderscript
44#define RS_MIN_INPUT_CUTOFF 10000
45
Romain Guy694b5192010-07-21 21:33:20 -070046///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070047// TextSetupFunctor
48///////////////////////////////////////////////////////////////////////////////
Chris Craik96a5c4c2015-01-27 15:46:35 -080049status_t TextSetupFunctor::setup(GLenum glyphFormat) {
Victoria Lease1e546812013-06-25 14:25:17 -070050
51 renderer->setupDraw();
52 renderer->setupDrawTextGamma(paint);
53 renderer->setupDrawDirtyRegionsDisabled();
54 renderer->setupDrawWithTexture(glyphFormat == GL_ALPHA);
55 switch (glyphFormat) {
56 case GL_ALPHA: {
57 renderer->setupDrawAlpha8Color(paint->getColor(), alpha);
58 break;
59 }
60 case GL_RGBA: {
61 float floatAlpha = alpha / 255.0f;
62 renderer->setupDrawColor(floatAlpha, floatAlpha, floatAlpha, floatAlpha);
63 break;
64 }
65 default: {
66#if DEBUG_FONT_RENDERER
67 ALOGD("TextSetupFunctor: called with unknown glyph format %x", glyphFormat);
68#endif
69 break;
70 }
71 }
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -050072 renderer->setupDrawColorFilter(paint->getColorFilter());
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -040073 renderer->setupDrawShader(paint->getShader());
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -050074 renderer->setupDrawBlending(paint);
Victoria Lease1e546812013-06-25 14:25:17 -070075 renderer->setupDrawProgram();
Chris Craik4063a0e2013-11-15 16:06:56 -080076 renderer->setupDrawModelView(kModelViewMode_Translate, false,
77 0.0f, 0.0f, 0.0f, 0.0f, pureTranslate);
Victoria Lease1e546812013-06-25 14:25:17 -070078 // Calling setupDrawTexture with the name 0 will enable the
79 // uv attributes and increase the texture unit count
80 // texture binding will be performed by the font renderer as
81 // needed
82 renderer->setupDrawTexture(0);
83 renderer->setupDrawPureColorUniforms();
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -050084 renderer->setupDrawColorFilterUniforms(paint->getColorFilter());
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -040085 renderer->setupDrawShaderUniforms(paint->getShader(), pureTranslate);
Victoria Lease1e546812013-06-25 14:25:17 -070086 renderer->setupDrawTextGammaUniforms();
87
88 return NO_ERROR;
89}
90
91///////////////////////////////////////////////////////////////////////////////
Romain Guy694b5192010-07-21 21:33:20 -070092// FontRenderer
93///////////////////////////////////////////////////////////////////////////////
94
Romain Guy514fb182011-01-19 14:38:29 -080095static bool sLogFontRendererCreate = true;
96
Romain Guye3a9b242013-01-08 11:15:30 -080097FontRenderer::FontRenderer() :
98 mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity) {
99
Romain Guyc9855a52011-01-21 21:14:15 -0800100 if (sLogFontRendererCreate) {
101 INIT_LOGD("Creating FontRenderer");
102 }
Romain Guy51769a62010-07-23 00:28:00 -0700103
Chris Craikd41c4d82015-01-05 15:51:13 -0800104 mGammaTable = nullptr;
Romain Guy694b5192010-07-21 21:33:20 -0700105 mInitialized = false;
Romain Guy694b5192010-07-21 21:33:20 -0700106
Chris Craikd41c4d82015-01-05 15:51:13 -0800107 mCurrentCacheTexture = nullptr;
Romain Guy9cccc2b92010-08-07 23:46:15 -0700108
Chet Haase2a47c142011-12-14 15:22:56 -0800109 mLinearFiltering = false;
110
Chet Haaseeb32a492012-08-31 13:54:03 -0700111 mSmallCacheWidth = DEFAULT_TEXT_SMALL_CACHE_WIDTH;
112 mSmallCacheHeight = DEFAULT_TEXT_SMALL_CACHE_HEIGHT;
113 mLargeCacheWidth = DEFAULT_TEXT_LARGE_CACHE_WIDTH;
114 mLargeCacheHeight = DEFAULT_TEXT_LARGE_CACHE_HEIGHT;
Romain Guy51769a62010-07-23 00:28:00 -0700115
116 char property[PROPERTY_VALUE_MAX];
Chris Craikd41c4d82015-01-05 15:51:13 -0800117 if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, nullptr) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800118 mSmallCacheWidth = atoi(property);
Romain Guy51769a62010-07-23 00:28:00 -0700119 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700120
Chris Craikd41c4d82015-01-05 15:51:13 -0800121 if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, nullptr) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800122 mSmallCacheHeight = atoi(property);
Chet Haaseeb32a492012-08-31 13:54:03 -0700123 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700124
Chris Craikd41c4d82015-01-05 15:51:13 -0800125 if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, nullptr) > 0) {
Chet Haaseeb32a492012-08-31 13:54:03 -0700126 mLargeCacheWidth = atoi(property);
127 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700128
Chris Craikd41c4d82015-01-05 15:51:13 -0800129 if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, nullptr) > 0) {
Chet Haaseeb32a492012-08-31 13:54:03 -0700130 mLargeCacheHeight = atoi(property);
131 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700132
133 uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
134 mSmallCacheWidth = mSmallCacheWidth > maxTextureSize ? maxTextureSize : mSmallCacheWidth;
135 mSmallCacheHeight = mSmallCacheHeight > maxTextureSize ? maxTextureSize : mSmallCacheHeight;
136 mLargeCacheWidth = mLargeCacheWidth > maxTextureSize ? maxTextureSize : mLargeCacheWidth;
137 mLargeCacheHeight = mLargeCacheHeight > maxTextureSize ? maxTextureSize : mLargeCacheHeight;
138
Chet Haaseeb32a492012-08-31 13:54:03 -0700139 if (sLogFontRendererCreate) {
140 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
141 mSmallCacheWidth, mSmallCacheHeight,
142 mLargeCacheWidth, mLargeCacheHeight >> 1,
143 mLargeCacheWidth, mLargeCacheHeight >> 1,
144 mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700145 }
Romain Guy514fb182011-01-19 14:38:29 -0800146
147 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700148}
149
Victoria Lease1e546812013-06-25 14:25:17 -0700150void clearCacheTextures(Vector<CacheTexture*>& cacheTextures) {
151 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
152 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700153 }
Victoria Lease1e546812013-06-25 14:25:17 -0700154 cacheTextures.clear();
155}
156
157FontRenderer::~FontRenderer() {
158 clearCacheTextures(mACacheTextures);
159 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700160
Romain Guye3a9b242013-01-08 11:15:30 -0800161 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
162 while (it.next()) {
163 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700164 }
Romain Guye3a9b242013-01-08 11:15:30 -0800165 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700166}
167
168void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700169 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700170
Romain Guye3a9b242013-01-08 11:15:30 -0800171 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
172 while (it.next()) {
173 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700174 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700175
Victoria Lease1e546812013-06-25 14:25:17 -0700176 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
177 mACacheTextures[i]->init();
178 }
179
180 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
181 mRGBACacheTextures[i]->init();
Romain Guy694b5192010-07-21 21:33:20 -0700182 }
183}
184
Victoria Lease1e546812013-06-25 14:25:17 -0700185void FontRenderer::flushLargeCaches(Vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700186 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700187 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
188 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700189 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700190 cacheTexture->init();
Romain Guye3a9b242013-01-08 11:15:30 -0800191 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
192 while (it.next()) {
193 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700194 }
Romain Guy80872462012-09-04 16:42:01 -0700195 cacheTexture->releaseTexture();
Chet Haase9a824562011-12-16 15:44:59 -0800196 }
197 }
Chet Haase9a824562011-12-16 15:44:59 -0800198}
199
Victoria Lease1e546812013-06-25 14:25:17 -0700200void FontRenderer::flushLargeCaches() {
201 flushLargeCaches(mACacheTextures);
202 flushLargeCaches(mRGBACacheTextures);
203}
204
205CacheTexture* FontRenderer::cacheBitmapInTexture(Vector<CacheTexture*>& cacheTextures,
206 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
207 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
208 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
209 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700210 }
211 }
212 // Could not fit glyph into current cache textures
Chris Craikd41c4d82015-01-05 15:51:13 -0800213 return nullptr;
Chet Haase378e9192012-08-15 15:54:54 -0700214}
215
Chet Haase7de0cb12011-12-05 16:35:38 -0800216void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700217 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700218 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800219
220 // If the glyph bitmap is empty let's assum the glyph is valid
221 // so we can avoid doing extra work later on
222 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
223 cachedGlyph->mIsValid = true;
Chris Craikd41c4d82015-01-05 15:51:13 -0800224 cachedGlyph->mCacheTexture = nullptr;
Romain Guya4adcf02013-02-28 12:15:35 -0800225 return;
226 }
227
Chet Haase7de0cb12011-12-05 16:35:38 -0800228 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800229
Victoria Lease1e546812013-06-25 14:25:17 -0700230 // choose an appropriate cache texture list for this glyph format
231 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
Chris Craikd41c4d82015-01-05 15:51:13 -0800232 Vector<CacheTexture*>* cacheTextures = nullptr;
Victoria Lease1e546812013-06-25 14:25:17 -0700233 switch (format) {
234 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700235 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700236 cacheTextures = &mACacheTextures;
237 break;
238 case SkMask::kARGB32_Format:
239 cacheTextures = &mRGBACacheTextures;
240 break;
241 default:
242#if DEBUG_FONT_RENDERER
243 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
244#endif
245 return;
246 }
247
Romain Guy694b5192010-07-21 21:33:20 -0700248 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700249 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700250 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700251 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
252 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800253 return;
Romain Guy694b5192010-07-21 21:33:20 -0700254 }
255
256 // Now copy the bitmap into the cache texture
257 uint32_t startX = 0;
258 uint32_t startY = 0;
259
Victoria Lease1e546812013-06-25 14:25:17 -0700260 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700261
Chet Haase378e9192012-08-15 15:54:54 -0700262 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700263 if (!precaching) {
264 // If the new glyph didn't fit and we are not just trying to precache it,
265 // clear out the cache and try again
266 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700267 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700268 }
Romain Guy694b5192010-07-21 21:33:20 -0700269
Chet Haase378e9192012-08-15 15:54:54 -0700270 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700271 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800272 return;
Romain Guy694b5192010-07-21 21:33:20 -0700273 }
274 }
275
Chet Haase378e9192012-08-15 15:54:54 -0700276 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800277
Romain Guy694b5192010-07-21 21:33:20 -0700278 *retOriginX = startX;
279 *retOriginY = startY;
280
281 uint32_t endX = startX + glyph.fWidth;
282 uint32_t endY = startY + glyph.fHeight;
283
Romain Guy80872462012-09-04 16:42:01 -0700284 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700285
Romain Guycf51a412013-04-08 19:40:31 -0700286 if (!cacheTexture->getPixelBuffer()) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800287 Caches::getInstance().textureState().activateTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800288 // Large-glyph texture memory is allocated only as needed
Romain Guy80872462012-09-04 16:42:01 -0700289 cacheTexture->allocateTexture();
Chet Haase7de0cb12011-12-05 16:35:38 -0800290 }
Romain Guy661a87e2013-03-19 15:24:36 -0700291 if (!cacheTexture->mesh()) {
292 cacheTexture->allocateMesh();
293 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700294
Romain Guycf51a412013-04-08 19:40:31 -0700295 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700296 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
297 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700298
Romain Guyb969a0d2013-02-05 14:38:40 -0800299 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800300 switch (format) {
301 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700302 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
303 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
304 - TEXTURE_BORDER_SIZE;
305 // write leading border line
306 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
307 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800308 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700309 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800310 row = cacheY * cacheWidth;
311 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800312 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
313 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800314 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800315 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800316 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800317 }
318 } else {
Victoria Lease1e546812013-06-25 14:25:17 -0700319 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800320 row = cacheY * cacheWidth;
321 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
322 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
323 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800324 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700325 }
Victoria Lease1e546812013-06-25 14:25:17 -0700326 // write trailing border line
327 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
328 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
329 break;
330 }
331 case SkMask::kARGB32_Format: {
332 // prep data lengths
333 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
334 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
335 size_t rowSize = formatSize * glyph.fWidth;
336 // prep advances
337 size_t dstStride = formatSize * cacheWidth;
338 // prep indices
339 // - we actually start one row early, and then increment before first copy
340 uint8_t* src = &bitmapBuffer[0 - srcStride];
341 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
342 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
343 uint8_t* dstL = dst - borderSize;
344 uint8_t* dstR = dst + rowSize;
345 // write leading border line
346 memset(dstL, 0, rowSize + 2 * borderSize);
347 // write glyph data
348 while (dst < dstEnd) {
349 memset(dstL += dstStride, 0, borderSize); // leading border column
350 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
351 memset(dstR += dstStride, 0, borderSize); // trailing border column
352 }
353 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700354 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800355 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700356 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800357 case SkMask::kBW_Format: {
Andreas Gampe1e196742014-11-10 15:23:43 -0800358 uint32_t cacheX = 0, cacheY = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700359 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
360 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800361 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700362 // write leading border line
363 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
364 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800365 for (cacheY = startY; cacheY < endY; cacheY++) {
366 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700367 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800368 uint8_t* buffer = bitmapBuffer;
369
Romain Guy0b58a3d2013-03-05 12:16:27 -0800370 row = cacheY * cacheWidth;
371 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800372 while (--rowBytes >= 0) {
373 uint8_t b = *buffer++;
374 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
375 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
376 }
377 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800378 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800379
Victoria Lease1e546812013-06-25 14:25:17 -0700380 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700381 }
Victoria Lease1e546812013-06-25 14:25:17 -0700382 // write trailing border line
383 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
384 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800385 break;
Romain Guy694b5192010-07-21 21:33:20 -0700386 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800387 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700388 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800389 break;
Romain Guy694b5192010-07-21 21:33:20 -0700390 }
Romain Guy97771732012-02-28 18:17:02 -0800391
Chet Haase7de0cb12011-12-05 16:35:38 -0800392 cachedGlyph->mIsValid = true;
Romain Guy694b5192010-07-21 21:33:20 -0700393}
394
Victoria Lease1e546812013-06-25 14:25:17 -0700395CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
396 bool allocate) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800397 CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700398
Chet Haase2a47c142011-12-14 15:22:56 -0800399 if (allocate) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800400 Caches::getInstance().textureState().activateTexture(0);
Romain Guy80872462012-09-04 16:42:01 -0700401 cacheTexture->allocateTexture();
Romain Guy661a87e2013-03-19 15:24:36 -0700402 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800403 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700404
Chet Haase2a47c142011-12-14 15:22:56 -0800405 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800406}
407
408void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700409 clearCacheTextures(mACacheTextures);
410 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700411
Chet Haase7de0cb12011-12-05 16:35:38 -0800412 mUploadTexture = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700413 mACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
414 GL_ALPHA, true));
415 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
416 GL_ALPHA, false));
417 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
418 GL_ALPHA, false));
419 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
420 GL_ALPHA, false));
421 mRGBACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
422 GL_RGBA, false));
423 mRGBACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
424 GL_RGBA, false));
425 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700426}
427
Romain Guy694b5192010-07-21 21:33:20 -0700428// We don't want to allocate anything unless we actually draw text
429void FontRenderer::checkInit() {
430 if (mInitialized) {
431 return;
432 }
433
434 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700435
436 mInitialized = true;
437}
438
Victoria Lease1e546812013-06-25 14:25:17 -0700439void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheTextures,
440 bool& resetPixelStore, GLuint& lastTextureId) {
441 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
442 CacheTexture* cacheTexture = cacheTextures[i];
443 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
444 if (cacheTexture->getTextureId() != lastTextureId) {
445 lastTextureId = cacheTexture->getTextureId();
Chris Craik44eb2c02015-01-29 09:45:09 -0800446 caches.textureState().activateTexture(0);
447 caches.textureState().bindTexture(lastTextureId);
Victoria Lease1e546812013-06-25 14:25:17 -0700448 }
449
450 if (cacheTexture->upload()) {
451 resetPixelStore = true;
452 }
453 }
454 }
455}
456
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700457void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900458 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700459 return;
Romain Guy694b5192010-07-21 21:33:20 -0700460 }
461
Romain Guy2d4fd362011-12-13 22:00:19 -0800462 Caches& caches = Caches::getInstance();
463 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700464
Romain Guycf51a412013-04-08 19:40:31 -0700465 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700466 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
467
Chet Haase378e9192012-08-15 15:54:54 -0700468 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700469 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
470 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700471
Romain Guycf51a412013-04-08 19:40:31 -0700472 // Unbind any PBO we might have used to update textures
Chris Craik44eb2c02015-01-29 09:45:09 -0800473 caches.pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700474
Romain Guy09087642013-04-04 12:27:54 -0700475 // Reset to default unpack row length to avoid affecting texture
476 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700477 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700478 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
479 }
480
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700481 mUploadTexture = false;
482}
483
Victoria Lease1e546812013-06-25 14:25:17 -0700484void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800485 if (!mFunctor) return;
486
487 Caches& caches = mFunctor->renderer->getCaches();
488 RenderState& renderState = mFunctor->renderer->renderState();
489
Romain Guy661a87e2013-03-19 15:24:36 -0700490 bool first = true;
Chris Craik96a5c4c2015-01-27 15:46:35 -0800491 bool forceRebind = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700492 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
493 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700494 if (texture->canDraw()) {
495 if (first) {
Victoria Lease1e546812013-06-25 14:25:17 -0700496 if (mFunctor) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800497 mFunctor->setup(texture->getFormat());
Victoria Lease1e546812013-06-25 14:25:17 -0700498 }
Romain Guy257ae352013-03-20 16:31:12 -0700499
Romain Guy661a87e2013-03-19 15:24:36 -0700500 checkTextureUpdate();
Chris Craik96a5c4c2015-01-27 15:46:35 -0800501 renderState.meshState().bindQuadIndicesBuffer();
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900502
Romain Guy661a87e2013-03-19 15:24:36 -0700503 if (!mDrawn) {
504 // If returns true, a VBO was bound and we must
505 // rebind our vertex attrib pointers even if
506 // they have the same values as the current pointers
Chris Craik96a5c4c2015-01-27 15:46:35 -0800507 forceRebind = renderState.meshState().unbindMeshBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700508 }
509
Chris Craik44eb2c02015-01-29 09:45:09 -0800510 caches.textureState().activateTexture(0);
Romain Guy661a87e2013-03-19 15:24:36 -0700511 first = false;
512 }
513
Chris Craik44eb2c02015-01-29 09:45:09 -0800514 caches.textureState().bindTexture(texture->getTextureId());
Romain Guy661a87e2013-03-19 15:24:36 -0700515 texture->setLinearFiltering(mLinearFiltering, false);
516
517 TextureVertex* mesh = texture->mesh();
Chris Craik96a5c4c2015-01-27 15:46:35 -0800518 MeshState& meshState = renderState.meshState();
519 Program* program = caches.currentProgram;
520 meshState.bindPositionVertexPointer(program, forceRebind, &mesh[0].x);
521 meshState.bindTexCoordsVertexPointer(program, forceRebind, &mesh[0].u);
Romain Guy661a87e2013-03-19 15:24:36 -0700522
523 glDrawElements(GL_TRIANGLES, texture->meshElementCount(),
524 GL_UNSIGNED_SHORT, texture->indices());
525
526 texture->resetMesh();
Chris Craik96a5c4c2015-01-27 15:46:35 -0800527 forceRebind = false;
Romain Guy115096f2013-03-19 11:32:41 -0700528 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900529 }
Victoria Lease1e546812013-06-25 14:25:17 -0700530}
531
532void FontRenderer::issueDrawCommand() {
533 issueDrawCommand(mACacheTextures);
534 issueDrawCommand(mRGBACacheTextures);
Romain Guy5b3b3522010-10-27 18:57:51 -0700535
536 mDrawn = true;
Romain Guy694b5192010-07-21 21:33:20 -0700537}
538
Romain Guy97771732012-02-28 18:17:02 -0800539void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
540 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800541 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800542 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800543 // Now use the new texture id
544 mCurrentCacheTexture = texture;
545 }
Romain Guy09147fb2010-07-22 13:08:20 -0700546
Romain Guy661a87e2013-03-19 15:24:36 -0700547 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
548 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800549}
550
551void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
552 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
553 float x4, float y4, float u4, float v4, CacheTexture* texture) {
554
555 if (mClip &&
556 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
557 return;
558 }
559
560 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
Romain Guy694b5192010-07-21 21:33:20 -0700561
Romain Guy5b3b3522010-10-27 18:57:51 -0700562 if (mBounds) {
563 mBounds->left = fmin(mBounds->left, x1);
564 mBounds->top = fmin(mBounds->top, y3);
565 mBounds->right = fmax(mBounds->right, x3);
566 mBounds->bottom = fmax(mBounds->bottom, y1);
567 }
568
Romain Guy661a87e2013-03-19 15:24:36 -0700569 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700570 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700571 }
572}
573
Romain Guy97771732012-02-28 18:17:02 -0800574void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
575 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
576 float x4, float y4, float u4, float v4, CacheTexture* texture) {
577
578 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
579
580 if (mBounds) {
581 mBounds->left = fmin(mBounds->left, fmin(x1, fmin(x2, fmin(x3, x4))));
582 mBounds->top = fmin(mBounds->top, fmin(y1, fmin(y2, fmin(y3, y4))));
583 mBounds->right = fmax(mBounds->right, fmax(x1, fmax(x2, fmax(x3, x4))));
584 mBounds->bottom = fmax(mBounds->bottom, fmax(y1, fmax(y2, fmax(y3, y4))));
585 }
586
Romain Guy661a87e2013-03-19 15:24:36 -0700587 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800588 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800589 }
590}
591
Chris Craik59744b72014-07-01 17:56:52 -0700592void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800593 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700594}
Romain Guy7975fb62010-10-01 16:36:14 -0700595
Chris Craikd218a922014-01-02 17:13:34 -0800596FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const char *text,
Derek Sollenbergere392c812014-05-21 11:25:22 -0400597 uint32_t startIndex, uint32_t len, int numGlyphs, float radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700598 checkInit();
599
Romain Guycf51a412013-04-08 19:40:31 -0700600 DropShadow image;
601 image.width = 0;
602 image.height = 0;
Chris Craikd41c4d82015-01-05 15:51:13 -0800603 image.image = nullptr;
Romain Guycf51a412013-04-08 19:40:31 -0700604 image.penX = 0;
605 image.penY = 0;
606
Romain Guy1e45aae2010-08-13 19:39:53 -0700607 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700608 return image;
609 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700610
Romain Guy2d4fd362011-12-13 22:00:19 -0800611 mDrawn = false;
Chris Craikd41c4d82015-01-05 15:51:13 -0800612 mClip = nullptr;
613 mBounds = nullptr;
Romain Guyff98fa52011-11-28 09:35:09 -0800614
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700615 Rect bounds;
Raph Levien416a8472012-07-19 22:48:17 -0700616 mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800617
Derek Sollenbergere392c812014-05-21 11:25:22 -0400618 uint32_t intRadius = Blur::convertRadiusToInt(radius);
619 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
620 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
Romain Guyff98fa52011-11-28 09:35:09 -0800621
Romain Guycf51a412013-04-08 19:40:31 -0700622 uint32_t maxSize = Caches::getInstance().maxTextureSize;
623 if (paddedWidth > maxSize || paddedHeight > maxSize) {
624 return image;
625 }
626
Dan Morrille4d9a012013-03-28 18:10:43 -0700627#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800628 // Align buffers for renderscript usage
629 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
630 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700631 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800632 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800633 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700634#else
635 int size = paddedWidth * paddedHeight;
636 uint8_t* dataBuffer = (uint8_t*) malloc(size);
637#endif
638
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800639 memset(dataBuffer, 0, size);
640
Derek Sollenbergere392c812014-05-21 11:25:22 -0400641 int penX = intRadius - bounds.left;
642 int penY = intRadius - bounds.bottom;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700643
Chris Craikdd8697c2013-02-22 10:41:36 -0800644 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
645 // text has non-whitespace, so draw and blur to create the shadow
646 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
647 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
648 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
Chris Craikd41c4d82015-01-05 15:51:13 -0800649 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
Chris Craikdd8697c2013-02-22 10:41:36 -0800650
Romain Guycf51a412013-04-08 19:40:31 -0700651 // Unbind any PBO we might have used
Chris Craik44eb2c02015-01-29 09:45:09 -0800652 Caches::getInstance().pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700653
Chris Craikdd8697c2013-02-22 10:41:36 -0800654 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
655 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700656
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700657 image.width = paddedWidth;
658 image.height = paddedHeight;
659 image.image = dataBuffer;
660 image.penX = penX;
661 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800662
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700663 return image;
664}
Romain Guy694b5192010-07-21 21:33:20 -0700665
Chris Craik96a5c4c2015-01-27 15:46:35 -0800666void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextSetupFunctor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700667 checkInit();
668
Romain Guy5b3b3522010-10-27 18:57:51 -0700669 mDrawn = false;
670 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700671 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700672 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800673}
Romain Guyff98fa52011-11-28 09:35:09 -0800674
Romain Guy671d6cf2012-01-18 12:39:17 -0800675void FontRenderer::finishRender() {
Chris Craikd41c4d82015-01-05 15:51:13 -0800676 mBounds = nullptr;
677 mClip = nullptr;
Romain Guy694b5192010-07-21 21:33:20 -0700678
Romain Guy661a87e2013-03-19 15:24:36 -0700679 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800680}
681
Chris Craikd218a922014-01-02 17:13:34 -0800682void FontRenderer::precache(const SkPaint* paint, const char* text, int numGlyphs,
Chris Craik59744b72014-07-01 17:56:52 -0700683 const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800684 Font* font = Font::create(this, paint, matrix);
Chet Haasee816bae2012-08-09 13:39:02 -0700685 font->precache(paint, text, numGlyphs);
686}
687
Romain Guycf51a412013-04-08 19:40:31 -0700688void FontRenderer::endPrecaching() {
689 checkTextureUpdate();
690}
691
Chris Craikd218a922014-01-02 17:13:34 -0800692bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
Romain Guy671d6cf2012-01-18 12:39:17 -0800693 uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
Chris Craik96a5c4c2015-01-27 15:46:35 -0800694 const float* positions, Rect* bounds, TextSetupFunctor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800695 if (!mCurrentFont) {
696 ALOGE("No font set");
697 return false;
698 }
699
Romain Guy257ae352013-03-20 16:31:12 -0700700 initRender(clip, bounds, functor);
Romain Guy671d6cf2012-01-18 12:39:17 -0800701 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800702
703 if (forceFinish) {
704 finishRender();
705 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700706
707 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700708}
709
Chris Craikd218a922014-01-02 17:13:34 -0800710bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
711 uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
Chris Craik96a5c4c2015-01-27 15:46:35 -0800712 float hOffset, float vOffset, Rect* bounds, TextSetupFunctor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800713 if (!mCurrentFont) {
714 ALOGE("No font set");
715 return false;
716 }
717
Victoria Lease1e546812013-06-25 14:25:17 -0700718 initRender(clip, bounds, functor);
Romain Guy97771732012-02-28 18:17:02 -0800719 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
720 finishRender();
721
722 return mDrawn;
723}
724
Romain Guy9b1204b2012-09-04 15:22:57 -0700725void FontRenderer::removeFont(const Font* font) {
Romain Guye3a9b242013-01-08 11:15:30 -0800726 mActiveFonts.remove(font->getDescription());
Romain Guy9b1204b2012-09-04 15:22:57 -0700727
728 if (mCurrentFont == font) {
Chris Craikd41c4d82015-01-05 15:51:13 -0800729 mCurrentFont = nullptr;
Romain Guy9b1204b2012-09-04 15:22:57 -0700730 }
731}
732
Derek Sollenbergere392c812014-05-21 11:25:22 -0400733void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
734 uint32_t intRadius = Blur::convertRadiusToInt(radius);
Dan Morrille4d9a012013-03-28 18:10:43 -0700735#ifdef ANDROID_ENABLE_RENDERSCRIPT
Derek Sollenbergere392c812014-05-21 11:25:22 -0400736 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700737 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700738
Chris Craikd41c4d82015-01-05 15:51:13 -0800739 if (mRs == nullptr) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700740 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800741 // a null path is OK because there are no custom kernels used
742 // hence nothing gets cached by RS
743 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800744 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700745 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800746 } else {
747 mRsElement = RSC::Element::A_8(mRs);
748 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700749 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800750 }
Chris Craikd41c4d82015-01-05 15:51:13 -0800751 if (mRs != nullptr) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800752 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
753 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
754 RS_ALLOCATION_MIPMAP_NONE,
755 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
756 *image);
757 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
758 RS_ALLOCATION_MIPMAP_NONE,
759 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
760 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800761
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800762 mRsScript->setRadius(radius);
763 mRsScript->setInput(ain);
764 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700765
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800766 // replace the original image's pointer, avoiding a copy back to the original buffer
767 free(*image);
768 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700769
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800770 return;
771 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800772 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700773#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800774
Chris Craik51d6a3d2014-12-22 17:16:56 -0800775 std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
776 Blur::generateGaussianWeights(gaussian.get(), intRadius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800777
Chris Craik51d6a3d2014-12-22 17:16:56 -0800778 std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
779 Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
780 Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700781}
782
Victoria Lease1e546812013-06-25 14:25:17 -0700783static uint32_t calculateCacheSize(const Vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700784 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700785 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
786 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700787 if (cacheTexture && cacheTexture->getPixelBuffer()) {
788 size += cacheTexture->getPixelBuffer()->getSize();
789 }
790 }
791 return size;
792}
793
Victoria Lease1e546812013-06-25 14:25:17 -0700794uint32_t FontRenderer::getCacheSize(GLenum format) const {
795 switch (format) {
796 case GL_ALPHA: {
797 return calculateCacheSize(mACacheTextures);
798 }
799 case GL_RGBA: {
800 return calculateCacheSize(mRGBACacheTextures);
801 }
802 default: {
803 return 0;
804 }
805 }
806}
807
Romain Guy694b5192010-07-21 21:33:20 -0700808}; // namespace uirenderer
809}; // namespace android