blob: c1b50c108c2f199d644feae1cb3c39bca7210ba2 [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
17#define LOG_TAG "OpenGLRenderer"
18
Derek Sollenbergerca79cf62012-08-14 16:44:52 -040019#include <SkGlyph.h>
Romain Guy694b5192010-07-21 21:33:20 -070020#include <SkUtils.h>
21
Romain Guy51769a62010-07-23 00:28:00 -070022#include <cutils/properties.h>
Romain Guye2d345e2010-09-24 18:39:22 -070023
Romain Guy51769a62010-07-23 00:28:00 -070024#include <utils/Log.h>
25
Dan Morrille4d9a012013-03-28 18:10:43 -070026#ifdef ANDROID_ENABLE_RENDERSCRIPT
Romain Guy6e200402013-03-08 11:28:22 -080027#include <RenderScript.h>
Dan Morrille4d9a012013-03-28 18:10:43 -070028#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -080029
Romain Guy6e200402013-03-08 11:28:22 -080030#include "utils/Blur.h"
Chris Craikf2d8ccc2013-02-13 16:14:17 -080031#include "utils/Timing.h"
Romain Guy6e200402013-03-08 11:28:22 -080032
Romain Guy15bc6432011-12-13 13:11:32 -080033#include "Caches.h"
Romain Guyc9855a52011-01-21 21:14:15 -080034#include "Debug.h"
Romain Guy09087642013-04-04 12:27:54 -070035#include "Extensions.h"
Romain Guy51769a62010-07-23 00:28:00 -070036#include "FontRenderer.h"
Victoria Lease1e546812013-06-25 14:25:17 -070037#include "OpenGLRenderer.h"
Romain Guycf51a412013-04-08 19:40:31 -070038#include "PixelBuffer.h"
Romain Guy9f5dab32012-09-04 12:55:44 -070039#include "Rect.h"
Romain Guy51769a62010-07-23 00:28:00 -070040
Romain Guy694b5192010-07-21 21:33:20 -070041namespace android {
42namespace uirenderer {
43
Chris Craikf2d8ccc2013-02-13 16:14:17 -080044// blur inputs smaller than this constant will bypass renderscript
45#define RS_MIN_INPUT_CUTOFF 10000
46
Romain Guy694b5192010-07-21 21:33:20 -070047///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070048// TextSetupFunctor
49///////////////////////////////////////////////////////////////////////////////
John Reck8b59a522014-11-22 00:10:02 +000050status_t TextSetupFunctor::operator ()(int what, void* data) {
Victoria Lease1e546812013-06-25 14:25:17 -070051 Data* typedData = reinterpret_cast<Data*>(data);
52 GLenum glyphFormat = typedData ? typedData->glyphFormat : GL_ALPHA;
53
54 renderer->setupDraw();
55 renderer->setupDrawTextGamma(paint);
56 renderer->setupDrawDirtyRegionsDisabled();
57 renderer->setupDrawWithTexture(glyphFormat == GL_ALPHA);
58 switch (glyphFormat) {
59 case GL_ALPHA: {
60 renderer->setupDrawAlpha8Color(paint->getColor(), alpha);
61 break;
62 }
63 case GL_RGBA: {
64 float floatAlpha = alpha / 255.0f;
65 renderer->setupDrawColor(floatAlpha, floatAlpha, floatAlpha, floatAlpha);
66 break;
67 }
68 default: {
69#if DEBUG_FONT_RENDERER
70 ALOGD("TextSetupFunctor: called with unknown glyph format %x", glyphFormat);
71#endif
72 break;
73 }
74 }
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -050075 renderer->setupDrawColorFilter(paint->getColorFilter());
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -040076 renderer->setupDrawShader(paint->getShader());
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -050077 renderer->setupDrawBlending(paint);
Victoria Lease1e546812013-06-25 14:25:17 -070078 renderer->setupDrawProgram();
Chris Craik4063a0e2013-11-15 16:06:56 -080079 renderer->setupDrawModelView(kModelViewMode_Translate, false,
80 0.0f, 0.0f, 0.0f, 0.0f, pureTranslate);
Victoria Lease1e546812013-06-25 14:25:17 -070081 // Calling setupDrawTexture with the name 0 will enable the
82 // uv attributes and increase the texture unit count
83 // texture binding will be performed by the font renderer as
84 // needed
85 renderer->setupDrawTexture(0);
86 renderer->setupDrawPureColorUniforms();
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -050087 renderer->setupDrawColorFilterUniforms(paint->getColorFilter());
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -040088 renderer->setupDrawShaderUniforms(paint->getShader(), pureTranslate);
Victoria Lease1e546812013-06-25 14:25:17 -070089 renderer->setupDrawTextGammaUniforms();
90
91 return NO_ERROR;
92}
93
94///////////////////////////////////////////////////////////////////////////////
Romain Guy694b5192010-07-21 21:33:20 -070095// FontRenderer
96///////////////////////////////////////////////////////////////////////////////
97
Romain Guy514fb182011-01-19 14:38:29 -080098static bool sLogFontRendererCreate = true;
99
Romain Guye3a9b242013-01-08 11:15:30 -0800100FontRenderer::FontRenderer() :
101 mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity) {
102
Romain Guyc9855a52011-01-21 21:14:15 -0800103 if (sLogFontRendererCreate) {
104 INIT_LOGD("Creating FontRenderer");
105 }
Romain Guy51769a62010-07-23 00:28:00 -0700106
Romain Guyb45c0c92010-08-26 20:35:23 -0700107 mGammaTable = NULL;
Romain Guy694b5192010-07-21 21:33:20 -0700108 mInitialized = false;
Romain Guy694b5192010-07-21 21:33:20 -0700109
Chet Haase7de0cb12011-12-05 16:35:38 -0800110 mCurrentCacheTexture = NULL;
Romain Guy9cccc2b92010-08-07 23:46:15 -0700111
Chet Haase2a47c142011-12-14 15:22:56 -0800112 mLinearFiltering = false;
113
Chet Haaseeb32a492012-08-31 13:54:03 -0700114 mSmallCacheWidth = DEFAULT_TEXT_SMALL_CACHE_WIDTH;
115 mSmallCacheHeight = DEFAULT_TEXT_SMALL_CACHE_HEIGHT;
116 mLargeCacheWidth = DEFAULT_TEXT_LARGE_CACHE_WIDTH;
117 mLargeCacheHeight = DEFAULT_TEXT_LARGE_CACHE_HEIGHT;
Romain Guy51769a62010-07-23 00:28:00 -0700118
119 char property[PROPERTY_VALUE_MAX];
Chet Haaseeb32a492012-08-31 13:54:03 -0700120 if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, NULL) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800121 mSmallCacheWidth = atoi(property);
Romain Guy51769a62010-07-23 00:28:00 -0700122 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700123
Chet Haaseeb32a492012-08-31 13:54:03 -0700124 if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, NULL) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800125 mSmallCacheHeight = atoi(property);
Chet Haaseeb32a492012-08-31 13:54:03 -0700126 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700127
Chet Haaseeb32a492012-08-31 13:54:03 -0700128 if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, NULL) > 0) {
129 mLargeCacheWidth = atoi(property);
130 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700131
Chet Haaseeb32a492012-08-31 13:54:03 -0700132 if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, NULL) > 0) {
133 mLargeCacheHeight = atoi(property);
134 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700135
136 uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
137 mSmallCacheWidth = mSmallCacheWidth > maxTextureSize ? maxTextureSize : mSmallCacheWidth;
138 mSmallCacheHeight = mSmallCacheHeight > maxTextureSize ? maxTextureSize : mSmallCacheHeight;
139 mLargeCacheWidth = mLargeCacheWidth > maxTextureSize ? maxTextureSize : mLargeCacheWidth;
140 mLargeCacheHeight = mLargeCacheHeight > maxTextureSize ? maxTextureSize : mLargeCacheHeight;
141
Chet Haaseeb32a492012-08-31 13:54:03 -0700142 if (sLogFontRendererCreate) {
143 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
144 mSmallCacheWidth, mSmallCacheHeight,
145 mLargeCacheWidth, mLargeCacheHeight >> 1,
146 mLargeCacheWidth, mLargeCacheHeight >> 1,
147 mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700148 }
Romain Guy514fb182011-01-19 14:38:29 -0800149
150 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700151}
152
Victoria Lease1e546812013-06-25 14:25:17 -0700153void clearCacheTextures(Vector<CacheTexture*>& cacheTextures) {
154 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
155 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700156 }
Victoria Lease1e546812013-06-25 14:25:17 -0700157 cacheTextures.clear();
158}
159
160FontRenderer::~FontRenderer() {
161 clearCacheTextures(mACacheTextures);
162 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700163
Romain Guye3a9b242013-01-08 11:15:30 -0800164 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
165 while (it.next()) {
166 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700167 }
Romain Guye3a9b242013-01-08 11:15:30 -0800168 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700169}
170
171void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700172 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700173
Romain Guye3a9b242013-01-08 11:15:30 -0800174 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
175 while (it.next()) {
176 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700177 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700178
Victoria Lease1e546812013-06-25 14:25:17 -0700179 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
180 mACacheTextures[i]->init();
181 }
182
183 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
184 mRGBACacheTextures[i]->init();
Romain Guy694b5192010-07-21 21:33:20 -0700185 }
chaochen1f61b192014-08-28 18:45:27 -0700186
187 mDrawn = false;
Romain Guy694b5192010-07-21 21:33:20 -0700188}
189
Victoria Lease1e546812013-06-25 14:25:17 -0700190void FontRenderer::flushLargeCaches(Vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700191 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700192 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
193 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700194 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700195 cacheTexture->init();
Romain Guye3a9b242013-01-08 11:15:30 -0800196 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
197 while (it.next()) {
198 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700199 }
Romain Guy80872462012-09-04 16:42:01 -0700200 cacheTexture->releaseTexture();
Chet Haase9a824562011-12-16 15:44:59 -0800201 }
202 }
Chet Haase9a824562011-12-16 15:44:59 -0800203}
204
Victoria Lease1e546812013-06-25 14:25:17 -0700205void FontRenderer::flushLargeCaches() {
206 flushLargeCaches(mACacheTextures);
207 flushLargeCaches(mRGBACacheTextures);
208}
209
210CacheTexture* FontRenderer::cacheBitmapInTexture(Vector<CacheTexture*>& cacheTextures,
211 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
212 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
213 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
214 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700215 }
216 }
217 // Could not fit glyph into current cache textures
218 return NULL;
219}
220
Chet Haase7de0cb12011-12-05 16:35:38 -0800221void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700222 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700223 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800224
225 // If the glyph bitmap is empty let's assum the glyph is valid
226 // so we can avoid doing extra work later on
227 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
228 cachedGlyph->mIsValid = true;
229 cachedGlyph->mCacheTexture = NULL;
230 return;
231 }
232
Chet Haase7de0cb12011-12-05 16:35:38 -0800233 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800234
Victoria Lease1e546812013-06-25 14:25:17 -0700235 // choose an appropriate cache texture list for this glyph format
236 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
237 Vector<CacheTexture*>* cacheTextures = NULL;
238 switch (format) {
239 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700240 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700241 cacheTextures = &mACacheTextures;
242 break;
243 case SkMask::kARGB32_Format:
244 cacheTextures = &mRGBACacheTextures;
245 break;
246 default:
247#if DEBUG_FONT_RENDERER
248 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
249#endif
250 return;
251 }
252
Romain Guy694b5192010-07-21 21:33:20 -0700253 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700254 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700255 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700256 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
257 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800258 return;
Romain Guy694b5192010-07-21 21:33:20 -0700259 }
260
261 // Now copy the bitmap into the cache texture
262 uint32_t startX = 0;
263 uint32_t startY = 0;
264
Victoria Lease1e546812013-06-25 14:25:17 -0700265 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700266
Chet Haase378e9192012-08-15 15:54:54 -0700267 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700268 if (!precaching) {
269 // If the new glyph didn't fit and we are not just trying to precache it,
270 // clear out the cache and try again
271 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700272 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700273 }
Romain Guy694b5192010-07-21 21:33:20 -0700274
Chet Haase378e9192012-08-15 15:54:54 -0700275 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700276 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800277 return;
Romain Guy694b5192010-07-21 21:33:20 -0700278 }
279 }
280
Chet Haase378e9192012-08-15 15:54:54 -0700281 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800282
Romain Guy694b5192010-07-21 21:33:20 -0700283 *retOriginX = startX;
284 *retOriginY = startY;
285
286 uint32_t endX = startX + glyph.fWidth;
287 uint32_t endY = startY + glyph.fHeight;
288
Romain Guy80872462012-09-04 16:42:01 -0700289 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700290
Romain Guycf51a412013-04-08 19:40:31 -0700291 if (!cacheTexture->getPixelBuffer()) {
Romain Guy80872462012-09-04 16:42:01 -0700292 Caches::getInstance().activeTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800293 // Large-glyph texture memory is allocated only as needed
Romain Guy80872462012-09-04 16:42:01 -0700294 cacheTexture->allocateTexture();
Chet Haase7de0cb12011-12-05 16:35:38 -0800295 }
Romain Guy661a87e2013-03-19 15:24:36 -0700296 if (!cacheTexture->mesh()) {
297 cacheTexture->allocateMesh();
298 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700299
Romain Guycf51a412013-04-08 19:40:31 -0700300 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700301 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
302 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700303
Romain Guyb969a0d2013-02-05 14:38:40 -0800304 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800305 switch (format) {
306 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700307 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
308 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
309 - TEXTURE_BORDER_SIZE;
310 // write leading border line
311 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
312 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800313 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700314 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800315 row = cacheY * cacheWidth;
316 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800317 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
318 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800319 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800320 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800321 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800322 }
323 } else {
Victoria Lease1e546812013-06-25 14:25:17 -0700324 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800325 row = cacheY * cacheWidth;
326 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
327 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
328 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800329 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700330 }
Victoria Lease1e546812013-06-25 14:25:17 -0700331 // write trailing border line
332 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
333 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
334 break;
335 }
336 case SkMask::kARGB32_Format: {
337 // prep data lengths
338 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
339 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
340 size_t rowSize = formatSize * glyph.fWidth;
341 // prep advances
342 size_t dstStride = formatSize * cacheWidth;
343 // prep indices
344 // - we actually start one row early, and then increment before first copy
345 uint8_t* src = &bitmapBuffer[0 - srcStride];
346 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
347 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
348 uint8_t* dstL = dst - borderSize;
349 uint8_t* dstR = dst + rowSize;
350 // write leading border line
351 memset(dstL, 0, rowSize + 2 * borderSize);
352 // write glyph data
353 while (dst < dstEnd) {
354 memset(dstL += dstStride, 0, borderSize); // leading border column
355 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
356 memset(dstR += dstStride, 0, borderSize); // trailing border column
357 }
358 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700359 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800360 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700361 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800362 case SkMask::kBW_Format: {
Andreas Gampe1e196742014-11-10 15:23:43 -0800363 uint32_t cacheX = 0, cacheY = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700364 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
365 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800366 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700367 // write leading border line
368 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
369 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800370 for (cacheY = startY; cacheY < endY; cacheY++) {
371 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700372 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800373 uint8_t* buffer = bitmapBuffer;
374
Romain Guy0b58a3d2013-03-05 12:16:27 -0800375 row = cacheY * cacheWidth;
376 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800377 while (--rowBytes >= 0) {
378 uint8_t b = *buffer++;
379 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
380 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
381 }
382 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800383 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800384
Victoria Lease1e546812013-06-25 14:25:17 -0700385 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700386 }
Victoria Lease1e546812013-06-25 14:25:17 -0700387 // write trailing border line
388 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
389 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800390 break;
Romain Guy694b5192010-07-21 21:33:20 -0700391 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800392 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700393 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800394 break;
Romain Guy694b5192010-07-21 21:33:20 -0700395 }
Romain Guy97771732012-02-28 18:17:02 -0800396
Chet Haase7de0cb12011-12-05 16:35:38 -0800397 cachedGlyph->mIsValid = true;
Romain Guy694b5192010-07-21 21:33:20 -0700398}
399
Victoria Lease1e546812013-06-25 14:25:17 -0700400CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
401 bool allocate) {
402 CacheTexture* cacheTexture = new CacheTexture(width, height, format, gMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700403
Chet Haase2a47c142011-12-14 15:22:56 -0800404 if (allocate) {
Romain Guy80872462012-09-04 16:42:01 -0700405 Caches::getInstance().activeTexture(0);
406 cacheTexture->allocateTexture();
Romain Guy661a87e2013-03-19 15:24:36 -0700407 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800408 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700409
Chet Haase2a47c142011-12-14 15:22:56 -0800410 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800411}
412
413void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700414 clearCacheTextures(mACacheTextures);
415 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700416
Chet Haase7de0cb12011-12-05 16:35:38 -0800417 mUploadTexture = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700418 mACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
419 GL_ALPHA, true));
420 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
421 GL_ALPHA, false));
422 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
423 GL_ALPHA, false));
424 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
425 GL_ALPHA, false));
426 mRGBACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
427 GL_RGBA, false));
428 mRGBACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
429 GL_RGBA, false));
430 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700431}
432
Romain Guy694b5192010-07-21 21:33:20 -0700433// We don't want to allocate anything unless we actually draw text
434void FontRenderer::checkInit() {
435 if (mInitialized) {
436 return;
437 }
438
439 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700440
441 mInitialized = true;
442}
443
Victoria Lease1e546812013-06-25 14:25:17 -0700444void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheTextures,
445 bool& resetPixelStore, GLuint& lastTextureId) {
446 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
447 CacheTexture* cacheTexture = cacheTextures[i];
448 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
449 if (cacheTexture->getTextureId() != lastTextureId) {
450 lastTextureId = cacheTexture->getTextureId();
451 caches.activeTexture(0);
452 caches.bindTexture(lastTextureId);
453 }
454
455 if (cacheTexture->upload()) {
456 resetPixelStore = true;
457 }
458 }
459 }
460}
461
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700462void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900463 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700464 return;
Romain Guy694b5192010-07-21 21:33:20 -0700465 }
466
Romain Guy2d4fd362011-12-13 22:00:19 -0800467 Caches& caches = Caches::getInstance();
468 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700469
Romain Guycf51a412013-04-08 19:40:31 -0700470 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700471 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
472
Chet Haase378e9192012-08-15 15:54:54 -0700473 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700474 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
475 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700476
Romain Guycf51a412013-04-08 19:40:31 -0700477 // Unbind any PBO we might have used to update textures
478 caches.unbindPixelBuffer();
479
Romain Guy09087642013-04-04 12:27:54 -0700480 // Reset to default unpack row length to avoid affecting texture
481 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700482 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700483 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
484 }
485
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700486 mUploadTexture = false;
487}
488
Victoria Lease1e546812013-06-25 14:25:17 -0700489void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
490 Caches& caches = Caches::getInstance();
Romain Guy661a87e2013-03-19 15:24:36 -0700491 bool first = true;
492 bool force = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700493 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
494 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700495 if (texture->canDraw()) {
496 if (first) {
Victoria Lease1e546812013-06-25 14:25:17 -0700497 if (mFunctor) {
498 TextSetupFunctor::Data functorData(texture->getFormat());
499 (*mFunctor)(0, &functorData);
500 }
Romain Guy257ae352013-03-20 16:31:12 -0700501
Romain Guy661a87e2013-03-19 15:24:36 -0700502 checkTextureUpdate();
ztenghui63d41ab2014-02-14 13:13:41 -0800503 caches.bindQuadIndicesBuffer();
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900504
Romain Guy661a87e2013-03-19 15:24:36 -0700505 if (!mDrawn) {
506 // If returns true, a VBO was bound and we must
507 // rebind our vertex attrib pointers even if
508 // they have the same values as the current pointers
509 force = caches.unbindMeshBuffer();
510 }
511
512 caches.activeTexture(0);
513 first = false;
514 }
515
Romain Guy8aa195d2013-06-04 18:00:09 -0700516 caches.bindTexture(texture->getTextureId());
Romain Guy661a87e2013-03-19 15:24:36 -0700517 texture->setLinearFiltering(mLinearFiltering, false);
518
519 TextureVertex* mesh = texture->mesh();
Romain Guy3380cfd2013-08-15 16:57:57 -0700520 caches.bindPositionVertexPointer(force, &mesh[0].x);
521 caches.bindTexCoordsVertexPointer(force, &mesh[0].u);
Romain Guy661a87e2013-03-19 15:24:36 -0700522 force = false;
523
524 glDrawElements(GL_TRIANGLES, texture->meshElementCount(),
525 GL_UNSIGNED_SHORT, texture->indices());
526
527 texture->resetMesh();
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;
603 image.image = NULL;
604 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;
Romain Guyff98fa52011-11-28 09:35:09 -0800612 mClip = NULL;
613 mBounds = NULL;
614
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,
649 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions);
650
Romain Guycf51a412013-04-08 19:40:31 -0700651 // Unbind any PBO we might have used
652 Caches::getInstance().unbindPixelBuffer();
653
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
Romain Guy257ae352013-03-20 16:31:12 -0700666void FontRenderer::initRender(const Rect* clip, Rect* bounds, Functor* 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() {
Romain Guy5b3b3522010-10-27 18:57:51 -0700676 mBounds = NULL;
Romain Guyff98fa52011-11-28 09:35:09 -0800677 mClip = NULL;
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 Craik527a3aa2013-03-04 10:19:31 -0800694 const float* positions, Rect* bounds, Functor* 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,
Victoria Lease1e546812013-06-25 14:25:17 -0700712 float hOffset, float vOffset, Rect* bounds, Functor* 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) {
729 mCurrentFont = NULL;
730 }
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
Tim Murray250b1cf2013-08-01 14:49:22 -0700739 if (mRs == 0) {
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 }
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800751 if (mRs != 0) {
752 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
Derek Sollenbergere392c812014-05-21 11:25:22 -0400775 float *gaussian = new float[2 * intRadius + 1];
776 Blur::generateGaussianWeights(gaussian, intRadius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800777
Dan Morrille4d9a012013-03-28 18:10:43 -0700778 uint8_t* scratch = new uint8_t[width * height];
Derek Sollenbergere392c812014-05-21 11:25:22 -0400779 Blur::horizontal(gaussian, intRadius, *image, scratch, width, height);
780 Blur::vertical(gaussian, intRadius, scratch, *image, width, height);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800781
Dan Morrille4d9a012013-03-28 18:10:43 -0700782 delete[] gaussian;
783 delete[] scratch;
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700784}
785
Victoria Lease1e546812013-06-25 14:25:17 -0700786static uint32_t calculateCacheSize(const Vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700787 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700788 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
789 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700790 if (cacheTexture && cacheTexture->getPixelBuffer()) {
791 size += cacheTexture->getPixelBuffer()->getSize();
792 }
793 }
794 return size;
795}
796
Victoria Lease1e546812013-06-25 14:25:17 -0700797uint32_t FontRenderer::getCacheSize(GLenum format) const {
798 switch (format) {
799 case GL_ALPHA: {
800 return calculateCacheSize(mACacheTextures);
801 }
802 case GL_RGBA: {
803 return calculateCacheSize(mRGBACacheTextures);
804 }
805 default: {
806 return 0;
807 }
808 }
809}
810
Romain Guy694b5192010-07-21 21:33:20 -0700811}; // namespace uirenderer
812}; // namespace android