blob: 75c3ead68f7becd85171c0944090336cbd53fda7 [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"
29#include "utils/Timing.h"
Romain Guy694b5192010-07-21 21:33:20 -070030
Chris Craik9db58c02015-08-19 15:19:18 -070031#include <algorithm>
32#include <cutils/properties.h>
Derek Sollenbergerca79cf62012-08-14 16:44:52 -040033#include <SkGlyph.h>
Romain Guy694b5192010-07-21 21:33:20 -070034#include <SkUtils.h>
Romain Guy51769a62010-07-23 00:28:00 -070035#include <utils/Log.h>
36
Dan Morrille4d9a012013-03-28 18:10:43 -070037#ifdef ANDROID_ENABLE_RENDERSCRIPT
Romain Guy6e200402013-03-08 11:28:22 -080038#include <RenderScript.h>
Dan Morrille4d9a012013-03-28 18:10:43 -070039#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -080040
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///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070050
Chris Craik82840732015-04-03 09:37:49 -070051void TextDrawFunctor::draw(CacheTexture& texture, bool linearFiltering) {
Chris Craik53e51e42015-06-01 10:35:35 -070052 int textureFillFlags = TextureFillFlags::None;
53 if (texture.getFormat() == GL_ALPHA) {
54 textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture;
Chris Craike2bb3802015-03-13 15:07:52 -070055 }
Chris Craik53e51e42015-06-01 10:35:35 -070056 if (linearFiltering) {
57 textureFillFlags |= TextureFillFlags::ForceFilter;
58 }
59 int transformFlags = pureTranslate
60 ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
Chris Craike2bb3802015-03-13 15:07:52 -070061 Glop glop;
62 GlopBuilder(renderer->mRenderState, renderer->mCaches, &glop)
63 .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
64 .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, renderer->currentSnapshot()->alpha)
Chris Craik53e51e42015-06-01 10:35:35 -070065 .setTransform(*(renderer->currentSnapshot()), transformFlags)
Chris Craike2bb3802015-03-13 15:07:52 -070066 .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
67 .setRoundRectClipState(renderer->currentSnapshot()->roundRectClipState)
68 .build();
69 renderer->renderGlop(glop);
Victoria Lease1e546812013-06-25 14:25:17 -070070}
71
72///////////////////////////////////////////////////////////////////////////////
Romain Guy694b5192010-07-21 21:33:20 -070073// FontRenderer
74///////////////////////////////////////////////////////////////////////////////
75
Romain Guy514fb182011-01-19 14:38:29 -080076static bool sLogFontRendererCreate = true;
77
Chris Craik083e7332015-02-27 17:04:20 -080078FontRenderer::FontRenderer()
79 : mGammaTable(nullptr)
80 , mCurrentFont(nullptr)
81 , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity)
82 , mCurrentCacheTexture(nullptr)
83 , mUploadTexture(false)
84 , mFunctor(nullptr)
85 , mClip(nullptr)
86 , mBounds(nullptr)
87 , mDrawn(false)
88 , mInitialized(false)
89 , mLinearFiltering(false) {
Romain Guye3a9b242013-01-08 11:15:30 -080090
Romain Guyc9855a52011-01-21 21:14:15 -080091 if (sLogFontRendererCreate) {
92 INIT_LOGD("Creating FontRenderer");
93 }
Romain Guy51769a62010-07-23 00:28:00 -070094
Chet Haaseeb32a492012-08-31 13:54:03 -070095 mSmallCacheWidth = DEFAULT_TEXT_SMALL_CACHE_WIDTH;
96 mSmallCacheHeight = DEFAULT_TEXT_SMALL_CACHE_HEIGHT;
97 mLargeCacheWidth = DEFAULT_TEXT_LARGE_CACHE_WIDTH;
98 mLargeCacheHeight = DEFAULT_TEXT_LARGE_CACHE_HEIGHT;
Romain Guy51769a62010-07-23 00:28:00 -070099
100 char property[PROPERTY_VALUE_MAX];
Chris Craikd41c4d82015-01-05 15:51:13 -0800101 if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, nullptr) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800102 mSmallCacheWidth = atoi(property);
Romain Guy51769a62010-07-23 00:28:00 -0700103 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700104
Chris Craikd41c4d82015-01-05 15:51:13 -0800105 if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, nullptr) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800106 mSmallCacheHeight = atoi(property);
Chet Haaseeb32a492012-08-31 13:54:03 -0700107 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700108
Chris Craikd41c4d82015-01-05 15:51:13 -0800109 if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, nullptr) > 0) {
Chet Haaseeb32a492012-08-31 13:54:03 -0700110 mLargeCacheWidth = atoi(property);
111 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700112
Chris Craikd41c4d82015-01-05 15:51:13 -0800113 if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, nullptr) > 0) {
Chet Haaseeb32a492012-08-31 13:54:03 -0700114 mLargeCacheHeight = atoi(property);
115 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700116
117 uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
Chris Craik083e7332015-02-27 17:04:20 -0800118
Chris Craik9db58c02015-08-19 15:19:18 -0700119 mSmallCacheWidth = std::min(mSmallCacheWidth, maxTextureSize);
120 mSmallCacheHeight = std::min(mSmallCacheHeight, maxTextureSize);
121 mLargeCacheWidth = std::min(mLargeCacheWidth, maxTextureSize);
122 mLargeCacheHeight = std::min(mLargeCacheHeight, maxTextureSize);
Romain Guy9f5dab32012-09-04 12:55:44 -0700123
Chet Haaseeb32a492012-08-31 13:54:03 -0700124 if (sLogFontRendererCreate) {
125 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
126 mSmallCacheWidth, mSmallCacheHeight,
127 mLargeCacheWidth, mLargeCacheHeight >> 1,
128 mLargeCacheWidth, mLargeCacheHeight >> 1,
129 mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700130 }
Romain Guy514fb182011-01-19 14:38:29 -0800131
132 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700133}
134
John Reck272a6852015-07-29 16:48:58 -0700135void clearCacheTextures(std::vector<CacheTexture*>& cacheTextures) {
Victoria Lease1e546812013-06-25 14:25:17 -0700136 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
137 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700138 }
Victoria Lease1e546812013-06-25 14:25:17 -0700139 cacheTextures.clear();
140}
141
142FontRenderer::~FontRenderer() {
143 clearCacheTextures(mACacheTextures);
144 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700145
Romain Guye3a9b242013-01-08 11:15:30 -0800146 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
147 while (it.next()) {
148 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700149 }
Romain Guye3a9b242013-01-08 11:15:30 -0800150 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700151}
152
153void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700154 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700155
Romain Guye3a9b242013-01-08 11:15:30 -0800156 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
157 while (it.next()) {
158 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700159 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700160
Victoria Lease1e546812013-06-25 14:25:17 -0700161 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
162 mACacheTextures[i]->init();
163 }
164
165 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
166 mRGBACacheTextures[i]->init();
Romain Guy694b5192010-07-21 21:33:20 -0700167 }
chaochen1f61b192014-08-28 18:45:27 -0700168
169 mDrawn = false;
Romain Guy694b5192010-07-21 21:33:20 -0700170}
171
John Reck272a6852015-07-29 16:48:58 -0700172void FontRenderer::flushLargeCaches(std::vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700173 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700174 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
175 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700176 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700177 cacheTexture->init();
Romain Guye3a9b242013-01-08 11:15:30 -0800178 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
179 while (it.next()) {
180 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700181 }
Chris Craike2bb3802015-03-13 15:07:52 -0700182 cacheTexture->releasePixelBuffer();
Chet Haase9a824562011-12-16 15:44:59 -0800183 }
184 }
Chet Haase9a824562011-12-16 15:44:59 -0800185}
186
Victoria Lease1e546812013-06-25 14:25:17 -0700187void FontRenderer::flushLargeCaches() {
188 flushLargeCaches(mACacheTextures);
189 flushLargeCaches(mRGBACacheTextures);
190}
191
John Reck272a6852015-07-29 16:48:58 -0700192CacheTexture* FontRenderer::cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700193 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
194 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
195 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
196 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700197 }
198 }
199 // Could not fit glyph into current cache textures
Chris Craikd41c4d82015-01-05 15:51:13 -0800200 return nullptr;
Chet Haase378e9192012-08-15 15:54:54 -0700201}
202
Chet Haase7de0cb12011-12-05 16:35:38 -0800203void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700204 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700205 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800206
207 // If the glyph bitmap is empty let's assum the glyph is valid
208 // so we can avoid doing extra work later on
209 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
210 cachedGlyph->mIsValid = true;
Chris Craikd41c4d82015-01-05 15:51:13 -0800211 cachedGlyph->mCacheTexture = nullptr;
Romain Guya4adcf02013-02-28 12:15:35 -0800212 return;
213 }
214
Chet Haase7de0cb12011-12-05 16:35:38 -0800215 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800216
Victoria Lease1e546812013-06-25 14:25:17 -0700217 // choose an appropriate cache texture list for this glyph format
218 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
John Reck272a6852015-07-29 16:48:58 -0700219 std::vector<CacheTexture*>* cacheTextures = nullptr;
Victoria Lease1e546812013-06-25 14:25:17 -0700220 switch (format) {
221 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700222 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700223 cacheTextures = &mACacheTextures;
224 break;
225 case SkMask::kARGB32_Format:
226 cacheTextures = &mRGBACacheTextures;
227 break;
228 default:
229#if DEBUG_FONT_RENDERER
230 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
231#endif
232 return;
233 }
234
Romain Guy694b5192010-07-21 21:33:20 -0700235 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700236 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700237 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700238 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
239 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800240 return;
Romain Guy694b5192010-07-21 21:33:20 -0700241 }
242
243 // Now copy the bitmap into the cache texture
244 uint32_t startX = 0;
245 uint32_t startY = 0;
246
Victoria Lease1e546812013-06-25 14:25:17 -0700247 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700248
Chet Haase378e9192012-08-15 15:54:54 -0700249 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700250 if (!precaching) {
251 // If the new glyph didn't fit and we are not just trying to precache it,
252 // clear out the cache and try again
253 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700254 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700255 }
Romain Guy694b5192010-07-21 21:33:20 -0700256
Chet Haase378e9192012-08-15 15:54:54 -0700257 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700258 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800259 return;
Romain Guy694b5192010-07-21 21:33:20 -0700260 }
261 }
262
Chet Haase378e9192012-08-15 15:54:54 -0700263 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800264
Romain Guy694b5192010-07-21 21:33:20 -0700265 *retOriginX = startX;
266 *retOriginY = startY;
267
268 uint32_t endX = startX + glyph.fWidth;
269 uint32_t endY = startY + glyph.fHeight;
270
Romain Guy80872462012-09-04 16:42:01 -0700271 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700272
Romain Guycf51a412013-04-08 19:40:31 -0700273 if (!cacheTexture->getPixelBuffer()) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800274 Caches::getInstance().textureState().activateTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800275 // Large-glyph texture memory is allocated only as needed
Chris Craike2bb3802015-03-13 15:07:52 -0700276 cacheTexture->allocatePixelBuffer();
Chet Haase7de0cb12011-12-05 16:35:38 -0800277 }
Romain Guy661a87e2013-03-19 15:24:36 -0700278 if (!cacheTexture->mesh()) {
279 cacheTexture->allocateMesh();
280 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700281
Romain Guycf51a412013-04-08 19:40:31 -0700282 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700283 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
284 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700285
Romain Guyb969a0d2013-02-05 14:38:40 -0800286 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800287 switch (format) {
288 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700289 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
290 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
291 - TEXTURE_BORDER_SIZE;
292 // write leading border line
293 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
294 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800295 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700296 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800297 row = cacheY * cacheWidth;
298 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800299 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
300 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800301 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800302 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800303 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800304 }
305 } else {
Victoria Lease1e546812013-06-25 14:25:17 -0700306 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800307 row = cacheY * cacheWidth;
308 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
309 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
310 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800311 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700312 }
Victoria Lease1e546812013-06-25 14:25:17 -0700313 // write trailing border line
314 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
315 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
316 break;
317 }
318 case SkMask::kARGB32_Format: {
319 // prep data lengths
320 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
321 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
322 size_t rowSize = formatSize * glyph.fWidth;
323 // prep advances
324 size_t dstStride = formatSize * cacheWidth;
325 // prep indices
326 // - we actually start one row early, and then increment before first copy
327 uint8_t* src = &bitmapBuffer[0 - srcStride];
328 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
329 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
330 uint8_t* dstL = dst - borderSize;
331 uint8_t* dstR = dst + rowSize;
332 // write leading border line
333 memset(dstL, 0, rowSize + 2 * borderSize);
334 // write glyph data
335 while (dst < dstEnd) {
336 memset(dstL += dstStride, 0, borderSize); // leading border column
337 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
338 memset(dstR += dstStride, 0, borderSize); // trailing border column
339 }
340 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700341 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800342 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700343 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800344 case SkMask::kBW_Format: {
Andreas Gampe1e196742014-11-10 15:23:43 -0800345 uint32_t cacheX = 0, cacheY = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700346 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
347 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800348 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700349 // write leading border line
350 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
351 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800352 for (cacheY = startY; cacheY < endY; cacheY++) {
353 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700354 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800355 uint8_t* buffer = bitmapBuffer;
356
Romain Guy0b58a3d2013-03-05 12:16:27 -0800357 row = cacheY * cacheWidth;
358 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800359 while (--rowBytes >= 0) {
360 uint8_t b = *buffer++;
361 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
362 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
363 }
364 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800365 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800366
Victoria Lease1e546812013-06-25 14:25:17 -0700367 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700368 }
Victoria Lease1e546812013-06-25 14:25:17 -0700369 // write trailing border line
370 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
371 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800372 break;
Romain Guy694b5192010-07-21 21:33:20 -0700373 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800374 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700375 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800376 break;
Romain Guy694b5192010-07-21 21:33:20 -0700377 }
Romain Guy97771732012-02-28 18:17:02 -0800378
Chet Haase7de0cb12011-12-05 16:35:38 -0800379 cachedGlyph->mIsValid = true;
Romain Guy694b5192010-07-21 21:33:20 -0700380}
381
Victoria Lease1e546812013-06-25 14:25:17 -0700382CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
383 bool allocate) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800384 CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700385
Chet Haase2a47c142011-12-14 15:22:56 -0800386 if (allocate) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800387 Caches::getInstance().textureState().activateTexture(0);
Chris Craike2bb3802015-03-13 15:07:52 -0700388 cacheTexture->allocatePixelBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700389 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800390 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700391
Chet Haase2a47c142011-12-14 15:22:56 -0800392 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800393}
394
395void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700396 clearCacheTextures(mACacheTextures);
397 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700398
Chet Haase7de0cb12011-12-05 16:35:38 -0800399 mUploadTexture = false;
John Reck272a6852015-07-29 16:48:58 -0700400 mACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700401 GL_ALPHA, true));
John Reck272a6852015-07-29 16:48:58 -0700402 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700403 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700404 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700405 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700406 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700407 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700408 mRGBACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700409 GL_RGBA, false));
John Reck272a6852015-07-29 16:48:58 -0700410 mRGBACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700411 GL_RGBA, false));
412 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700413}
414
Romain Guy694b5192010-07-21 21:33:20 -0700415// We don't want to allocate anything unless we actually draw text
416void FontRenderer::checkInit() {
417 if (mInitialized) {
418 return;
419 }
420
421 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700422
423 mInitialized = true;
424}
425
John Reck272a6852015-07-29 16:48:58 -0700426void checkTextureUpdateForCache(Caches& caches, std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700427 bool& resetPixelStore, GLuint& lastTextureId) {
428 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
429 CacheTexture* cacheTexture = cacheTextures[i];
430 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
431 if (cacheTexture->getTextureId() != lastTextureId) {
432 lastTextureId = cacheTexture->getTextureId();
Chris Craik44eb2c02015-01-29 09:45:09 -0800433 caches.textureState().activateTexture(0);
434 caches.textureState().bindTexture(lastTextureId);
Victoria Lease1e546812013-06-25 14:25:17 -0700435 }
436
437 if (cacheTexture->upload()) {
438 resetPixelStore = true;
439 }
440 }
441 }
442}
443
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700444void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900445 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700446 return;
Romain Guy694b5192010-07-21 21:33:20 -0700447 }
448
Romain Guy2d4fd362011-12-13 22:00:19 -0800449 Caches& caches = Caches::getInstance();
450 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700451
Romain Guycf51a412013-04-08 19:40:31 -0700452 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700453 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
454
Chet Haase378e9192012-08-15 15:54:54 -0700455 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700456 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
457 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700458
Romain Guycf51a412013-04-08 19:40:31 -0700459 // Unbind any PBO we might have used to update textures
Chris Craik44eb2c02015-01-29 09:45:09 -0800460 caches.pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700461
Romain Guy09087642013-04-04 12:27:54 -0700462 // Reset to default unpack row length to avoid affecting texture
463 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700464 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700465 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
466 }
467
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700468 mUploadTexture = false;
469}
470
John Reck272a6852015-07-29 16:48:58 -0700471void FontRenderer::issueDrawCommand(std::vector<CacheTexture*>& cacheTextures) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800472 if (!mFunctor) return;
473
Romain Guy661a87e2013-03-19 15:24:36 -0700474 bool first = true;
Victoria Lease1e546812013-06-25 14:25:17 -0700475 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
476 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700477 if (texture->canDraw()) {
478 if (first) {
Chris Craike2bb3802015-03-13 15:07:52 -0700479 checkTextureUpdate();
Romain Guy661a87e2013-03-19 15:24:36 -0700480 first = false;
Chris Craik083e7332015-02-27 17:04:20 -0800481 mDrawn = true;
Romain Guy661a87e2013-03-19 15:24:36 -0700482 }
Chris Craik82840732015-04-03 09:37:49 -0700483
Chris Craike2bb3802015-03-13 15:07:52 -0700484 mFunctor->draw(*texture, mLinearFiltering);
Romain Guy661a87e2013-03-19 15:24:36 -0700485
Romain Guy661a87e2013-03-19 15:24:36 -0700486 texture->resetMesh();
Romain Guy115096f2013-03-19 11:32:41 -0700487 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900488 }
Victoria Lease1e546812013-06-25 14:25:17 -0700489}
490
491void FontRenderer::issueDrawCommand() {
492 issueDrawCommand(mACacheTextures);
493 issueDrawCommand(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700494}
495
Romain Guy97771732012-02-28 18:17:02 -0800496void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
497 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800498 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800499 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800500 // Now use the new texture id
501 mCurrentCacheTexture = texture;
502 }
Romain Guy09147fb2010-07-22 13:08:20 -0700503
Romain Guy661a87e2013-03-19 15:24:36 -0700504 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
505 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800506}
507
508void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
509 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
510 float x4, float y4, float u4, float v4, CacheTexture* texture) {
511
512 if (mClip &&
513 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
514 return;
515 }
516
517 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 -0700518
Romain Guy5b3b3522010-10-27 18:57:51 -0700519 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700520 mBounds->left = std::min(mBounds->left, x1);
521 mBounds->top = std::min(mBounds->top, y3);
522 mBounds->right = std::max(mBounds->right, x3);
523 mBounds->bottom = std::max(mBounds->bottom, y1);
Romain Guy5b3b3522010-10-27 18:57:51 -0700524 }
525
Romain Guy661a87e2013-03-19 15:24:36 -0700526 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700527 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700528 }
529}
530
Romain Guy97771732012-02-28 18:17:02 -0800531void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
532 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
533 float x4, float y4, float u4, float v4, CacheTexture* texture) {
534
535 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
536
537 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700538 mBounds->left = std::min(mBounds->left, std::min(x1, std::min(x2, std::min(x3, x4))));
539 mBounds->top = std::min(mBounds->top, std::min(y1, std::min(y2, std::min(y3, y4))));
540 mBounds->right = std::max(mBounds->right, std::max(x1, std::max(x2, std::max(x3, x4))));
541 mBounds->bottom = std::max(mBounds->bottom, std::max(y1, std::max(y2, std::max(y3, y4))));
Romain Guy97771732012-02-28 18:17:02 -0800542 }
543
Romain Guy661a87e2013-03-19 15:24:36 -0700544 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800545 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800546 }
547}
548
Chris Craik59744b72014-07-01 17:56:52 -0700549void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800550 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700551}
Romain Guy7975fb62010-10-01 16:36:14 -0700552
Chris Craikd218a922014-01-02 17:13:34 -0800553FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const char *text,
Derek Sollenbergere392c812014-05-21 11:25:22 -0400554 uint32_t startIndex, uint32_t len, int numGlyphs, float radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700555 checkInit();
556
Romain Guycf51a412013-04-08 19:40:31 -0700557 DropShadow image;
558 image.width = 0;
559 image.height = 0;
Chris Craikd41c4d82015-01-05 15:51:13 -0800560 image.image = nullptr;
Romain Guycf51a412013-04-08 19:40:31 -0700561 image.penX = 0;
562 image.penY = 0;
563
Romain Guy1e45aae2010-08-13 19:39:53 -0700564 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700565 return image;
566 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700567
Romain Guy2d4fd362011-12-13 22:00:19 -0800568 mDrawn = false;
Chris Craikd41c4d82015-01-05 15:51:13 -0800569 mClip = nullptr;
570 mBounds = nullptr;
Romain Guyff98fa52011-11-28 09:35:09 -0800571
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700572 Rect bounds;
Raph Levien416a8472012-07-19 22:48:17 -0700573 mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800574
Derek Sollenbergere392c812014-05-21 11:25:22 -0400575 uint32_t intRadius = Blur::convertRadiusToInt(radius);
576 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
577 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
Romain Guyff98fa52011-11-28 09:35:09 -0800578
Romain Guycf51a412013-04-08 19:40:31 -0700579 uint32_t maxSize = Caches::getInstance().maxTextureSize;
580 if (paddedWidth > maxSize || paddedHeight > maxSize) {
581 return image;
582 }
583
Dan Morrille4d9a012013-03-28 18:10:43 -0700584#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800585 // Align buffers for renderscript usage
586 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
587 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700588 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800589 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800590 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700591#else
592 int size = paddedWidth * paddedHeight;
593 uint8_t* dataBuffer = (uint8_t*) malloc(size);
594#endif
595
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800596 memset(dataBuffer, 0, size);
597
Derek Sollenbergere392c812014-05-21 11:25:22 -0400598 int penX = intRadius - bounds.left;
599 int penY = intRadius - bounds.bottom;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700600
Chris Craikdd8697c2013-02-22 10:41:36 -0800601 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
602 // text has non-whitespace, so draw and blur to create the shadow
603 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
604 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
605 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
Chris Craikd41c4d82015-01-05 15:51:13 -0800606 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
Chris Craikdd8697c2013-02-22 10:41:36 -0800607
Romain Guycf51a412013-04-08 19:40:31 -0700608 // Unbind any PBO we might have used
Chris Craik44eb2c02015-01-29 09:45:09 -0800609 Caches::getInstance().pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700610
Chris Craikdd8697c2013-02-22 10:41:36 -0800611 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
612 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700613
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700614 image.width = paddedWidth;
615 image.height = paddedHeight;
616 image.image = dataBuffer;
617 image.penX = penX;
618 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800619
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700620 return image;
621}
Romain Guy694b5192010-07-21 21:33:20 -0700622
Chris Craik82840732015-04-03 09:37:49 -0700623void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextDrawFunctor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700624 checkInit();
625
Romain Guy5b3b3522010-10-27 18:57:51 -0700626 mDrawn = false;
627 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700628 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700629 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800630}
Romain Guyff98fa52011-11-28 09:35:09 -0800631
Romain Guy671d6cf2012-01-18 12:39:17 -0800632void FontRenderer::finishRender() {
Chris Craikd41c4d82015-01-05 15:51:13 -0800633 mBounds = nullptr;
634 mClip = nullptr;
Romain Guy694b5192010-07-21 21:33:20 -0700635
Romain Guy661a87e2013-03-19 15:24:36 -0700636 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800637}
638
Chris Craikd218a922014-01-02 17:13:34 -0800639void FontRenderer::precache(const SkPaint* paint, const char* text, int numGlyphs,
Chris Craik59744b72014-07-01 17:56:52 -0700640 const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800641 Font* font = Font::create(this, paint, matrix);
Chet Haasee816bae2012-08-09 13:39:02 -0700642 font->precache(paint, text, numGlyphs);
643}
644
Romain Guycf51a412013-04-08 19:40:31 -0700645void FontRenderer::endPrecaching() {
646 checkTextureUpdate();
647}
648
Chris Craikd218a922014-01-02 17:13:34 -0800649bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
Romain Guy671d6cf2012-01-18 12:39:17 -0800650 uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
Chris Craik82840732015-04-03 09:37:49 -0700651 const float* positions, Rect* bounds, TextDrawFunctor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800652 if (!mCurrentFont) {
653 ALOGE("No font set");
654 return false;
655 }
656
Romain Guy257ae352013-03-20 16:31:12 -0700657 initRender(clip, bounds, functor);
Romain Guy671d6cf2012-01-18 12:39:17 -0800658 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800659
660 if (forceFinish) {
661 finishRender();
662 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700663
664 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700665}
666
Chris Craikd218a922014-01-02 17:13:34 -0800667bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
668 uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
Chris Craik82840732015-04-03 09:37:49 -0700669 float hOffset, float vOffset, Rect* bounds, TextDrawFunctor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800670 if (!mCurrentFont) {
671 ALOGE("No font set");
672 return false;
673 }
674
Victoria Lease1e546812013-06-25 14:25:17 -0700675 initRender(clip, bounds, functor);
Romain Guy97771732012-02-28 18:17:02 -0800676 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
677 finishRender();
678
679 return mDrawn;
680}
681
Romain Guy9b1204b2012-09-04 15:22:57 -0700682void FontRenderer::removeFont(const Font* font) {
Romain Guye3a9b242013-01-08 11:15:30 -0800683 mActiveFonts.remove(font->getDescription());
Romain Guy9b1204b2012-09-04 15:22:57 -0700684
685 if (mCurrentFont == font) {
Chris Craikd41c4d82015-01-05 15:51:13 -0800686 mCurrentFont = nullptr;
Romain Guy9b1204b2012-09-04 15:22:57 -0700687 }
688}
689
Derek Sollenbergere392c812014-05-21 11:25:22 -0400690void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
691 uint32_t intRadius = Blur::convertRadiusToInt(radius);
Dan Morrille4d9a012013-03-28 18:10:43 -0700692#ifdef ANDROID_ENABLE_RENDERSCRIPT
Derek Sollenbergere392c812014-05-21 11:25:22 -0400693 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700694 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700695
Chris Craikd41c4d82015-01-05 15:51:13 -0800696 if (mRs == nullptr) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700697 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800698 // a null path is OK because there are no custom kernels used
699 // hence nothing gets cached by RS
700 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800701 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700702 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800703 } else {
704 mRsElement = RSC::Element::A_8(mRs);
705 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700706 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800707 }
Chris Craikd41c4d82015-01-05 15:51:13 -0800708 if (mRs != nullptr) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800709 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
710 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
711 RS_ALLOCATION_MIPMAP_NONE,
712 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
713 *image);
714 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
715 RS_ALLOCATION_MIPMAP_NONE,
716 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
717 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800718
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800719 mRsScript->setRadius(radius);
720 mRsScript->setInput(ain);
721 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700722
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800723 // replace the original image's pointer, avoiding a copy back to the original buffer
724 free(*image);
725 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700726
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800727 return;
728 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800729 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700730#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800731
Chris Craik51d6a3d2014-12-22 17:16:56 -0800732 std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
huanhuan.x.wanga46ca5e2015-04-14 16:23:15 +0200733 Blur::generateGaussianWeights(gaussian.get(), radius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800734
Chris Craik51d6a3d2014-12-22 17:16:56 -0800735 std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
736 Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
737 Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700738}
739
John Reck272a6852015-07-29 16:48:58 -0700740static uint32_t calculateCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700741 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700742 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
743 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700744 if (cacheTexture && cacheTexture->getPixelBuffer()) {
745 size += cacheTexture->getPixelBuffer()->getSize();
746 }
747 }
748 return size;
749}
750
Victoria Lease1e546812013-06-25 14:25:17 -0700751uint32_t FontRenderer::getCacheSize(GLenum format) const {
752 switch (format) {
753 case GL_ALPHA: {
754 return calculateCacheSize(mACacheTextures);
755 }
756 case GL_RGBA: {
757 return calculateCacheSize(mRGBACacheTextures);
758 }
759 default: {
760 return 0;
761 }
762 }
763}
764
Romain Guy694b5192010-07-21 21:33:20 -0700765}; // namespace uirenderer
766}; // namespace android