blob: 47654f400ec26f897c79bf1a88a667a68b18ec9a [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 "PixelBuffer.h"
25#include "Rect.h"
26#include "renderstate/RenderState.h"
27#include "utils/Blur.h"
28#include "utils/Timing.h"
Romain Guy694b5192010-07-21 21:33:20 -070029
Chris Craika1717272015-11-19 13:02:43 -080030
31#if HWUI_NEW_OPS
Chris Craik9e7fcfd2015-11-25 13:27:33 -080032#include "BakedOpDispatcher.h"
Chris Craika1717272015-11-19 13:02:43 -080033#include "BakedOpRenderer.h"
Chris Craik9e7fcfd2015-11-25 13:27:33 -080034#include "BakedOpState.h"
Chris Craika1717272015-11-19 13:02:43 -080035#else
36#include "OpenGLRenderer.h"
37#endif
38
Chris Craik9db58c02015-08-19 15:19:18 -070039#include <algorithm>
40#include <cutils/properties.h>
Derek Sollenbergerca79cf62012-08-14 16:44:52 -040041#include <SkGlyph.h>
Romain Guy694b5192010-07-21 21:33:20 -070042#include <SkUtils.h>
Romain Guy51769a62010-07-23 00:28:00 -070043#include <utils/Log.h>
44
Dan Morrille4d9a012013-03-28 18:10:43 -070045#ifdef ANDROID_ENABLE_RENDERSCRIPT
Romain Guy6e200402013-03-08 11:28:22 -080046#include <RenderScript.h>
Dan Morrille4d9a012013-03-28 18:10:43 -070047#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -080048
Romain Guy694b5192010-07-21 21:33:20 -070049namespace android {
50namespace uirenderer {
51
Chris Craikf2d8ccc2013-02-13 16:14:17 -080052// blur inputs smaller than this constant will bypass renderscript
53#define RS_MIN_INPUT_CUTOFF 10000
54
Romain Guy694b5192010-07-21 21:33:20 -070055///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070056// TextSetupFunctor
57///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070058
Chris Craik82840732015-04-03 09:37:49 -070059void TextDrawFunctor::draw(CacheTexture& texture, bool linearFiltering) {
Chris Craik53e51e42015-06-01 10:35:35 -070060 int textureFillFlags = TextureFillFlags::None;
61 if (texture.getFormat() == GL_ALPHA) {
62 textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture;
Chris Craike2bb3802015-03-13 15:07:52 -070063 }
Chris Craik53e51e42015-06-01 10:35:35 -070064 if (linearFiltering) {
65 textureFillFlags |= TextureFillFlags::ForceFilter;
66 }
67 int transformFlags = pureTranslate
68 ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
Chris Craike2bb3802015-03-13 15:07:52 -070069 Glop glop;
Chris Craika1717272015-11-19 13:02:43 -080070#if HWUI_NEW_OPS
71 GlopBuilder(renderer->renderState(), renderer->caches(), &glop)
72 .setRoundRectClipState(bakedState->roundRectClipState)
73 .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
74 .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, bakedState->alpha)
75 .setTransform(bakedState->computedState.transform, transformFlags)
76 .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
77 .build();
78 renderer->renderGlop(*bakedState, glop);
79#else
Chris Craike2bb3802015-03-13 15:07:52 -070080 GlopBuilder(renderer->mRenderState, renderer->mCaches, &glop)
Chris Craika1717272015-11-19 13:02:43 -080081 .setRoundRectClipState(renderer->currentSnapshot()->roundRectClipState)
Chris Craike2bb3802015-03-13 15:07:52 -070082 .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
83 .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, renderer->currentSnapshot()->alpha)
Chris Craik53e51e42015-06-01 10:35:35 -070084 .setTransform(*(renderer->currentSnapshot()), transformFlags)
Chris Craike2bb3802015-03-13 15:07:52 -070085 .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
Chris Craike2bb3802015-03-13 15:07:52 -070086 .build();
87 renderer->renderGlop(glop);
Chris Craika1717272015-11-19 13:02:43 -080088#endif
Victoria Lease1e546812013-06-25 14:25:17 -070089}
90
91///////////////////////////////////////////////////////////////////////////////
Romain Guy694b5192010-07-21 21:33:20 -070092// FontRenderer
93///////////////////////////////////////////////////////////////////////////////
94
Romain Guy514fb182011-01-19 14:38:29 -080095static bool sLogFontRendererCreate = true;
96
Chris Craikc08820f2015-09-22 14:22:29 -070097FontRenderer::FontRenderer(const uint8_t* gammaTable)
98 : mGammaTable(gammaTable)
Chris Craik083e7332015-02-27 17:04:20 -080099 , mCurrentFont(nullptr)
100 , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity)
101 , mCurrentCacheTexture(nullptr)
102 , mUploadTexture(false)
103 , mFunctor(nullptr)
104 , mClip(nullptr)
105 , mBounds(nullptr)
106 , mDrawn(false)
107 , mInitialized(false)
108 , mLinearFiltering(false) {
Romain Guye3a9b242013-01-08 11:15:30 -0800109
Romain Guyc9855a52011-01-21 21:14:15 -0800110 if (sLogFontRendererCreate) {
111 INIT_LOGD("Creating FontRenderer");
112 }
Romain Guy51769a62010-07-23 00:28:00 -0700113
Chris Craikc08820f2015-09-22 14:22:29 -0700114 mSmallCacheWidth = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_WIDTH,
115 DEFAULT_TEXT_SMALL_CACHE_WIDTH);
116 mSmallCacheHeight = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_HEIGHT,
117 DEFAULT_TEXT_SMALL_CACHE_HEIGHT);
Romain Guy51769a62010-07-23 00:28:00 -0700118
Chris Craikc08820f2015-09-22 14:22:29 -0700119 mLargeCacheWidth = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_WIDTH,
120 DEFAULT_TEXT_LARGE_CACHE_WIDTH);
121 mLargeCacheHeight = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_HEIGHT,
122 DEFAULT_TEXT_LARGE_CACHE_HEIGHT);
Romain Guy9f5dab32012-09-04 12:55:44 -0700123
124 uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
Chris Craik083e7332015-02-27 17:04:20 -0800125
Chris Craik9db58c02015-08-19 15:19:18 -0700126 mSmallCacheWidth = std::min(mSmallCacheWidth, maxTextureSize);
127 mSmallCacheHeight = std::min(mSmallCacheHeight, maxTextureSize);
128 mLargeCacheWidth = std::min(mLargeCacheWidth, maxTextureSize);
129 mLargeCacheHeight = std::min(mLargeCacheHeight, maxTextureSize);
Romain Guy9f5dab32012-09-04 12:55:44 -0700130
Chet Haaseeb32a492012-08-31 13:54:03 -0700131 if (sLogFontRendererCreate) {
132 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
133 mSmallCacheWidth, mSmallCacheHeight,
134 mLargeCacheWidth, mLargeCacheHeight >> 1,
135 mLargeCacheWidth, mLargeCacheHeight >> 1,
136 mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700137 }
Romain Guy514fb182011-01-19 14:38:29 -0800138
139 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700140}
141
John Reck272a6852015-07-29 16:48:58 -0700142void clearCacheTextures(std::vector<CacheTexture*>& cacheTextures) {
Victoria Lease1e546812013-06-25 14:25:17 -0700143 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
144 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700145 }
Victoria Lease1e546812013-06-25 14:25:17 -0700146 cacheTextures.clear();
147}
148
149FontRenderer::~FontRenderer() {
150 clearCacheTextures(mACacheTextures);
151 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700152
Romain Guye3a9b242013-01-08 11:15:30 -0800153 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
154 while (it.next()) {
155 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700156 }
Romain Guye3a9b242013-01-08 11:15:30 -0800157 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700158}
159
160void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700161 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700162
Romain Guye3a9b242013-01-08 11:15:30 -0800163 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
164 while (it.next()) {
165 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700166 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700167
Victoria Lease1e546812013-06-25 14:25:17 -0700168 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
169 mACacheTextures[i]->init();
170 }
171
172 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
173 mRGBACacheTextures[i]->init();
Romain Guy694b5192010-07-21 21:33:20 -0700174 }
chaochen1f61b192014-08-28 18:45:27 -0700175
176 mDrawn = false;
Romain Guy694b5192010-07-21 21:33:20 -0700177}
178
John Reck272a6852015-07-29 16:48:58 -0700179void FontRenderer::flushLargeCaches(std::vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700180 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700181 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
182 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700183 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700184 cacheTexture->init();
Romain Guye3a9b242013-01-08 11:15:30 -0800185 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
186 while (it.next()) {
187 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700188 }
Chris Craike2bb3802015-03-13 15:07:52 -0700189 cacheTexture->releasePixelBuffer();
Chet Haase9a824562011-12-16 15:44:59 -0800190 }
191 }
Chet Haase9a824562011-12-16 15:44:59 -0800192}
193
Victoria Lease1e546812013-06-25 14:25:17 -0700194void FontRenderer::flushLargeCaches() {
195 flushLargeCaches(mACacheTextures);
196 flushLargeCaches(mRGBACacheTextures);
197}
198
John Reck272a6852015-07-29 16:48:58 -0700199CacheTexture* FontRenderer::cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700200 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
201 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
202 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
203 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700204 }
205 }
206 // Could not fit glyph into current cache textures
Chris Craikd41c4d82015-01-05 15:51:13 -0800207 return nullptr;
Chet Haase378e9192012-08-15 15:54:54 -0700208}
209
Chet Haase7de0cb12011-12-05 16:35:38 -0800210void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700211 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700212 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800213
214 // If the glyph bitmap is empty let's assum the glyph is valid
215 // so we can avoid doing extra work later on
216 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
217 cachedGlyph->mIsValid = true;
Chris Craikd41c4d82015-01-05 15:51:13 -0800218 cachedGlyph->mCacheTexture = nullptr;
Romain Guya4adcf02013-02-28 12:15:35 -0800219 return;
220 }
221
Chet Haase7de0cb12011-12-05 16:35:38 -0800222 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800223
Victoria Lease1e546812013-06-25 14:25:17 -0700224 // choose an appropriate cache texture list for this glyph format
225 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
John Reck272a6852015-07-29 16:48:58 -0700226 std::vector<CacheTexture*>* cacheTextures = nullptr;
Victoria Lease1e546812013-06-25 14:25:17 -0700227 switch (format) {
228 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700229 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700230 cacheTextures = &mACacheTextures;
231 break;
232 case SkMask::kARGB32_Format:
233 cacheTextures = &mRGBACacheTextures;
234 break;
235 default:
236#if DEBUG_FONT_RENDERER
237 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
238#endif
239 return;
240 }
241
Romain Guy694b5192010-07-21 21:33:20 -0700242 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700243 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700244 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700245 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
246 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800247 return;
Romain Guy694b5192010-07-21 21:33:20 -0700248 }
249
250 // Now copy the bitmap into the cache texture
251 uint32_t startX = 0;
252 uint32_t startY = 0;
253
Victoria Lease1e546812013-06-25 14:25:17 -0700254 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700255
Chet Haase378e9192012-08-15 15:54:54 -0700256 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700257 if (!precaching) {
258 // If the new glyph didn't fit and we are not just trying to precache it,
259 // clear out the cache and try again
260 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700261 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700262 }
Romain Guy694b5192010-07-21 21:33:20 -0700263
Chet Haase378e9192012-08-15 15:54:54 -0700264 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700265 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800266 return;
Romain Guy694b5192010-07-21 21:33:20 -0700267 }
268 }
269
Chet Haase378e9192012-08-15 15:54:54 -0700270 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800271
Romain Guy694b5192010-07-21 21:33:20 -0700272 *retOriginX = startX;
273 *retOriginY = startY;
274
275 uint32_t endX = startX + glyph.fWidth;
276 uint32_t endY = startY + glyph.fHeight;
277
Romain Guy80872462012-09-04 16:42:01 -0700278 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700279
Romain Guycf51a412013-04-08 19:40:31 -0700280 if (!cacheTexture->getPixelBuffer()) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800281 Caches::getInstance().textureState().activateTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800282 // Large-glyph texture memory is allocated only as needed
Chris Craike2bb3802015-03-13 15:07:52 -0700283 cacheTexture->allocatePixelBuffer();
Chet Haase7de0cb12011-12-05 16:35:38 -0800284 }
Romain Guy661a87e2013-03-19 15:24:36 -0700285 if (!cacheTexture->mesh()) {
286 cacheTexture->allocateMesh();
287 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700288
Romain Guycf51a412013-04-08 19:40:31 -0700289 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700290 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
291 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700292
Romain Guyb969a0d2013-02-05 14:38:40 -0800293 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800294 switch (format) {
295 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700296 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
297 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
298 - TEXTURE_BORDER_SIZE;
299 // write leading border line
300 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
301 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800302 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700303 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800304 row = cacheY * cacheWidth;
305 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800306 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
307 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800308 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800309 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800310 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800311 }
312 } else {
Victoria Lease1e546812013-06-25 14:25:17 -0700313 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800314 row = cacheY * cacheWidth;
315 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
316 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
317 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800318 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700319 }
Victoria Lease1e546812013-06-25 14:25:17 -0700320 // write trailing border line
321 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
322 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
323 break;
324 }
325 case SkMask::kARGB32_Format: {
326 // prep data lengths
327 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
328 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
329 size_t rowSize = formatSize * glyph.fWidth;
330 // prep advances
331 size_t dstStride = formatSize * cacheWidth;
332 // prep indices
333 // - we actually start one row early, and then increment before first copy
334 uint8_t* src = &bitmapBuffer[0 - srcStride];
335 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
336 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
337 uint8_t* dstL = dst - borderSize;
338 uint8_t* dstR = dst + rowSize;
339 // write leading border line
340 memset(dstL, 0, rowSize + 2 * borderSize);
341 // write glyph data
342 while (dst < dstEnd) {
343 memset(dstL += dstStride, 0, borderSize); // leading border column
344 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
345 memset(dstR += dstStride, 0, borderSize); // trailing border column
346 }
347 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700348 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800349 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700350 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800351 case SkMask::kBW_Format: {
Andreas Gampe1e196742014-11-10 15:23:43 -0800352 uint32_t cacheX = 0, cacheY = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700353 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
354 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800355 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700356 // write leading border line
357 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
358 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800359 for (cacheY = startY; cacheY < endY; cacheY++) {
360 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700361 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800362 uint8_t* buffer = bitmapBuffer;
363
Romain Guy0b58a3d2013-03-05 12:16:27 -0800364 row = cacheY * cacheWidth;
365 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800366 while (--rowBytes >= 0) {
367 uint8_t b = *buffer++;
368 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
369 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
370 }
371 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800372 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800373
Victoria Lease1e546812013-06-25 14:25:17 -0700374 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700375 }
Victoria Lease1e546812013-06-25 14:25:17 -0700376 // write trailing border line
377 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
378 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800379 break;
Romain Guy694b5192010-07-21 21:33:20 -0700380 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800381 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700382 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800383 break;
Romain Guy694b5192010-07-21 21:33:20 -0700384 }
Romain Guy97771732012-02-28 18:17:02 -0800385
Chet Haase7de0cb12011-12-05 16:35:38 -0800386 cachedGlyph->mIsValid = true;
Romain Guy694b5192010-07-21 21:33:20 -0700387}
388
Victoria Lease1e546812013-06-25 14:25:17 -0700389CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
390 bool allocate) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800391 CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700392
Chet Haase2a47c142011-12-14 15:22:56 -0800393 if (allocate) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800394 Caches::getInstance().textureState().activateTexture(0);
Chris Craike2bb3802015-03-13 15:07:52 -0700395 cacheTexture->allocatePixelBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700396 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800397 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700398
Chet Haase2a47c142011-12-14 15:22:56 -0800399 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800400}
401
402void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700403 clearCacheTextures(mACacheTextures);
404 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700405
Chet Haase7de0cb12011-12-05 16:35:38 -0800406 mUploadTexture = false;
John Reck272a6852015-07-29 16:48:58 -0700407 mACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700408 GL_ALPHA, true));
John Reck272a6852015-07-29 16:48:58 -0700409 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700410 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700411 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700412 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700413 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700414 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700415 mRGBACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700416 GL_RGBA, false));
John Reck272a6852015-07-29 16:48:58 -0700417 mRGBACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700418 GL_RGBA, false));
419 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700420}
421
Romain Guy694b5192010-07-21 21:33:20 -0700422// We don't want to allocate anything unless we actually draw text
423void FontRenderer::checkInit() {
424 if (mInitialized) {
425 return;
426 }
427
428 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700429
430 mInitialized = true;
431}
432
John Reck272a6852015-07-29 16:48:58 -0700433void checkTextureUpdateForCache(Caches& caches, std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700434 bool& resetPixelStore, GLuint& lastTextureId) {
435 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
436 CacheTexture* cacheTexture = cacheTextures[i];
437 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
438 if (cacheTexture->getTextureId() != lastTextureId) {
439 lastTextureId = cacheTexture->getTextureId();
Chris Craik44eb2c02015-01-29 09:45:09 -0800440 caches.textureState().activateTexture(0);
441 caches.textureState().bindTexture(lastTextureId);
Victoria Lease1e546812013-06-25 14:25:17 -0700442 }
443
444 if (cacheTexture->upload()) {
445 resetPixelStore = true;
446 }
447 }
448 }
449}
450
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700451void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900452 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700453 return;
Romain Guy694b5192010-07-21 21:33:20 -0700454 }
455
Romain Guy2d4fd362011-12-13 22:00:19 -0800456 Caches& caches = Caches::getInstance();
457 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700458
Romain Guycf51a412013-04-08 19:40:31 -0700459 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700460 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
461
Chet Haase378e9192012-08-15 15:54:54 -0700462 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700463 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
464 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700465
Romain Guycf51a412013-04-08 19:40:31 -0700466 // Unbind any PBO we might have used to update textures
Chris Craik44eb2c02015-01-29 09:45:09 -0800467 caches.pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700468
Romain Guy09087642013-04-04 12:27:54 -0700469 // Reset to default unpack row length to avoid affecting texture
470 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700471 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700472 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
473 }
474
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700475 mUploadTexture = false;
476}
477
John Reck272a6852015-07-29 16:48:58 -0700478void FontRenderer::issueDrawCommand(std::vector<CacheTexture*>& cacheTextures) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800479 if (!mFunctor) return;
480
Romain Guy661a87e2013-03-19 15:24:36 -0700481 bool first = true;
Victoria Lease1e546812013-06-25 14:25:17 -0700482 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
483 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700484 if (texture->canDraw()) {
485 if (first) {
Chris Craike2bb3802015-03-13 15:07:52 -0700486 checkTextureUpdate();
Romain Guy661a87e2013-03-19 15:24:36 -0700487 first = false;
Chris Craik083e7332015-02-27 17:04:20 -0800488 mDrawn = true;
Romain Guy661a87e2013-03-19 15:24:36 -0700489 }
Chris Craik82840732015-04-03 09:37:49 -0700490
Chris Craike2bb3802015-03-13 15:07:52 -0700491 mFunctor->draw(*texture, mLinearFiltering);
Romain Guy661a87e2013-03-19 15:24:36 -0700492
Romain Guy661a87e2013-03-19 15:24:36 -0700493 texture->resetMesh();
Romain Guy115096f2013-03-19 11:32:41 -0700494 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900495 }
Victoria Lease1e546812013-06-25 14:25:17 -0700496}
497
498void FontRenderer::issueDrawCommand() {
499 issueDrawCommand(mACacheTextures);
500 issueDrawCommand(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700501}
502
Romain Guy97771732012-02-28 18:17:02 -0800503void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
504 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800505 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800506 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800507 // Now use the new texture id
508 mCurrentCacheTexture = texture;
509 }
Romain Guy09147fb2010-07-22 13:08:20 -0700510
Romain Guy661a87e2013-03-19 15:24:36 -0700511 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
512 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800513}
514
515void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
516 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
517 float x4, float y4, float u4, float v4, CacheTexture* texture) {
518
519 if (mClip &&
520 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
521 return;
522 }
523
524 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 -0700525
Romain Guy5b3b3522010-10-27 18:57:51 -0700526 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700527 mBounds->left = std::min(mBounds->left, x1);
528 mBounds->top = std::min(mBounds->top, y3);
529 mBounds->right = std::max(mBounds->right, x3);
530 mBounds->bottom = std::max(mBounds->bottom, y1);
Romain Guy5b3b3522010-10-27 18:57:51 -0700531 }
532
Romain Guy661a87e2013-03-19 15:24:36 -0700533 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700534 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700535 }
536}
537
Romain Guy97771732012-02-28 18:17:02 -0800538void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
539 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
540 float x4, float y4, float u4, float v4, CacheTexture* texture) {
541
542 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
543
544 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700545 mBounds->left = std::min(mBounds->left, std::min(x1, std::min(x2, std::min(x3, x4))));
546 mBounds->top = std::min(mBounds->top, std::min(y1, std::min(y2, std::min(y3, y4))));
547 mBounds->right = std::max(mBounds->right, std::max(x1, std::max(x2, std::max(x3, x4))));
548 mBounds->bottom = std::max(mBounds->bottom, std::max(y1, std::max(y2, std::max(y3, y4))));
Romain Guy97771732012-02-28 18:17:02 -0800549 }
550
Romain Guy661a87e2013-03-19 15:24:36 -0700551 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800552 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800553 }
554}
555
Chris Craik59744b72014-07-01 17:56:52 -0700556void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800557 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700558}
Romain Guy7975fb62010-10-01 16:36:14 -0700559
Chris Craikd218a922014-01-02 17:13:34 -0800560FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const char *text,
Chris Craika1717272015-11-19 13:02:43 -0800561 int numGlyphs, float radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700562 checkInit();
563
Romain Guycf51a412013-04-08 19:40:31 -0700564 DropShadow image;
565 image.width = 0;
566 image.height = 0;
Chris Craikd41c4d82015-01-05 15:51:13 -0800567 image.image = nullptr;
Romain Guycf51a412013-04-08 19:40:31 -0700568 image.penX = 0;
569 image.penY = 0;
570
Romain Guy1e45aae2010-08-13 19:39:53 -0700571 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700572 return image;
573 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700574
Romain Guy2d4fd362011-12-13 22:00:19 -0800575 mDrawn = false;
Chris Craikd41c4d82015-01-05 15:51:13 -0800576 mClip = nullptr;
577 mBounds = nullptr;
Romain Guyff98fa52011-11-28 09:35:09 -0800578
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700579 Rect bounds;
Chris Craika1717272015-11-19 13:02:43 -0800580 mCurrentFont->measure(paint, text, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800581
Derek Sollenbergere392c812014-05-21 11:25:22 -0400582 uint32_t intRadius = Blur::convertRadiusToInt(radius);
583 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
584 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
Romain Guyff98fa52011-11-28 09:35:09 -0800585
Romain Guycf51a412013-04-08 19:40:31 -0700586 uint32_t maxSize = Caches::getInstance().maxTextureSize;
587 if (paddedWidth > maxSize || paddedHeight > maxSize) {
588 return image;
589 }
590
Dan Morrille4d9a012013-03-28 18:10:43 -0700591#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800592 // Align buffers for renderscript usage
593 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
594 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700595 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800596 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800597 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700598#else
599 int size = paddedWidth * paddedHeight;
600 uint8_t* dataBuffer = (uint8_t*) malloc(size);
601#endif
602
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800603 memset(dataBuffer, 0, size);
604
Derek Sollenbergere392c812014-05-21 11:25:22 -0400605 int penX = intRadius - bounds.left;
606 int penY = intRadius - bounds.bottom;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700607
Chris Craikdd8697c2013-02-22 10:41:36 -0800608 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
609 // text has non-whitespace, so draw and blur to create the shadow
610 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
611 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
Chris Craika1717272015-11-19 13:02:43 -0800612 mCurrentFont->render(paint, text, numGlyphs, penX, penY,
Chris Craikd41c4d82015-01-05 15:51:13 -0800613 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
Chris Craikdd8697c2013-02-22 10:41:36 -0800614
Romain Guycf51a412013-04-08 19:40:31 -0700615 // Unbind any PBO we might have used
Chris Craik44eb2c02015-01-29 09:45:09 -0800616 Caches::getInstance().pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700617
Chris Craikdd8697c2013-02-22 10:41:36 -0800618 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
619 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700620
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700621 image.width = paddedWidth;
622 image.height = paddedHeight;
623 image.image = dataBuffer;
624 image.penX = penX;
625 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800626
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700627 return image;
628}
Romain Guy694b5192010-07-21 21:33:20 -0700629
Chris Craik82840732015-04-03 09:37:49 -0700630void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextDrawFunctor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700631 checkInit();
632
Romain Guy5b3b3522010-10-27 18:57:51 -0700633 mDrawn = false;
634 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700635 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700636 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800637}
Romain Guyff98fa52011-11-28 09:35:09 -0800638
Romain Guy671d6cf2012-01-18 12:39:17 -0800639void FontRenderer::finishRender() {
Chris Craikd41c4d82015-01-05 15:51:13 -0800640 mBounds = nullptr;
641 mClip = nullptr;
Romain Guy694b5192010-07-21 21:33:20 -0700642
Romain Guy661a87e2013-03-19 15:24:36 -0700643 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800644}
645
Chris Craikd218a922014-01-02 17:13:34 -0800646void FontRenderer::precache(const SkPaint* paint, const char* text, int numGlyphs,
Chris Craik59744b72014-07-01 17:56:52 -0700647 const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800648 Font* font = Font::create(this, paint, matrix);
Chet Haasee816bae2012-08-09 13:39:02 -0700649 font->precache(paint, text, numGlyphs);
650}
651
Romain Guycf51a412013-04-08 19:40:31 -0700652void FontRenderer::endPrecaching() {
653 checkTextureUpdate();
654}
655
Chris Craikd218a922014-01-02 17:13:34 -0800656bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
Chris Craika1717272015-11-19 13:02:43 -0800657 int numGlyphs, int x, int y, const float* positions,
658 Rect* bounds, TextDrawFunctor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800659 if (!mCurrentFont) {
660 ALOGE("No font set");
661 return false;
662 }
663
Romain Guy257ae352013-03-20 16:31:12 -0700664 initRender(clip, bounds, functor);
Chris Craika1717272015-11-19 13:02:43 -0800665 mCurrentFont->render(paint, text, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800666
667 if (forceFinish) {
668 finishRender();
669 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700670
671 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700672}
673
Chris Craikd218a922014-01-02 17:13:34 -0800674bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
Chris Craika1717272015-11-19 13:02:43 -0800675 int numGlyphs, const SkPath* path, float hOffset, float vOffset,
676 Rect* bounds, TextDrawFunctor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800677 if (!mCurrentFont) {
678 ALOGE("No font set");
679 return false;
680 }
681
Victoria Lease1e546812013-06-25 14:25:17 -0700682 initRender(clip, bounds, functor);
Chris Craika1717272015-11-19 13:02:43 -0800683 mCurrentFont->render(paint, text, numGlyphs, path, hOffset, vOffset);
Romain Guy97771732012-02-28 18:17:02 -0800684 finishRender();
685
686 return mDrawn;
687}
688
Derek Sollenbergere392c812014-05-21 11:25:22 -0400689void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
690 uint32_t intRadius = Blur::convertRadiusToInt(radius);
Dan Morrille4d9a012013-03-28 18:10:43 -0700691#ifdef ANDROID_ENABLE_RENDERSCRIPT
Derek Sollenbergere392c812014-05-21 11:25:22 -0400692 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700693 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700694
Chris Craikd41c4d82015-01-05 15:51:13 -0800695 if (mRs == nullptr) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700696 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800697 // a null path is OK because there are no custom kernels used
698 // hence nothing gets cached by RS
699 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800700 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700701 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800702 } else {
703 mRsElement = RSC::Element::A_8(mRs);
704 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700705 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800706 }
Chris Craikd41c4d82015-01-05 15:51:13 -0800707 if (mRs != nullptr) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800708 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
709 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
710 RS_ALLOCATION_MIPMAP_NONE,
711 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
712 *image);
713 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
714 RS_ALLOCATION_MIPMAP_NONE,
715 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
716 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800717
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800718 mRsScript->setRadius(radius);
719 mRsScript->setInput(ain);
720 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700721
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800722 // replace the original image's pointer, avoiding a copy back to the original buffer
723 free(*image);
724 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700725
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800726 return;
727 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800728 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700729#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800730
Chris Craik51d6a3d2014-12-22 17:16:56 -0800731 std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
huanhuan.x.wanga46ca5e2015-04-14 16:23:15 +0200732 Blur::generateGaussianWeights(gaussian.get(), radius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800733
Chris Craik51d6a3d2014-12-22 17:16:56 -0800734 std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
735 Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
736 Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700737}
738
John Reck272a6852015-07-29 16:48:58 -0700739static uint32_t calculateCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700740 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700741 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
742 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700743 if (cacheTexture && cacheTexture->getPixelBuffer()) {
744 size += cacheTexture->getPixelBuffer()->getSize();
745 }
746 }
747 return size;
748}
749
Victoria Lease1e546812013-06-25 14:25:17 -0700750uint32_t FontRenderer::getCacheSize(GLenum format) const {
751 switch (format) {
752 case GL_ALPHA: {
753 return calculateCacheSize(mACacheTextures);
754 }
755 case GL_RGBA: {
756 return calculateCacheSize(mRGBACacheTextures);
757 }
758 default: {
759 return 0;
760 }
761 }
762}
763
Romain Guy694b5192010-07-21 21:33:20 -0700764}; // namespace uirenderer
765}; // namespace android