blob: 5b5b0982067023d531a92c9fe4a6ee2e0e4eee54 [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///////////////////////////////////////////////////////////////////////////////
Andreas Gampe64bb4132014-11-22 00:35:09 +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 Guy9cccc2b2010-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 }
186}
187
Victoria Lease1e546812013-06-25 14:25:17 -0700188void FontRenderer::flushLargeCaches(Vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700189 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700190 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
191 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700192 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700193 cacheTexture->init();
Romain Guye3a9b242013-01-08 11:15:30 -0800194 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
195 while (it.next()) {
196 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700197 }
Romain Guy80872462012-09-04 16:42:01 -0700198 cacheTexture->releaseTexture();
Chet Haase9a824562011-12-16 15:44:59 -0800199 }
200 }
Chet Haase9a824562011-12-16 15:44:59 -0800201}
202
Victoria Lease1e546812013-06-25 14:25:17 -0700203void FontRenderer::flushLargeCaches() {
204 flushLargeCaches(mACacheTextures);
205 flushLargeCaches(mRGBACacheTextures);
206}
207
208CacheTexture* FontRenderer::cacheBitmapInTexture(Vector<CacheTexture*>& cacheTextures,
209 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
210 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
211 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
212 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700213 }
214 }
215 // Could not fit glyph into current cache textures
216 return NULL;
217}
218
Chet Haase7de0cb12011-12-05 16:35:38 -0800219void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700220 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700221 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800222
223 // If the glyph bitmap is empty let's assum the glyph is valid
224 // so we can avoid doing extra work later on
225 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
226 cachedGlyph->mIsValid = true;
227 cachedGlyph->mCacheTexture = NULL;
228 return;
229 }
230
Chet Haase7de0cb12011-12-05 16:35:38 -0800231 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800232
Victoria Lease1e546812013-06-25 14:25:17 -0700233 // choose an appropriate cache texture list for this glyph format
234 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
235 Vector<CacheTexture*>* cacheTextures = NULL;
236 switch (format) {
237 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700238 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700239 cacheTextures = &mACacheTextures;
240 break;
241 case SkMask::kARGB32_Format:
242 cacheTextures = &mRGBACacheTextures;
243 break;
244 default:
245#if DEBUG_FONT_RENDERER
246 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
247#endif
248 return;
249 }
250
Romain Guy694b5192010-07-21 21:33:20 -0700251 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700252 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700253 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700254 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
255 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800256 return;
Romain Guy694b5192010-07-21 21:33:20 -0700257 }
258
259 // Now copy the bitmap into the cache texture
260 uint32_t startX = 0;
261 uint32_t startY = 0;
262
Victoria Lease1e546812013-06-25 14:25:17 -0700263 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700264
Chet Haase378e9192012-08-15 15:54:54 -0700265 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700266 if (!precaching) {
267 // If the new glyph didn't fit and we are not just trying to precache it,
268 // clear out the cache and try again
269 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700270 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700271 }
Romain Guy694b5192010-07-21 21:33:20 -0700272
Chet Haase378e9192012-08-15 15:54:54 -0700273 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700274 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800275 return;
Romain Guy694b5192010-07-21 21:33:20 -0700276 }
277 }
278
Chet Haase378e9192012-08-15 15:54:54 -0700279 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800280
Romain Guy694b5192010-07-21 21:33:20 -0700281 *retOriginX = startX;
282 *retOriginY = startY;
283
284 uint32_t endX = startX + glyph.fWidth;
285 uint32_t endY = startY + glyph.fHeight;
286
Romain Guy80872462012-09-04 16:42:01 -0700287 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700288
Romain Guycf51a412013-04-08 19:40:31 -0700289 if (!cacheTexture->getPixelBuffer()) {
Romain Guy80872462012-09-04 16:42:01 -0700290 Caches::getInstance().activeTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800291 // Large-glyph texture memory is allocated only as needed
Romain Guy80872462012-09-04 16:42:01 -0700292 cacheTexture->allocateTexture();
Chet Haase7de0cb12011-12-05 16:35:38 -0800293 }
Romain Guy661a87e2013-03-19 15:24:36 -0700294 if (!cacheTexture->mesh()) {
295 cacheTexture->allocateMesh();
296 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700297
Romain Guycf51a412013-04-08 19:40:31 -0700298 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700299 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
300 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700301
Romain Guyb969a0d2013-02-05 14:38:40 -0800302 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800303 switch (format) {
304 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700305 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
306 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
307 - TEXTURE_BORDER_SIZE;
308 // write leading border line
309 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
310 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800311 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700312 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800313 row = cacheY * cacheWidth;
314 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800315 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
316 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800317 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800318 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800319 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800320 }
321 } else {
Victoria Lease1e546812013-06-25 14:25:17 -0700322 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800323 row = cacheY * cacheWidth;
324 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
325 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
326 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800327 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700328 }
Victoria Lease1e546812013-06-25 14:25:17 -0700329 // write trailing border line
330 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
331 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
332 break;
333 }
334 case SkMask::kARGB32_Format: {
335 // prep data lengths
336 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
337 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
338 size_t rowSize = formatSize * glyph.fWidth;
339 // prep advances
340 size_t dstStride = formatSize * cacheWidth;
341 // prep indices
342 // - we actually start one row early, and then increment before first copy
343 uint8_t* src = &bitmapBuffer[0 - srcStride];
344 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
345 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
346 uint8_t* dstL = dst - borderSize;
347 uint8_t* dstR = dst + rowSize;
348 // write leading border line
349 memset(dstL, 0, rowSize + 2 * borderSize);
350 // write glyph data
351 while (dst < dstEnd) {
352 memset(dstL += dstStride, 0, borderSize); // leading border column
353 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
354 memset(dstR += dstStride, 0, borderSize); // trailing border column
355 }
356 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700357 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800358 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700359 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800360 case SkMask::kBW_Format: {
Andreas Gampe1e196742014-11-10 15:23:43 -0800361 uint32_t cacheX = 0, cacheY = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700362 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
363 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800364 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700365 // write leading border line
366 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
367 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800368 for (cacheY = startY; cacheY < endY; cacheY++) {
369 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700370 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800371 uint8_t* buffer = bitmapBuffer;
372
Romain Guy0b58a3d2013-03-05 12:16:27 -0800373 row = cacheY * cacheWidth;
374 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800375 while (--rowBytes >= 0) {
376 uint8_t b = *buffer++;
377 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
378 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
379 }
380 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800381 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800382
Victoria Lease1e546812013-06-25 14:25:17 -0700383 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700384 }
Victoria Lease1e546812013-06-25 14:25:17 -0700385 // write trailing border line
386 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
387 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800388 break;
Romain Guy694b5192010-07-21 21:33:20 -0700389 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800390 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700391 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800392 break;
Romain Guy694b5192010-07-21 21:33:20 -0700393 }
Romain Guy97771732012-02-28 18:17:02 -0800394
Chet Haase7de0cb12011-12-05 16:35:38 -0800395 cachedGlyph->mIsValid = true;
Romain Guy694b5192010-07-21 21:33:20 -0700396}
397
Victoria Lease1e546812013-06-25 14:25:17 -0700398CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
399 bool allocate) {
400 CacheTexture* cacheTexture = new CacheTexture(width, height, format, gMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700401
Chet Haase2a47c142011-12-14 15:22:56 -0800402 if (allocate) {
Romain Guy80872462012-09-04 16:42:01 -0700403 Caches::getInstance().activeTexture(0);
404 cacheTexture->allocateTexture();
Romain Guy661a87e2013-03-19 15:24:36 -0700405 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800406 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700407
Chet Haase2a47c142011-12-14 15:22:56 -0800408 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800409}
410
411void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700412 clearCacheTextures(mACacheTextures);
413 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700414
Chet Haase7de0cb12011-12-05 16:35:38 -0800415 mUploadTexture = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700416 mACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
417 GL_ALPHA, true));
418 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
419 GL_ALPHA, false));
420 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
421 GL_ALPHA, false));
422 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
423 GL_ALPHA, false));
424 mRGBACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
425 GL_RGBA, false));
426 mRGBACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
427 GL_RGBA, false));
428 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700429}
430
Romain Guy694b5192010-07-21 21:33:20 -0700431// We don't want to allocate anything unless we actually draw text
432void FontRenderer::checkInit() {
433 if (mInitialized) {
434 return;
435 }
436
437 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700438
439 mInitialized = true;
440}
441
Victoria Lease1e546812013-06-25 14:25:17 -0700442void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheTextures,
443 bool& resetPixelStore, GLuint& lastTextureId) {
444 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
445 CacheTexture* cacheTexture = cacheTextures[i];
446 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
447 if (cacheTexture->getTextureId() != lastTextureId) {
448 lastTextureId = cacheTexture->getTextureId();
449 caches.activeTexture(0);
450 caches.bindTexture(lastTextureId);
451 }
452
453 if (cacheTexture->upload()) {
454 resetPixelStore = true;
455 }
456 }
457 }
458}
459
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700460void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900461 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700462 return;
Romain Guy694b5192010-07-21 21:33:20 -0700463 }
464
Romain Guy2d4fd362011-12-13 22:00:19 -0800465 Caches& caches = Caches::getInstance();
466 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700467
Romain Guycf51a412013-04-08 19:40:31 -0700468 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700469 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
470
Chet Haase378e9192012-08-15 15:54:54 -0700471 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700472 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
473 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700474
Romain Guycf51a412013-04-08 19:40:31 -0700475 // Unbind any PBO we might have used to update textures
476 caches.unbindPixelBuffer();
477
Romain Guy09087642013-04-04 12:27:54 -0700478 // Reset to default unpack row length to avoid affecting texture
479 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700480 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700481 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
482 }
483
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700484 mUploadTexture = false;
485}
486
Victoria Lease1e546812013-06-25 14:25:17 -0700487void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
488 Caches& caches = Caches::getInstance();
Romain Guy661a87e2013-03-19 15:24:36 -0700489 bool first = true;
490 bool force = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700491 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
492 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700493 if (texture->canDraw()) {
494 if (first) {
Victoria Lease1e546812013-06-25 14:25:17 -0700495 if (mFunctor) {
496 TextSetupFunctor::Data functorData(texture->getFormat());
497 (*mFunctor)(0, &functorData);
498 }
Romain Guy257ae352013-03-20 16:31:12 -0700499
Romain Guy661a87e2013-03-19 15:24:36 -0700500 checkTextureUpdate();
ztenghui63d41ab2014-02-14 13:13:41 -0800501 caches.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
507 force = caches.unbindMeshBuffer();
508 }
509
510 caches.activeTexture(0);
511 first = false;
512 }
513
Romain Guy8aa195d2013-06-04 18:00:09 -0700514 caches.bindTexture(texture->getTextureId());
Romain Guy661a87e2013-03-19 15:24:36 -0700515 texture->setLinearFiltering(mLinearFiltering, false);
516
517 TextureVertex* mesh = texture->mesh();
Romain Guy3380cfd2013-08-15 16:57:57 -0700518 caches.bindPositionVertexPointer(force, &mesh[0].x);
519 caches.bindTexCoordsVertexPointer(force, &mesh[0].u);
Romain Guy661a87e2013-03-19 15:24:36 -0700520 force = false;
521
522 glDrawElements(GL_TRIANGLES, texture->meshElementCount(),
523 GL_UNSIGNED_SHORT, texture->indices());
524
525 texture->resetMesh();
Romain Guy115096f2013-03-19 11:32:41 -0700526 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900527 }
Victoria Lease1e546812013-06-25 14:25:17 -0700528}
529
530void FontRenderer::issueDrawCommand() {
531 issueDrawCommand(mACacheTextures);
532 issueDrawCommand(mRGBACacheTextures);
Romain Guy5b3b3522010-10-27 18:57:51 -0700533
534 mDrawn = true;
Romain Guy694b5192010-07-21 21:33:20 -0700535}
536
Romain Guy97771732012-02-28 18:17:02 -0800537void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
538 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800539 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800540 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800541 // Now use the new texture id
542 mCurrentCacheTexture = texture;
543 }
Romain Guy09147fb2010-07-22 13:08:20 -0700544
Romain Guy661a87e2013-03-19 15:24:36 -0700545 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
546 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800547}
548
549void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
550 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
551 float x4, float y4, float u4, float v4, CacheTexture* texture) {
552
553 if (mClip &&
554 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
555 return;
556 }
557
558 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 -0700559
Romain Guy5b3b3522010-10-27 18:57:51 -0700560 if (mBounds) {
561 mBounds->left = fmin(mBounds->left, x1);
562 mBounds->top = fmin(mBounds->top, y3);
563 mBounds->right = fmax(mBounds->right, x3);
564 mBounds->bottom = fmax(mBounds->bottom, y1);
565 }
566
Romain Guy661a87e2013-03-19 15:24:36 -0700567 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700568 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700569 }
570}
571
Romain Guy97771732012-02-28 18:17:02 -0800572void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
573 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
574 float x4, float y4, float u4, float v4, CacheTexture* texture) {
575
576 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
577
578 if (mBounds) {
579 mBounds->left = fmin(mBounds->left, fmin(x1, fmin(x2, fmin(x3, x4))));
580 mBounds->top = fmin(mBounds->top, fmin(y1, fmin(y2, fmin(y3, y4))));
581 mBounds->right = fmax(mBounds->right, fmax(x1, fmax(x2, fmax(x3, x4))));
582 mBounds->bottom = fmax(mBounds->bottom, fmax(y1, fmax(y2, fmax(y3, y4))));
583 }
584
Romain Guy661a87e2013-03-19 15:24:36 -0700585 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800586 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800587 }
588}
589
Chris Craik59744b72014-07-01 17:56:52 -0700590void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800591 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700592}
Romain Guy7975fb62010-10-01 16:36:14 -0700593
Chris Craikd218a922014-01-02 17:13:34 -0800594FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const char *text,
Derek Sollenbergere392c812014-05-21 11:25:22 -0400595 uint32_t startIndex, uint32_t len, int numGlyphs, float radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700596 checkInit();
597
Romain Guycf51a412013-04-08 19:40:31 -0700598 DropShadow image;
599 image.width = 0;
600 image.height = 0;
601 image.image = NULL;
602 image.penX = 0;
603 image.penY = 0;
604
Romain Guy1e45aae2010-08-13 19:39:53 -0700605 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700606 return image;
607 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700608
Romain Guy2d4fd362011-12-13 22:00:19 -0800609 mDrawn = false;
Romain Guyff98fa52011-11-28 09:35:09 -0800610 mClip = NULL;
611 mBounds = NULL;
612
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700613 Rect bounds;
Raph Levien416a8472012-07-19 22:48:17 -0700614 mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800615
Derek Sollenbergere392c812014-05-21 11:25:22 -0400616 uint32_t intRadius = Blur::convertRadiusToInt(radius);
617 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
618 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
Romain Guyff98fa52011-11-28 09:35:09 -0800619
Romain Guycf51a412013-04-08 19:40:31 -0700620 uint32_t maxSize = Caches::getInstance().maxTextureSize;
621 if (paddedWidth > maxSize || paddedHeight > maxSize) {
622 return image;
623 }
624
Dan Morrille4d9a012013-03-28 18:10:43 -0700625#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800626 // Align buffers for renderscript usage
627 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
628 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700629 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800630 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800631 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700632#else
633 int size = paddedWidth * paddedHeight;
634 uint8_t* dataBuffer = (uint8_t*) malloc(size);
635#endif
636
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800637 memset(dataBuffer, 0, size);
638
Derek Sollenbergere392c812014-05-21 11:25:22 -0400639 int penX = intRadius - bounds.left;
640 int penY = intRadius - bounds.bottom;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700641
Chris Craikdd8697c2013-02-22 10:41:36 -0800642 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
643 // text has non-whitespace, so draw and blur to create the shadow
644 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
645 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
646 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
647 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions);
648
Romain Guycf51a412013-04-08 19:40:31 -0700649 // Unbind any PBO we might have used
650 Caches::getInstance().unbindPixelBuffer();
651
Chris Craikdd8697c2013-02-22 10:41:36 -0800652 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
653 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700654
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700655 image.width = paddedWidth;
656 image.height = paddedHeight;
657 image.image = dataBuffer;
658 image.penX = penX;
659 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800660
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700661 return image;
662}
Romain Guy694b5192010-07-21 21:33:20 -0700663
Romain Guy257ae352013-03-20 16:31:12 -0700664void FontRenderer::initRender(const Rect* clip, Rect* bounds, Functor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700665 checkInit();
666
Romain Guy5b3b3522010-10-27 18:57:51 -0700667 mDrawn = false;
668 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700669 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700670 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800671}
Romain Guyff98fa52011-11-28 09:35:09 -0800672
Romain Guy671d6cf2012-01-18 12:39:17 -0800673void FontRenderer::finishRender() {
Romain Guy5b3b3522010-10-27 18:57:51 -0700674 mBounds = NULL;
Romain Guyff98fa52011-11-28 09:35:09 -0800675 mClip = NULL;
Romain Guy694b5192010-07-21 21:33:20 -0700676
Romain Guy661a87e2013-03-19 15:24:36 -0700677 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800678}
679
Chris Craikd218a922014-01-02 17:13:34 -0800680void FontRenderer::precache(const SkPaint* paint, const char* text, int numGlyphs,
Chris Craik59744b72014-07-01 17:56:52 -0700681 const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800682 Font* font = Font::create(this, paint, matrix);
Chet Haasee816bae2012-08-09 13:39:02 -0700683 font->precache(paint, text, numGlyphs);
684}
685
Romain Guycf51a412013-04-08 19:40:31 -0700686void FontRenderer::endPrecaching() {
687 checkTextureUpdate();
688}
689
Chris Craikd218a922014-01-02 17:13:34 -0800690bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
Romain Guy671d6cf2012-01-18 12:39:17 -0800691 uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
Chris Craik527a3aa2013-03-04 10:19:31 -0800692 const float* positions, Rect* bounds, Functor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800693 if (!mCurrentFont) {
694 ALOGE("No font set");
695 return false;
696 }
697
Romain Guy257ae352013-03-20 16:31:12 -0700698 initRender(clip, bounds, functor);
Romain Guy671d6cf2012-01-18 12:39:17 -0800699 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800700
701 if (forceFinish) {
702 finishRender();
703 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700704
705 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700706}
707
Chris Craikd218a922014-01-02 17:13:34 -0800708bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
709 uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
Victoria Lease1e546812013-06-25 14:25:17 -0700710 float hOffset, float vOffset, Rect* bounds, Functor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800711 if (!mCurrentFont) {
712 ALOGE("No font set");
713 return false;
714 }
715
Victoria Lease1e546812013-06-25 14:25:17 -0700716 initRender(clip, bounds, functor);
Romain Guy97771732012-02-28 18:17:02 -0800717 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
718 finishRender();
719
720 return mDrawn;
721}
722
Romain Guy9b1204b2012-09-04 15:22:57 -0700723void FontRenderer::removeFont(const Font* font) {
Romain Guye3a9b242013-01-08 11:15:30 -0800724 mActiveFonts.remove(font->getDescription());
Romain Guy9b1204b2012-09-04 15:22:57 -0700725
726 if (mCurrentFont == font) {
727 mCurrentFont = NULL;
728 }
729}
730
Derek Sollenbergere392c812014-05-21 11:25:22 -0400731void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
732 uint32_t intRadius = Blur::convertRadiusToInt(radius);
Dan Morrille4d9a012013-03-28 18:10:43 -0700733#ifdef ANDROID_ENABLE_RENDERSCRIPT
Derek Sollenbergere392c812014-05-21 11:25:22 -0400734 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700735 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700736
Tim Murray250b1cf2013-08-01 14:49:22 -0700737 if (mRs == 0) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700738 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800739 // a null path is OK because there are no custom kernels used
740 // hence nothing gets cached by RS
741 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800742 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700743 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800744 } else {
745 mRsElement = RSC::Element::A_8(mRs);
746 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700747 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800748 }
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800749 if (mRs != 0) {
750 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
751 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
752 RS_ALLOCATION_MIPMAP_NONE,
753 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
754 *image);
755 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
756 RS_ALLOCATION_MIPMAP_NONE,
757 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
758 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800759
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800760 mRsScript->setRadius(radius);
761 mRsScript->setInput(ain);
762 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700763
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800764 // replace the original image's pointer, avoiding a copy back to the original buffer
765 free(*image);
766 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700767
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800768 return;
769 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800770 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700771#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800772
Derek Sollenbergere392c812014-05-21 11:25:22 -0400773 float *gaussian = new float[2 * intRadius + 1];
774 Blur::generateGaussianWeights(gaussian, intRadius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800775
Dan Morrille4d9a012013-03-28 18:10:43 -0700776 uint8_t* scratch = new uint8_t[width * height];
Derek Sollenbergere392c812014-05-21 11:25:22 -0400777 Blur::horizontal(gaussian, intRadius, *image, scratch, width, height);
778 Blur::vertical(gaussian, intRadius, scratch, *image, width, height);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800779
Dan Morrille4d9a012013-03-28 18:10:43 -0700780 delete[] gaussian;
781 delete[] scratch;
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700782}
783
Victoria Lease1e546812013-06-25 14:25:17 -0700784static uint32_t calculateCacheSize(const Vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700785 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700786 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
787 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700788 if (cacheTexture && cacheTexture->getPixelBuffer()) {
789 size += cacheTexture->getPixelBuffer()->getSize();
790 }
791 }
792 return size;
793}
794
Victoria Lease1e546812013-06-25 14:25:17 -0700795uint32_t FontRenderer::getCacheSize(GLenum format) const {
796 switch (format) {
797 case GL_ALPHA: {
798 return calculateCacheSize(mACacheTextures);
799 }
800 case GL_RGBA: {
801 return calculateCacheSize(mRGBACacheTextures);
802 }
803 default: {
804 return 0;
805 }
806 }
807}
808
Romain Guy694b5192010-07-21 21:33:20 -0700809}; // namespace uirenderer
810}; // namespace android