blob: 35051b7cccead4b56cf8786837d5d379b4c8de50 [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"
Chris Craike2bb3802015-03-13 15:07:52 -070022#include "Glop.h"
23#include "GlopBuilder.h"
Chris Craik96a5c4c2015-01-27 15:46:35 -080024#include "OpenGLRenderer.h"
25#include "PixelBuffer.h"
26#include "Rect.h"
27#include "renderstate/RenderState.h"
28#include "utils/Blur.h"
Chris Craik083e7332015-02-27 17:04:20 -080029#include "utils/MathUtils.h"
Chris Craik96a5c4c2015-01-27 15:46:35 -080030#include "utils/Timing.h"
Romain Guy694b5192010-07-21 21:33:20 -070031
Derek Sollenbergerca79cf62012-08-14 16:44:52 -040032#include <SkGlyph.h>
Romain Guy694b5192010-07-21 21:33:20 -070033#include <SkUtils.h>
34
Romain Guy51769a62010-07-23 00:28:00 -070035#include <cutils/properties.h>
Romain Guye2d345e2010-09-24 18:39:22 -070036
Romain Guy51769a62010-07-23 00:28:00 -070037#include <utils/Log.h>
38
Dan Morrille4d9a012013-03-28 18:10:43 -070039#ifdef ANDROID_ENABLE_RENDERSCRIPT
Romain Guy6e200402013-03-08 11:28:22 -080040#include <RenderScript.h>
Dan Morrille4d9a012013-03-28 18:10:43 -070041#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -080042
Romain Guy694b5192010-07-21 21:33:20 -070043namespace android {
44namespace uirenderer {
45
Chris Craikf2d8ccc2013-02-13 16:14:17 -080046// blur inputs smaller than this constant will bypass renderscript
47#define RS_MIN_INPUT_CUTOFF 10000
48
Romain Guy694b5192010-07-21 21:33:20 -070049///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070050// TextSetupFunctor
51///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070052
Chris Craik82840732015-04-03 09:37:49 -070053void TextDrawFunctor::draw(CacheTexture& texture, bool linearFiltering) {
Chris Craik53e51e42015-06-01 10:35:35 -070054 int textureFillFlags = TextureFillFlags::None;
55 if (texture.getFormat() == GL_ALPHA) {
56 textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture;
Chris Craike2bb3802015-03-13 15:07:52 -070057 }
Chris Craik53e51e42015-06-01 10:35:35 -070058 if (linearFiltering) {
59 textureFillFlags |= TextureFillFlags::ForceFilter;
60 }
61 int transformFlags = pureTranslate
62 ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
Chris Craike2bb3802015-03-13 15:07:52 -070063 Glop glop;
64 GlopBuilder(renderer->mRenderState, renderer->mCaches, &glop)
65 .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
66 .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, renderer->currentSnapshot()->alpha)
Chris Craik53e51e42015-06-01 10:35:35 -070067 .setTransform(*(renderer->currentSnapshot()), transformFlags)
Chris Craike2bb3802015-03-13 15:07:52 -070068 .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
69 .setRoundRectClipState(renderer->currentSnapshot()->roundRectClipState)
70 .build();
71 renderer->renderGlop(glop);
Victoria Lease1e546812013-06-25 14:25:17 -070072}
73
74///////////////////////////////////////////////////////////////////////////////
Romain Guy694b5192010-07-21 21:33:20 -070075// FontRenderer
76///////////////////////////////////////////////////////////////////////////////
77
Romain Guy514fb182011-01-19 14:38:29 -080078static bool sLogFontRendererCreate = true;
79
Chris Craik083e7332015-02-27 17:04:20 -080080FontRenderer::FontRenderer()
81 : mGammaTable(nullptr)
82 , mCurrentFont(nullptr)
83 , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity)
84 , mCurrentCacheTexture(nullptr)
85 , mUploadTexture(false)
86 , mFunctor(nullptr)
87 , mClip(nullptr)
88 , mBounds(nullptr)
89 , mDrawn(false)
90 , mInitialized(false)
91 , mLinearFiltering(false) {
Romain Guye3a9b242013-01-08 11:15:30 -080092
Romain Guyc9855a52011-01-21 21:14:15 -080093 if (sLogFontRendererCreate) {
94 INIT_LOGD("Creating FontRenderer");
95 }
Romain Guy51769a62010-07-23 00:28:00 -070096
Chet Haaseeb32a492012-08-31 13:54:03 -070097 mSmallCacheWidth = DEFAULT_TEXT_SMALL_CACHE_WIDTH;
98 mSmallCacheHeight = DEFAULT_TEXT_SMALL_CACHE_HEIGHT;
99 mLargeCacheWidth = DEFAULT_TEXT_LARGE_CACHE_WIDTH;
100 mLargeCacheHeight = DEFAULT_TEXT_LARGE_CACHE_HEIGHT;
Romain Guy51769a62010-07-23 00:28:00 -0700101
102 char property[PROPERTY_VALUE_MAX];
Chris Craikd41c4d82015-01-05 15:51:13 -0800103 if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, nullptr) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800104 mSmallCacheWidth = atoi(property);
Romain Guy51769a62010-07-23 00:28:00 -0700105 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700106
Chris Craikd41c4d82015-01-05 15:51:13 -0800107 if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, nullptr) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800108 mSmallCacheHeight = atoi(property);
Chet Haaseeb32a492012-08-31 13:54:03 -0700109 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700110
Chris Craikd41c4d82015-01-05 15:51:13 -0800111 if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, nullptr) > 0) {
Chet Haaseeb32a492012-08-31 13:54:03 -0700112 mLargeCacheWidth = atoi(property);
113 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700114
Chris Craikd41c4d82015-01-05 15:51:13 -0800115 if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, nullptr) > 0) {
Chet Haaseeb32a492012-08-31 13:54:03 -0700116 mLargeCacheHeight = atoi(property);
117 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700118
119 uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
Chris Craik083e7332015-02-27 17:04:20 -0800120
121 mSmallCacheWidth = MathUtils::min(mSmallCacheWidth, maxTextureSize);
122 mSmallCacheHeight = MathUtils::min(mSmallCacheHeight, maxTextureSize);
123 mLargeCacheWidth = MathUtils::min(mLargeCacheWidth, maxTextureSize);
124 mLargeCacheHeight = MathUtils::min(mLargeCacheHeight, maxTextureSize);
Romain Guy9f5dab32012-09-04 12:55:44 -0700125
Chet Haaseeb32a492012-08-31 13:54:03 -0700126 if (sLogFontRendererCreate) {
127 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
128 mSmallCacheWidth, mSmallCacheHeight,
129 mLargeCacheWidth, mLargeCacheHeight >> 1,
130 mLargeCacheWidth, mLargeCacheHeight >> 1,
131 mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700132 }
Romain Guy514fb182011-01-19 14:38:29 -0800133
134 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700135}
136
Victoria Lease1e546812013-06-25 14:25:17 -0700137void clearCacheTextures(Vector<CacheTexture*>& cacheTextures) {
138 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
139 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700140 }
Victoria Lease1e546812013-06-25 14:25:17 -0700141 cacheTextures.clear();
142}
143
144FontRenderer::~FontRenderer() {
145 clearCacheTextures(mACacheTextures);
146 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700147
Romain Guye3a9b242013-01-08 11:15:30 -0800148 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
149 while (it.next()) {
150 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700151 }
Romain Guye3a9b242013-01-08 11:15:30 -0800152 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700153}
154
155void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700156 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700157
Romain Guye3a9b242013-01-08 11:15:30 -0800158 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
159 while (it.next()) {
160 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700161 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700162
Victoria Lease1e546812013-06-25 14:25:17 -0700163 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
164 mACacheTextures[i]->init();
165 }
166
167 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
168 mRGBACacheTextures[i]->init();
Romain Guy694b5192010-07-21 21:33:20 -0700169 }
chaochen1f61b192014-08-28 18:45:27 -0700170
171 mDrawn = false;
Romain Guy694b5192010-07-21 21:33:20 -0700172}
173
Victoria Lease1e546812013-06-25 14:25:17 -0700174void FontRenderer::flushLargeCaches(Vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700175 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700176 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
177 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700178 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700179 cacheTexture->init();
Romain Guye3a9b242013-01-08 11:15:30 -0800180 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
181 while (it.next()) {
182 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700183 }
Chris Craike2bb3802015-03-13 15:07:52 -0700184 cacheTexture->releasePixelBuffer();
Chet Haase9a824562011-12-16 15:44:59 -0800185 }
186 }
Chet Haase9a824562011-12-16 15:44:59 -0800187}
188
Victoria Lease1e546812013-06-25 14:25:17 -0700189void FontRenderer::flushLargeCaches() {
190 flushLargeCaches(mACacheTextures);
191 flushLargeCaches(mRGBACacheTextures);
192}
193
194CacheTexture* FontRenderer::cacheBitmapInTexture(Vector<CacheTexture*>& cacheTextures,
195 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
196 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
197 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
198 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700199 }
200 }
201 // Could not fit glyph into current cache textures
Chris Craikd41c4d82015-01-05 15:51:13 -0800202 return nullptr;
Chet Haase378e9192012-08-15 15:54:54 -0700203}
204
Chet Haase7de0cb12011-12-05 16:35:38 -0800205void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700206 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700207 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800208
209 // If the glyph bitmap is empty let's assum the glyph is valid
210 // so we can avoid doing extra work later on
211 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
212 cachedGlyph->mIsValid = true;
Chris Craikd41c4d82015-01-05 15:51:13 -0800213 cachedGlyph->mCacheTexture = nullptr;
Romain Guya4adcf02013-02-28 12:15:35 -0800214 return;
215 }
216
Chet Haase7de0cb12011-12-05 16:35:38 -0800217 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800218
Victoria Lease1e546812013-06-25 14:25:17 -0700219 // choose an appropriate cache texture list for this glyph format
220 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
Chris Craikd41c4d82015-01-05 15:51:13 -0800221 Vector<CacheTexture*>* cacheTextures = nullptr;
Victoria Lease1e546812013-06-25 14:25:17 -0700222 switch (format) {
223 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700224 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700225 cacheTextures = &mACacheTextures;
226 break;
227 case SkMask::kARGB32_Format:
228 cacheTextures = &mRGBACacheTextures;
229 break;
230 default:
231#if DEBUG_FONT_RENDERER
232 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
233#endif
234 return;
235 }
236
Romain Guy694b5192010-07-21 21:33:20 -0700237 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700238 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700239 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700240 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
241 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800242 return;
Romain Guy694b5192010-07-21 21:33:20 -0700243 }
244
245 // Now copy the bitmap into the cache texture
246 uint32_t startX = 0;
247 uint32_t startY = 0;
248
Victoria Lease1e546812013-06-25 14:25:17 -0700249 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700250
Chet Haase378e9192012-08-15 15:54:54 -0700251 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700252 if (!precaching) {
253 // If the new glyph didn't fit and we are not just trying to precache it,
254 // clear out the cache and try again
255 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700256 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700257 }
Romain Guy694b5192010-07-21 21:33:20 -0700258
Chet Haase378e9192012-08-15 15:54:54 -0700259 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700260 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800261 return;
Romain Guy694b5192010-07-21 21:33:20 -0700262 }
263 }
264
Chet Haase378e9192012-08-15 15:54:54 -0700265 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800266
Romain Guy694b5192010-07-21 21:33:20 -0700267 *retOriginX = startX;
268 *retOriginY = startY;
269
270 uint32_t endX = startX + glyph.fWidth;
271 uint32_t endY = startY + glyph.fHeight;
272
Romain Guy80872462012-09-04 16:42:01 -0700273 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700274
Romain Guycf51a412013-04-08 19:40:31 -0700275 if (!cacheTexture->getPixelBuffer()) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800276 Caches::getInstance().textureState().activateTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800277 // Large-glyph texture memory is allocated only as needed
Chris Craike2bb3802015-03-13 15:07:52 -0700278 cacheTexture->allocatePixelBuffer();
Chet Haase7de0cb12011-12-05 16:35:38 -0800279 }
Romain Guy661a87e2013-03-19 15:24:36 -0700280 if (!cacheTexture->mesh()) {
281 cacheTexture->allocateMesh();
282 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700283
Romain Guycf51a412013-04-08 19:40:31 -0700284 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700285 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
286 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700287
Romain Guyb969a0d2013-02-05 14:38:40 -0800288 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800289 switch (format) {
290 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700291 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
292 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
293 - TEXTURE_BORDER_SIZE;
294 // write leading border line
295 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
296 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800297 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700298 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800299 row = cacheY * cacheWidth;
300 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800301 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
302 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800303 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800304 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800305 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800306 }
307 } else {
Victoria Lease1e546812013-06-25 14:25:17 -0700308 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800309 row = cacheY * cacheWidth;
310 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
311 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
312 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800313 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700314 }
Victoria Lease1e546812013-06-25 14:25:17 -0700315 // write trailing border line
316 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
317 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
318 break;
319 }
320 case SkMask::kARGB32_Format: {
321 // prep data lengths
322 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
323 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
324 size_t rowSize = formatSize * glyph.fWidth;
325 // prep advances
326 size_t dstStride = formatSize * cacheWidth;
327 // prep indices
328 // - we actually start one row early, and then increment before first copy
329 uint8_t* src = &bitmapBuffer[0 - srcStride];
330 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
331 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
332 uint8_t* dstL = dst - borderSize;
333 uint8_t* dstR = dst + rowSize;
334 // write leading border line
335 memset(dstL, 0, rowSize + 2 * borderSize);
336 // write glyph data
337 while (dst < dstEnd) {
338 memset(dstL += dstStride, 0, borderSize); // leading border column
339 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
340 memset(dstR += dstStride, 0, borderSize); // trailing border column
341 }
342 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700343 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800344 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700345 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800346 case SkMask::kBW_Format: {
Andreas Gampe1e196742014-11-10 15:23:43 -0800347 uint32_t cacheX = 0, cacheY = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700348 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
349 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800350 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700351 // write leading border line
352 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
353 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800354 for (cacheY = startY; cacheY < endY; cacheY++) {
355 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700356 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800357 uint8_t* buffer = bitmapBuffer;
358
Romain Guy0b58a3d2013-03-05 12:16:27 -0800359 row = cacheY * cacheWidth;
360 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800361 while (--rowBytes >= 0) {
362 uint8_t b = *buffer++;
363 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
364 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
365 }
366 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800367 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800368
Victoria Lease1e546812013-06-25 14:25:17 -0700369 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700370 }
Victoria Lease1e546812013-06-25 14:25:17 -0700371 // write trailing border line
372 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
373 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800374 break;
Romain Guy694b5192010-07-21 21:33:20 -0700375 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800376 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700377 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800378 break;
Romain Guy694b5192010-07-21 21:33:20 -0700379 }
Romain Guy97771732012-02-28 18:17:02 -0800380
Chet Haase7de0cb12011-12-05 16:35:38 -0800381 cachedGlyph->mIsValid = true;
Romain Guy694b5192010-07-21 21:33:20 -0700382}
383
Victoria Lease1e546812013-06-25 14:25:17 -0700384CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
385 bool allocate) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800386 CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700387
Chet Haase2a47c142011-12-14 15:22:56 -0800388 if (allocate) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800389 Caches::getInstance().textureState().activateTexture(0);
Chris Craike2bb3802015-03-13 15:07:52 -0700390 cacheTexture->allocatePixelBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700391 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800392 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700393
Chet Haase2a47c142011-12-14 15:22:56 -0800394 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800395}
396
397void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700398 clearCacheTextures(mACacheTextures);
399 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700400
Chet Haase7de0cb12011-12-05 16:35:38 -0800401 mUploadTexture = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700402 mACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
403 GL_ALPHA, true));
404 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
405 GL_ALPHA, false));
406 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
407 GL_ALPHA, false));
408 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
409 GL_ALPHA, false));
410 mRGBACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
411 GL_RGBA, false));
412 mRGBACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
413 GL_RGBA, false));
414 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700415}
416
Romain Guy694b5192010-07-21 21:33:20 -0700417// We don't want to allocate anything unless we actually draw text
418void FontRenderer::checkInit() {
419 if (mInitialized) {
420 return;
421 }
422
423 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700424
425 mInitialized = true;
426}
427
Victoria Lease1e546812013-06-25 14:25:17 -0700428void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheTextures,
429 bool& resetPixelStore, GLuint& lastTextureId) {
430 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
431 CacheTexture* cacheTexture = cacheTextures[i];
432 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
433 if (cacheTexture->getTextureId() != lastTextureId) {
434 lastTextureId = cacheTexture->getTextureId();
Chris Craik44eb2c02015-01-29 09:45:09 -0800435 caches.textureState().activateTexture(0);
436 caches.textureState().bindTexture(lastTextureId);
Victoria Lease1e546812013-06-25 14:25:17 -0700437 }
438
439 if (cacheTexture->upload()) {
440 resetPixelStore = true;
441 }
442 }
443 }
444}
445
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700446void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900447 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700448 return;
Romain Guy694b5192010-07-21 21:33:20 -0700449 }
450
Romain Guy2d4fd362011-12-13 22:00:19 -0800451 Caches& caches = Caches::getInstance();
452 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700453
Romain Guycf51a412013-04-08 19:40:31 -0700454 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700455 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
456
Chet Haase378e9192012-08-15 15:54:54 -0700457 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700458 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
459 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700460
Romain Guycf51a412013-04-08 19:40:31 -0700461 // Unbind any PBO we might have used to update textures
Chris Craik44eb2c02015-01-29 09:45:09 -0800462 caches.pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700463
Romain Guy09087642013-04-04 12:27:54 -0700464 // Reset to default unpack row length to avoid affecting texture
465 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700466 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700467 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
468 }
469
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700470 mUploadTexture = false;
471}
472
Victoria Lease1e546812013-06-25 14:25:17 -0700473void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800474 if (!mFunctor) return;
475
Romain Guy661a87e2013-03-19 15:24:36 -0700476 bool first = true;
Chris Craik96a5c4c2015-01-27 15:46:35 -0800477 bool forceRebind = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700478 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
479 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700480 if (texture->canDraw()) {
481 if (first) {
Chris Craike2bb3802015-03-13 15:07:52 -0700482 checkTextureUpdate();
Romain Guy661a87e2013-03-19 15:24:36 -0700483 first = false;
Chris Craik083e7332015-02-27 17:04:20 -0800484 mDrawn = true;
Romain Guy661a87e2013-03-19 15:24:36 -0700485 }
Chris Craik82840732015-04-03 09:37:49 -0700486
Chris Craike2bb3802015-03-13 15:07:52 -0700487 mFunctor->draw(*texture, mLinearFiltering);
Romain Guy661a87e2013-03-19 15:24:36 -0700488
Romain Guy661a87e2013-03-19 15:24:36 -0700489 texture->resetMesh();
Chris Craik96a5c4c2015-01-27 15:46:35 -0800490 forceRebind = false;
Romain Guy115096f2013-03-19 11:32:41 -0700491 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900492 }
Victoria Lease1e546812013-06-25 14:25:17 -0700493}
494
495void FontRenderer::issueDrawCommand() {
496 issueDrawCommand(mACacheTextures);
497 issueDrawCommand(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700498}
499
Romain Guy97771732012-02-28 18:17:02 -0800500void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
501 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800502 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800503 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800504 // Now use the new texture id
505 mCurrentCacheTexture = texture;
506 }
Romain Guy09147fb2010-07-22 13:08:20 -0700507
Romain Guy661a87e2013-03-19 15:24:36 -0700508 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
509 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800510}
511
512void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
513 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
514 float x4, float y4, float u4, float v4, CacheTexture* texture) {
515
516 if (mClip &&
517 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
518 return;
519 }
520
521 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 -0700522
Romain Guy5b3b3522010-10-27 18:57:51 -0700523 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700524 mBounds->left = std::min(mBounds->left, x1);
525 mBounds->top = std::min(mBounds->top, y3);
526 mBounds->right = std::max(mBounds->right, x3);
527 mBounds->bottom = std::max(mBounds->bottom, y1);
Romain Guy5b3b3522010-10-27 18:57:51 -0700528 }
529
Romain Guy661a87e2013-03-19 15:24:36 -0700530 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700531 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700532 }
533}
534
Romain Guy97771732012-02-28 18:17:02 -0800535void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
536 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
537 float x4, float y4, float u4, float v4, CacheTexture* texture) {
538
539 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
540
541 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700542 mBounds->left = std::min(mBounds->left, std::min(x1, std::min(x2, std::min(x3, x4))));
543 mBounds->top = std::min(mBounds->top, std::min(y1, std::min(y2, std::min(y3, y4))));
544 mBounds->right = std::max(mBounds->right, std::max(x1, std::max(x2, std::max(x3, x4))));
545 mBounds->bottom = std::max(mBounds->bottom, std::max(y1, std::max(y2, std::max(y3, y4))));
Romain Guy97771732012-02-28 18:17:02 -0800546 }
547
Romain Guy661a87e2013-03-19 15:24:36 -0700548 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800549 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800550 }
551}
552
Chris Craik59744b72014-07-01 17:56:52 -0700553void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800554 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700555}
Romain Guy7975fb62010-10-01 16:36:14 -0700556
Chris Craikd218a922014-01-02 17:13:34 -0800557FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const char *text,
Derek Sollenbergere392c812014-05-21 11:25:22 -0400558 uint32_t startIndex, uint32_t len, int numGlyphs, float radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700559 checkInit();
560
Romain Guycf51a412013-04-08 19:40:31 -0700561 DropShadow image;
562 image.width = 0;
563 image.height = 0;
Chris Craikd41c4d82015-01-05 15:51:13 -0800564 image.image = nullptr;
Romain Guycf51a412013-04-08 19:40:31 -0700565 image.penX = 0;
566 image.penY = 0;
567
Romain Guy1e45aae2010-08-13 19:39:53 -0700568 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700569 return image;
570 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700571
Romain Guy2d4fd362011-12-13 22:00:19 -0800572 mDrawn = false;
Chris Craikd41c4d82015-01-05 15:51:13 -0800573 mClip = nullptr;
574 mBounds = nullptr;
Romain Guyff98fa52011-11-28 09:35:09 -0800575
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700576 Rect bounds;
Raph Levien416a8472012-07-19 22:48:17 -0700577 mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800578
Derek Sollenbergere392c812014-05-21 11:25:22 -0400579 uint32_t intRadius = Blur::convertRadiusToInt(radius);
580 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
581 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
Romain Guyff98fa52011-11-28 09:35:09 -0800582
Romain Guycf51a412013-04-08 19:40:31 -0700583 uint32_t maxSize = Caches::getInstance().maxTextureSize;
584 if (paddedWidth > maxSize || paddedHeight > maxSize) {
585 return image;
586 }
587
Dan Morrille4d9a012013-03-28 18:10:43 -0700588#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800589 // Align buffers for renderscript usage
590 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
591 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700592 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800593 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800594 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700595#else
596 int size = paddedWidth * paddedHeight;
597 uint8_t* dataBuffer = (uint8_t*) malloc(size);
598#endif
599
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800600 memset(dataBuffer, 0, size);
601
Derek Sollenbergere392c812014-05-21 11:25:22 -0400602 int penX = intRadius - bounds.left;
603 int penY = intRadius - bounds.bottom;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700604
Chris Craikdd8697c2013-02-22 10:41:36 -0800605 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
606 // text has non-whitespace, so draw and blur to create the shadow
607 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
608 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
609 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
Chris Craikd41c4d82015-01-05 15:51:13 -0800610 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
Chris Craikdd8697c2013-02-22 10:41:36 -0800611
Romain Guycf51a412013-04-08 19:40:31 -0700612 // Unbind any PBO we might have used
Chris Craik44eb2c02015-01-29 09:45:09 -0800613 Caches::getInstance().pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700614
Chris Craikdd8697c2013-02-22 10:41:36 -0800615 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
616 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700617
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700618 image.width = paddedWidth;
619 image.height = paddedHeight;
620 image.image = dataBuffer;
621 image.penX = penX;
622 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800623
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700624 return image;
625}
Romain Guy694b5192010-07-21 21:33:20 -0700626
Chris Craik82840732015-04-03 09:37:49 -0700627void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextDrawFunctor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700628 checkInit();
629
Romain Guy5b3b3522010-10-27 18:57:51 -0700630 mDrawn = false;
631 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700632 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700633 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800634}
Romain Guyff98fa52011-11-28 09:35:09 -0800635
Romain Guy671d6cf2012-01-18 12:39:17 -0800636void FontRenderer::finishRender() {
Chris Craikd41c4d82015-01-05 15:51:13 -0800637 mBounds = nullptr;
638 mClip = nullptr;
Romain Guy694b5192010-07-21 21:33:20 -0700639
Romain Guy661a87e2013-03-19 15:24:36 -0700640 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800641}
642
Chris Craikd218a922014-01-02 17:13:34 -0800643void FontRenderer::precache(const SkPaint* paint, const char* text, int numGlyphs,
Chris Craik59744b72014-07-01 17:56:52 -0700644 const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800645 Font* font = Font::create(this, paint, matrix);
Chet Haasee816bae2012-08-09 13:39:02 -0700646 font->precache(paint, text, numGlyphs);
647}
648
Romain Guycf51a412013-04-08 19:40:31 -0700649void FontRenderer::endPrecaching() {
650 checkTextureUpdate();
651}
652
Chris Craikd218a922014-01-02 17:13:34 -0800653bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
Romain Guy671d6cf2012-01-18 12:39:17 -0800654 uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
Chris Craik82840732015-04-03 09:37:49 -0700655 const float* positions, Rect* bounds, TextDrawFunctor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800656 if (!mCurrentFont) {
657 ALOGE("No font set");
658 return false;
659 }
660
Romain Guy257ae352013-03-20 16:31:12 -0700661 initRender(clip, bounds, functor);
Romain Guy671d6cf2012-01-18 12:39:17 -0800662 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800663
664 if (forceFinish) {
665 finishRender();
666 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700667
668 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700669}
670
Chris Craikd218a922014-01-02 17:13:34 -0800671bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
672 uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
Chris Craik82840732015-04-03 09:37:49 -0700673 float hOffset, float vOffset, Rect* bounds, TextDrawFunctor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800674 if (!mCurrentFont) {
675 ALOGE("No font set");
676 return false;
677 }
678
Victoria Lease1e546812013-06-25 14:25:17 -0700679 initRender(clip, bounds, functor);
Romain Guy97771732012-02-28 18:17:02 -0800680 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
681 finishRender();
682
683 return mDrawn;
684}
685
Romain Guy9b1204b2012-09-04 15:22:57 -0700686void FontRenderer::removeFont(const Font* font) {
Romain Guye3a9b242013-01-08 11:15:30 -0800687 mActiveFonts.remove(font->getDescription());
Romain Guy9b1204b2012-09-04 15:22:57 -0700688
689 if (mCurrentFont == font) {
Chris Craikd41c4d82015-01-05 15:51:13 -0800690 mCurrentFont = nullptr;
Romain Guy9b1204b2012-09-04 15:22:57 -0700691 }
692}
693
Derek Sollenbergere392c812014-05-21 11:25:22 -0400694void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
695 uint32_t intRadius = Blur::convertRadiusToInt(radius);
Dan Morrille4d9a012013-03-28 18:10:43 -0700696#ifdef ANDROID_ENABLE_RENDERSCRIPT
Derek Sollenbergere392c812014-05-21 11:25:22 -0400697 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700698 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700699
Chris Craikd41c4d82015-01-05 15:51:13 -0800700 if (mRs == nullptr) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700701 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800702 // a null path is OK because there are no custom kernels used
703 // hence nothing gets cached by RS
704 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800705 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700706 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800707 } else {
708 mRsElement = RSC::Element::A_8(mRs);
709 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700710 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800711 }
Chris Craikd41c4d82015-01-05 15:51:13 -0800712 if (mRs != nullptr) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800713 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
714 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
715 RS_ALLOCATION_MIPMAP_NONE,
716 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
717 *image);
718 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
719 RS_ALLOCATION_MIPMAP_NONE,
720 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
721 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800722
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800723 mRsScript->setRadius(radius);
724 mRsScript->setInput(ain);
725 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700726
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800727 // replace the original image's pointer, avoiding a copy back to the original buffer
728 free(*image);
729 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700730
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800731 return;
732 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800733 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700734#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800735
Chris Craik51d6a3d2014-12-22 17:16:56 -0800736 std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
737 Blur::generateGaussianWeights(gaussian.get(), intRadius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800738
Chris Craik51d6a3d2014-12-22 17:16:56 -0800739 std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
740 Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
741 Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700742}
743
Victoria Lease1e546812013-06-25 14:25:17 -0700744static uint32_t calculateCacheSize(const Vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700745 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700746 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
747 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700748 if (cacheTexture && cacheTexture->getPixelBuffer()) {
749 size += cacheTexture->getPixelBuffer()->getSize();
750 }
751 }
752 return size;
753}
754
Victoria Lease1e546812013-06-25 14:25:17 -0700755uint32_t FontRenderer::getCacheSize(GLenum format) const {
756 switch (format) {
757 case GL_ALPHA: {
758 return calculateCacheSize(mACacheTextures);
759 }
760 case GL_RGBA: {
761 return calculateCacheSize(mRGBACacheTextures);
762 }
763 default: {
764 return 0;
765 }
766 }
767}
768
Romain Guy694b5192010-07-21 21:33:20 -0700769}; // namespace uirenderer
770}; // namespace android