blob: effc65ea967f83acbfabdae96778ad4e7a232175 [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
Chris Craik5e00c7c2016-07-06 16:10:09 -070019#include "BakedOpDispatcher.h"
20#include "BakedOpRenderer.h"
21#include "BakedOpState.h"
Chris Craik96a5c4c2015-01-27 15:46:35 -080022#include "Caches.h"
23#include "Debug.h"
24#include "Extensions.h"
Chris Craike2bb3802015-03-13 15:07:52 -070025#include "Glop.h"
26#include "GlopBuilder.h"
Chris Craik96a5c4c2015-01-27 15:46:35 -080027#include "PixelBuffer.h"
28#include "Rect.h"
29#include "renderstate/RenderState.h"
30#include "utils/Blur.h"
31#include "utils/Timing.h"
Romain Guy694b5192010-07-21 21:33:20 -070032
Chris Craik9db58c02015-08-19 15:19:18 -070033#include <algorithm>
34#include <cutils/properties.h>
Derek Sollenbergerca79cf62012-08-14 16:44:52 -040035#include <SkGlyph.h>
Romain Guy694b5192010-07-21 21:33:20 -070036#include <SkUtils.h>
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;
Romain Guy253f2c22016-09-28 17:34:42 -070063#ifdef ANDROID_ENABLE_LINEAR_BLENDING
64 bool gammaCorrection = true;
65#else
66 bool gammaCorrection = false;
67#endif
Chris Craike2bb3802015-03-13 15:07:52 -070068 Glop glop;
Chris Craika1717272015-11-19 13:02:43 -080069 GlopBuilder(renderer->renderState(), renderer->caches(), &glop)
70 .setRoundRectClipState(bakedState->roundRectClipState)
71 .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
72 .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, bakedState->alpha)
Romain Guy253f2c22016-09-28 17:34:42 -070073 .setGammaCorrection(gammaCorrection)
Chris Craika1717272015-11-19 13:02:43 -080074 .setTransform(bakedState->computedState.transform, transformFlags)
Chris Craikf09ff5a2015-12-08 17:21:58 -080075 .setModelViewIdentityEmptyBounds()
Chris Craika1717272015-11-19 13:02:43 -080076 .build();
Chris Craik15c3f192015-12-03 12:16:56 -080077 // Note: don't pass dirty bounds here, so user must manage passing dirty bounds to renderer
78 renderer->renderGlop(nullptr, clip, glop);
Victoria Lease1e546812013-06-25 14:25:17 -070079}
80
81///////////////////////////////////////////////////////////////////////////////
Romain Guy694b5192010-07-21 21:33:20 -070082// FontRenderer
83///////////////////////////////////////////////////////////////////////////////
84
Romain Guy514fb182011-01-19 14:38:29 -080085static bool sLogFontRendererCreate = true;
86
Chris Craikc08820f2015-09-22 14:22:29 -070087FontRenderer::FontRenderer(const uint8_t* gammaTable)
88 : mGammaTable(gammaTable)
Chris Craik083e7332015-02-27 17:04:20 -080089 , mCurrentFont(nullptr)
90 , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity)
91 , mCurrentCacheTexture(nullptr)
92 , mUploadTexture(false)
93 , mFunctor(nullptr)
94 , mClip(nullptr)
95 , mBounds(nullptr)
96 , mDrawn(false)
97 , mInitialized(false)
98 , mLinearFiltering(false) {
Romain Guye3a9b242013-01-08 11:15:30 -080099
Romain Guyc9855a52011-01-21 21:14:15 -0800100 if (sLogFontRendererCreate) {
101 INIT_LOGD("Creating FontRenderer");
102 }
Romain Guy51769a62010-07-23 00:28:00 -0700103
Chris Craikc08820f2015-09-22 14:22:29 -0700104 mSmallCacheWidth = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_WIDTH,
105 DEFAULT_TEXT_SMALL_CACHE_WIDTH);
106 mSmallCacheHeight = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_HEIGHT,
107 DEFAULT_TEXT_SMALL_CACHE_HEIGHT);
Romain Guy51769a62010-07-23 00:28:00 -0700108
Chris Craikc08820f2015-09-22 14:22:29 -0700109 mLargeCacheWidth = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_WIDTH,
110 DEFAULT_TEXT_LARGE_CACHE_WIDTH);
111 mLargeCacheHeight = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_HEIGHT,
112 DEFAULT_TEXT_LARGE_CACHE_HEIGHT);
Romain Guy9f5dab32012-09-04 12:55:44 -0700113
114 uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
Chris Craik083e7332015-02-27 17:04:20 -0800115
Chris Craik9db58c02015-08-19 15:19:18 -0700116 mSmallCacheWidth = std::min(mSmallCacheWidth, maxTextureSize);
117 mSmallCacheHeight = std::min(mSmallCacheHeight, maxTextureSize);
118 mLargeCacheWidth = std::min(mLargeCacheWidth, maxTextureSize);
119 mLargeCacheHeight = std::min(mLargeCacheHeight, maxTextureSize);
Romain Guy9f5dab32012-09-04 12:55:44 -0700120
Chet Haaseeb32a492012-08-31 13:54:03 -0700121 if (sLogFontRendererCreate) {
122 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
123 mSmallCacheWidth, mSmallCacheHeight,
124 mLargeCacheWidth, mLargeCacheHeight >> 1,
125 mLargeCacheWidth, mLargeCacheHeight >> 1,
126 mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700127 }
Romain Guy514fb182011-01-19 14:38:29 -0800128
129 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700130}
131
John Reck272a6852015-07-29 16:48:58 -0700132void clearCacheTextures(std::vector<CacheTexture*>& cacheTextures) {
Victoria Lease1e546812013-06-25 14:25:17 -0700133 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
134 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700135 }
Victoria Lease1e546812013-06-25 14:25:17 -0700136 cacheTextures.clear();
137}
138
139FontRenderer::~FontRenderer() {
140 clearCacheTextures(mACacheTextures);
141 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700142
Romain Guye3a9b242013-01-08 11:15:30 -0800143 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
144 while (it.next()) {
145 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700146 }
Romain Guye3a9b242013-01-08 11:15:30 -0800147 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700148}
149
150void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700151 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700152
Romain Guye3a9b242013-01-08 11:15:30 -0800153 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
154 while (it.next()) {
155 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700156 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700157
Victoria Lease1e546812013-06-25 14:25:17 -0700158 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
159 mACacheTextures[i]->init();
sergeyvaf102be2016-09-09 18:02:07 -0700160
161#ifdef BUGREPORT_FONT_CACHE_USAGE
162 mHistoryTracker.glyphsCleared(mACacheTextures[i]);
163#endif
Victoria Lease1e546812013-06-25 14:25:17 -0700164 }
165
166 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
167 mRGBACacheTextures[i]->init();
sergeyvaf102be2016-09-09 18:02:07 -0700168#ifdef BUGREPORT_FONT_CACHE_USAGE
169 mHistoryTracker.glyphsCleared(mRGBACacheTextures[i]);
170#endif
Romain Guy694b5192010-07-21 21:33:20 -0700171 }
chaochen1f61b192014-08-28 18:45:27 -0700172
173 mDrawn = false;
Romain Guy694b5192010-07-21 21:33:20 -0700174}
175
John Reck272a6852015-07-29 16:48:58 -0700176void FontRenderer::flushLargeCaches(std::vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700177 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700178 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
179 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700180 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700181 cacheTexture->init();
sergeyvaf102be2016-09-09 18:02:07 -0700182#ifdef BUGREPORT_FONT_CACHE_USAGE
183 mHistoryTracker.glyphsCleared(cacheTexture);
184#endif
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 row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
297 - TEXTURE_BORDER_SIZE;
298 // write leading border line
299 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
300 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800301 if (mGammaTable) {
Romain Guy253f2c22016-09-28 17:34:42 -0700302 for (uint32_t cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800303 row = cacheY * cacheWidth;
304 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guy253f2c22016-09-28 17:34:42 -0700305 for (uint32_t cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
Romain Guyb969a0d2013-02-05 14:38:40 -0800306 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800307 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800308 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800309 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800310 }
311 } else {
Romain Guy253f2c22016-09-28 17:34:42 -0700312 for (uint32_t cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800313 row = cacheY * cacheWidth;
314 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
315 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
316 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800317 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700318 }
Victoria Lease1e546812013-06-25 14:25:17 -0700319 // write trailing border line
320 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
321 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
322 break;
323 }
324 case SkMask::kARGB32_Format: {
325 // prep data lengths
326 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
327 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
328 size_t rowSize = formatSize * glyph.fWidth;
329 // prep advances
330 size_t dstStride = formatSize * cacheWidth;
331 // prep indices
332 // - we actually start one row early, and then increment before first copy
333 uint8_t* src = &bitmapBuffer[0 - srcStride];
334 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
335 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
336 uint8_t* dstL = dst - borderSize;
337 uint8_t* dstR = dst + rowSize;
338 // write leading border line
339 memset(dstL, 0, rowSize + 2 * borderSize);
340 // write glyph data
341 while (dst < dstEnd) {
342 memset(dstL += dstStride, 0, borderSize); // leading border column
343 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
344 memset(dstR += dstStride, 0, borderSize); // trailing border column
345 }
346 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700347 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800348 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700349 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800350 case SkMask::kBW_Format: {
Andreas Gampe1e196742014-11-10 15:23:43 -0800351 uint32_t cacheX = 0, cacheY = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700352 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
353 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800354 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700355 // write leading border line
356 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
357 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800358 for (cacheY = startY; cacheY < endY; cacheY++) {
359 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700360 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800361 uint8_t* buffer = bitmapBuffer;
362
Romain Guy0b58a3d2013-03-05 12:16:27 -0800363 row = cacheY * cacheWidth;
364 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800365 while (--rowBytes >= 0) {
366 uint8_t b = *buffer++;
367 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
368 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
369 }
370 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800371 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800372
Victoria Lease1e546812013-06-25 14:25:17 -0700373 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700374 }
Victoria Lease1e546812013-06-25 14:25:17 -0700375 // write trailing border line
376 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
377 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800378 break;
Romain Guy694b5192010-07-21 21:33:20 -0700379 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800380 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700381 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800382 break;
Romain Guy694b5192010-07-21 21:33:20 -0700383 }
Romain Guy97771732012-02-28 18:17:02 -0800384
Chet Haase7de0cb12011-12-05 16:35:38 -0800385 cachedGlyph->mIsValid = true;
sergeyvaf102be2016-09-09 18:02:07 -0700386
387#ifdef BUGREPORT_FONT_CACHE_USAGE
388 mHistoryTracker.glyphUploaded(cacheTexture, startX, startY, glyph.fWidth, glyph.fHeight);
389#endif
Romain Guy694b5192010-07-21 21:33:20 -0700390}
391
Victoria Lease1e546812013-06-25 14:25:17 -0700392CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
393 bool allocate) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800394 CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700395
Chet Haase2a47c142011-12-14 15:22:56 -0800396 if (allocate) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800397 Caches::getInstance().textureState().activateTexture(0);
Chris Craike2bb3802015-03-13 15:07:52 -0700398 cacheTexture->allocatePixelBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700399 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800400 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700401
Chet Haase2a47c142011-12-14 15:22:56 -0800402 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800403}
404
405void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700406 clearCacheTextures(mACacheTextures);
407 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700408
Chet Haase7de0cb12011-12-05 16:35:38 -0800409 mUploadTexture = false;
John Reck272a6852015-07-29 16:48:58 -0700410 mACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700411 GL_ALPHA, true));
John Reck272a6852015-07-29 16:48:58 -0700412 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700413 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700414 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700415 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700416 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700417 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700418 mRGBACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700419 GL_RGBA, false));
John Reck272a6852015-07-29 16:48:58 -0700420 mRGBACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700421 GL_RGBA, false));
422 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700423}
424
Romain Guy694b5192010-07-21 21:33:20 -0700425// We don't want to allocate anything unless we actually draw text
426void FontRenderer::checkInit() {
427 if (mInitialized) {
428 return;
429 }
430
431 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700432
433 mInitialized = true;
434}
435
John Reck272a6852015-07-29 16:48:58 -0700436void checkTextureUpdateForCache(Caches& caches, std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700437 bool& resetPixelStore, GLuint& lastTextureId) {
438 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
439 CacheTexture* cacheTexture = cacheTextures[i];
440 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
441 if (cacheTexture->getTextureId() != lastTextureId) {
442 lastTextureId = cacheTexture->getTextureId();
Chris Craik44eb2c02015-01-29 09:45:09 -0800443 caches.textureState().activateTexture(0);
444 caches.textureState().bindTexture(lastTextureId);
Victoria Lease1e546812013-06-25 14:25:17 -0700445 }
446
447 if (cacheTexture->upload()) {
448 resetPixelStore = true;
449 }
450 }
451 }
452}
453
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700454void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900455 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700456 return;
Romain Guy694b5192010-07-21 21:33:20 -0700457 }
458
Romain Guy2d4fd362011-12-13 22:00:19 -0800459 Caches& caches = Caches::getInstance();
460 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700461
Romain Guycf51a412013-04-08 19:40:31 -0700462 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700463
Chet Haase378e9192012-08-15 15:54:54 -0700464 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700465 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
466 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700467
Romain Guycf51a412013-04-08 19:40:31 -0700468 // Unbind any PBO we might have used to update textures
Chris Craik44eb2c02015-01-29 09:45:09 -0800469 caches.pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700470
Romain Guy09087642013-04-04 12:27:54 -0700471 // Reset to default unpack row length to avoid affecting texture
472 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700473 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700474 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
475 }
476
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700477 mUploadTexture = false;
478}
479
John Reck272a6852015-07-29 16:48:58 -0700480void FontRenderer::issueDrawCommand(std::vector<CacheTexture*>& cacheTextures) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800481 if (!mFunctor) return;
482
Romain Guy661a87e2013-03-19 15:24:36 -0700483 bool first = true;
Victoria Lease1e546812013-06-25 14:25:17 -0700484 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
485 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700486 if (texture->canDraw()) {
487 if (first) {
Chris Craike2bb3802015-03-13 15:07:52 -0700488 checkTextureUpdate();
Romain Guy661a87e2013-03-19 15:24:36 -0700489 first = false;
Chris Craik083e7332015-02-27 17:04:20 -0800490 mDrawn = true;
Romain Guy661a87e2013-03-19 15:24:36 -0700491 }
Chris Craik82840732015-04-03 09:37:49 -0700492
Chris Craike2bb3802015-03-13 15:07:52 -0700493 mFunctor->draw(*texture, mLinearFiltering);
Romain Guy661a87e2013-03-19 15:24:36 -0700494
Romain Guy661a87e2013-03-19 15:24:36 -0700495 texture->resetMesh();
Romain Guy115096f2013-03-19 11:32:41 -0700496 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900497 }
Victoria Lease1e546812013-06-25 14:25:17 -0700498}
499
500void FontRenderer::issueDrawCommand() {
501 issueDrawCommand(mACacheTextures);
502 issueDrawCommand(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700503}
504
Romain Guy97771732012-02-28 18:17:02 -0800505void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
506 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800507 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800508 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800509 // Now use the new texture id
510 mCurrentCacheTexture = texture;
511 }
Romain Guy09147fb2010-07-22 13:08:20 -0700512
Romain Guy661a87e2013-03-19 15:24:36 -0700513 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
514 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800515}
516
517void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
518 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
519 float x4, float y4, float u4, float v4, CacheTexture* texture) {
520
521 if (mClip &&
522 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
523 return;
524 }
525
526 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 -0700527
Romain Guy5b3b3522010-10-27 18:57:51 -0700528 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700529 mBounds->left = std::min(mBounds->left, x1);
530 mBounds->top = std::min(mBounds->top, y3);
531 mBounds->right = std::max(mBounds->right, x3);
532 mBounds->bottom = std::max(mBounds->bottom, y1);
Romain Guy5b3b3522010-10-27 18:57:51 -0700533 }
534
Romain Guy661a87e2013-03-19 15:24:36 -0700535 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700536 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700537 }
538}
539
Romain Guy97771732012-02-28 18:17:02 -0800540void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
541 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
542 float x4, float y4, float u4, float v4, CacheTexture* texture) {
543
544 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
545
546 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700547 mBounds->left = std::min(mBounds->left, std::min(x1, std::min(x2, std::min(x3, x4))));
548 mBounds->top = std::min(mBounds->top, std::min(y1, std::min(y2, std::min(y3, y4))));
549 mBounds->right = std::max(mBounds->right, std::max(x1, std::max(x2, std::max(x3, x4))));
550 mBounds->bottom = std::max(mBounds->bottom, std::max(y1, std::max(y2, std::max(y3, y4))));
Romain Guy97771732012-02-28 18:17:02 -0800551 }
552
Romain Guy661a87e2013-03-19 15:24:36 -0700553 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800554 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800555 }
556}
557
Chris Craik59744b72014-07-01 17:56:52 -0700558void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800559 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700560}
Romain Guy7975fb62010-10-01 16:36:14 -0700561
Chris Craike8c3c812016-02-05 20:10:50 -0800562FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const glyph_t *glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800563 int numGlyphs, float radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700564 checkInit();
565
Romain Guycf51a412013-04-08 19:40:31 -0700566 DropShadow image;
567 image.width = 0;
568 image.height = 0;
Chris Craikd41c4d82015-01-05 15:51:13 -0800569 image.image = nullptr;
Romain Guycf51a412013-04-08 19:40:31 -0700570 image.penX = 0;
571 image.penY = 0;
572
Romain Guy1e45aae2010-08-13 19:39:53 -0700573 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700574 return image;
575 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700576
Romain Guy2d4fd362011-12-13 22:00:19 -0800577 mDrawn = false;
Chris Craikd41c4d82015-01-05 15:51:13 -0800578 mClip = nullptr;
579 mBounds = nullptr;
Romain Guyff98fa52011-11-28 09:35:09 -0800580
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700581 Rect bounds;
Chris Craike8c3c812016-02-05 20:10:50 -0800582 mCurrentFont->measure(paint, glyphs, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800583
Derek Sollenbergere392c812014-05-21 11:25:22 -0400584 uint32_t intRadius = Blur::convertRadiusToInt(radius);
585 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
586 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
Romain Guyff98fa52011-11-28 09:35:09 -0800587
Romain Guycf51a412013-04-08 19:40:31 -0700588 uint32_t maxSize = Caches::getInstance().maxTextureSize;
589 if (paddedWidth > maxSize || paddedHeight > maxSize) {
590 return image;
591 }
592
Dan Morrille4d9a012013-03-28 18:10:43 -0700593#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800594 // Align buffers for renderscript usage
595 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
596 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700597 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800598 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800599 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700600#else
601 int size = paddedWidth * paddedHeight;
602 uint8_t* dataBuffer = (uint8_t*) malloc(size);
603#endif
604
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800605 memset(dataBuffer, 0, size);
606
Derek Sollenbergere392c812014-05-21 11:25:22 -0400607 int penX = intRadius - bounds.left;
608 int penY = intRadius - bounds.bottom;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700609
Chris Craikdd8697c2013-02-22 10:41:36 -0800610 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
611 // text has non-whitespace, so draw and blur to create the shadow
612 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
613 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
Chris Craike8c3c812016-02-05 20:10:50 -0800614 mCurrentFont->render(paint, glyphs, numGlyphs, penX, penY,
Chris Craikd41c4d82015-01-05 15:51:13 -0800615 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
Chris Craikdd8697c2013-02-22 10:41:36 -0800616
Romain Guycf51a412013-04-08 19:40:31 -0700617 // Unbind any PBO we might have used
Chris Craik44eb2c02015-01-29 09:45:09 -0800618 Caches::getInstance().pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700619
Chris Craikdd8697c2013-02-22 10:41:36 -0800620 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
621 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700622
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700623 image.width = paddedWidth;
624 image.height = paddedHeight;
625 image.image = dataBuffer;
626 image.penX = penX;
627 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800628
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700629 return image;
630}
Romain Guy694b5192010-07-21 21:33:20 -0700631
Chris Craik82840732015-04-03 09:37:49 -0700632void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextDrawFunctor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700633 checkInit();
634
Romain Guy5b3b3522010-10-27 18:57:51 -0700635 mDrawn = false;
636 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700637 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700638 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800639}
Romain Guyff98fa52011-11-28 09:35:09 -0800640
Romain Guy671d6cf2012-01-18 12:39:17 -0800641void FontRenderer::finishRender() {
Chris Craikd41c4d82015-01-05 15:51:13 -0800642 mBounds = nullptr;
643 mClip = nullptr;
Romain Guy694b5192010-07-21 21:33:20 -0700644
Romain Guy661a87e2013-03-19 15:24:36 -0700645 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800646}
647
Chris Craike8c3c812016-02-05 20:10:50 -0800648void FontRenderer::precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
Chris Craik59744b72014-07-01 17:56:52 -0700649 const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800650 Font* font = Font::create(this, paint, matrix);
Chris Craike8c3c812016-02-05 20:10:50 -0800651 font->precache(paint, glyphs, numGlyphs);
Chet Haasee816bae2012-08-09 13:39:02 -0700652}
653
Romain Guycf51a412013-04-08 19:40:31 -0700654void FontRenderer::endPrecaching() {
655 checkTextureUpdate();
656}
657
Chris Craike8c3c812016-02-05 20:10:50 -0800658bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800659 int numGlyphs, int x, int y, const float* positions,
660 Rect* bounds, TextDrawFunctor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800661 if (!mCurrentFont) {
662 ALOGE("No font set");
663 return false;
664 }
665
Romain Guy257ae352013-03-20 16:31:12 -0700666 initRender(clip, bounds, functor);
Chris Craike8c3c812016-02-05 20:10:50 -0800667 mCurrentFont->render(paint, glyphs, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800668
669 if (forceFinish) {
670 finishRender();
671 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700672
673 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700674}
675
Chris Craike8c3c812016-02-05 20:10:50 -0800676bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800677 int numGlyphs, const SkPath* path, float hOffset, float vOffset,
678 Rect* bounds, TextDrawFunctor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800679 if (!mCurrentFont) {
680 ALOGE("No font set");
681 return false;
682 }
683
Victoria Lease1e546812013-06-25 14:25:17 -0700684 initRender(clip, bounds, functor);
Chris Craike8c3c812016-02-05 20:10:50 -0800685 mCurrentFont->render(paint, glyphs, numGlyphs, path, hOffset, vOffset);
Romain Guy97771732012-02-28 18:17:02 -0800686 finishRender();
687
688 return mDrawn;
689}
690
Derek Sollenbergere392c812014-05-21 11:25:22 -0400691void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
692 uint32_t intRadius = Blur::convertRadiusToInt(radius);
Dan Morrille4d9a012013-03-28 18:10:43 -0700693#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf3754a82016-04-19 18:13:21 -0700694 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF && radius <= 25.0f) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700695 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700696
Chris Craikd41c4d82015-01-05 15:51:13 -0800697 if (mRs == nullptr) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700698 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800699 // a null path is OK because there are no custom kernels used
700 // hence nothing gets cached by RS
701 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800702 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700703 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800704 } else {
705 mRsElement = RSC::Element::A_8(mRs);
706 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700707 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800708 }
Chris Craikd41c4d82015-01-05 15:51:13 -0800709 if (mRs != nullptr) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800710 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
711 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
712 RS_ALLOCATION_MIPMAP_NONE,
713 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
714 *image);
715 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
716 RS_ALLOCATION_MIPMAP_NONE,
717 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
718 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800719
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800720 mRsScript->setRadius(radius);
721 mRsScript->setInput(ain);
722 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700723
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800724 // replace the original image's pointer, avoiding a copy back to the original buffer
725 free(*image);
726 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700727
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800728 return;
729 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800730 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700731#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800732
Chris Craik51d6a3d2014-12-22 17:16:56 -0800733 std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
huanhuan.x.wanga46ca5e2015-04-14 16:23:15 +0200734 Blur::generateGaussianWeights(gaussian.get(), radius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800735
Chris Craik51d6a3d2014-12-22 17:16:56 -0800736 std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
737 Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
738 Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700739}
740
John Reck272a6852015-07-29 16:48:58 -0700741static uint32_t calculateCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700742 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700743 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
744 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700745 if (cacheTexture && cacheTexture->getPixelBuffer()) {
746 size += cacheTexture->getPixelBuffer()->getSize();
747 }
748 }
749 return size;
750}
751
sergeyvbaf29e72016-09-08 11:09:34 -0700752static uint32_t calculateFreeCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
753 uint32_t size = 0;
754 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
755 CacheTexture* cacheTexture = cacheTextures[i];
756 if (cacheTexture && cacheTexture->getPixelBuffer()) {
757 size += cacheTexture->calculateFreeMemory();
Victoria Lease1e546812013-06-25 14:25:17 -0700758 }
759 }
sergeyvbaf29e72016-09-08 11:09:34 -0700760 return size;
761}
762
763const std::vector<CacheTexture*>& FontRenderer::cacheTexturesForFormat(GLenum format) const {
764 switch (format) {
765 case GL_ALPHA: {
766 return mACacheTextures;
767 }
768 case GL_RGBA: {
769 return mRGBACacheTextures;
770 }
771 default: {
772 LOG_ALWAYS_FATAL("Unsupported format: %d", format);
773 // Impossible to hit this, but the compiler doesn't know that
774 return *(new std::vector<CacheTexture*>());
775 }
776 }
777}
778
779static void dumpTextures(String8& log, const char* tag,
780 const std::vector<CacheTexture*>& cacheTextures) {
781 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
782 CacheTexture* cacheTexture = cacheTextures[i];
783 if (cacheTexture && cacheTexture->getPixelBuffer()) {
784 uint32_t free = cacheTexture->calculateFreeMemory();
785 uint32_t total = cacheTexture->getPixelBuffer()->getSize();
786 log.appendFormat(" %-4s texture %d %8d / %8d\n", tag, i, total - free, total);
787 }
788 }
789}
790
791void FontRenderer::dumpMemoryUsage(String8& log) const {
792 const uint32_t sizeA8 = getCacheSize(GL_ALPHA);
793 const uint32_t usedA8 = sizeA8 - getFreeCacheSize(GL_ALPHA);
794 const uint32_t sizeRGBA = getCacheSize(GL_RGBA);
795 const uint32_t usedRGBA = sizeRGBA - getFreeCacheSize(GL_RGBA);
796 log.appendFormat(" FontRenderer A8 %8d / %8d\n", usedA8, sizeA8);
797 dumpTextures(log, "A8", cacheTexturesForFormat(GL_ALPHA));
798 log.appendFormat(" FontRenderer RGBA %8d / %8d\n", usedRGBA, sizeRGBA);
799 dumpTextures(log, "RGBA", cacheTexturesForFormat(GL_RGBA));
800 log.appendFormat(" FontRenderer total %8d / %8d\n", usedA8 + usedRGBA, sizeA8 + sizeRGBA);
801}
802
803uint32_t FontRenderer::getCacheSize(GLenum format) const {
804 return calculateCacheSize(cacheTexturesForFormat(format));
805}
806
807uint32_t FontRenderer::getFreeCacheSize(GLenum format) const {
808 return calculateFreeCacheSize(cacheTexturesForFormat(format));
809}
810
811uint32_t FontRenderer::getSize() const {
812 return getCacheSize(GL_ALPHA) + getCacheSize(GL_RGBA);
Victoria Lease1e546812013-06-25 14:25:17 -0700813}
814
Romain Guy694b5192010-07-21 21:33:20 -0700815}; // namespace uirenderer
816}; // namespace android