blob: 681cf55066b4e2bed3bab26561c640d5649d402f [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)
Chris Craikf09ff5a2015-12-08 17:21:58 -080076 .setModelViewIdentityEmptyBounds()
Chris Craika1717272015-11-19 13:02:43 -080077 .build();
Chris Craik15c3f192015-12-03 12:16:56 -080078 // Note: don't pass dirty bounds here, so user must manage passing dirty bounds to renderer
79 renderer->renderGlop(nullptr, clip, glop);
Chris Craika1717272015-11-19 13:02:43 -080080#else
Chris Craike2bb3802015-03-13 15:07:52 -070081 GlopBuilder(renderer->mRenderState, renderer->mCaches, &glop)
Chris Craika1717272015-11-19 13:02:43 -080082 .setRoundRectClipState(renderer->currentSnapshot()->roundRectClipState)
Chris Craike2bb3802015-03-13 15:07:52 -070083 .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
84 .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, renderer->currentSnapshot()->alpha)
Chris Craik53e51e42015-06-01 10:35:35 -070085 .setTransform(*(renderer->currentSnapshot()), transformFlags)
Chris Craik5430ab22015-12-10 16:28:16 -080086 .setModelViewOffsetRect(0, 0, Rect())
Chris Craike2bb3802015-03-13 15:07:52 -070087 .build();
88 renderer->renderGlop(glop);
Chris Craika1717272015-11-19 13:02:43 -080089#endif
Victoria Lease1e546812013-06-25 14:25:17 -070090}
91
92///////////////////////////////////////////////////////////////////////////////
Romain Guy694b5192010-07-21 21:33:20 -070093// FontRenderer
94///////////////////////////////////////////////////////////////////////////////
95
Romain Guy514fb182011-01-19 14:38:29 -080096static bool sLogFontRendererCreate = true;
97
Chris Craikc08820f2015-09-22 14:22:29 -070098FontRenderer::FontRenderer(const uint8_t* gammaTable)
99 : mGammaTable(gammaTable)
Chris Craik083e7332015-02-27 17:04:20 -0800100 , mCurrentFont(nullptr)
101 , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity)
102 , mCurrentCacheTexture(nullptr)
103 , mUploadTexture(false)
104 , mFunctor(nullptr)
105 , mClip(nullptr)
106 , mBounds(nullptr)
107 , mDrawn(false)
108 , mInitialized(false)
109 , mLinearFiltering(false) {
Romain Guye3a9b242013-01-08 11:15:30 -0800110
Romain Guyc9855a52011-01-21 21:14:15 -0800111 if (sLogFontRendererCreate) {
112 INIT_LOGD("Creating FontRenderer");
113 }
Romain Guy51769a62010-07-23 00:28:00 -0700114
Chris Craikc08820f2015-09-22 14:22:29 -0700115 mSmallCacheWidth = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_WIDTH,
116 DEFAULT_TEXT_SMALL_CACHE_WIDTH);
117 mSmallCacheHeight = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_HEIGHT,
118 DEFAULT_TEXT_SMALL_CACHE_HEIGHT);
Romain Guy51769a62010-07-23 00:28:00 -0700119
Chris Craikc08820f2015-09-22 14:22:29 -0700120 mLargeCacheWidth = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_WIDTH,
121 DEFAULT_TEXT_LARGE_CACHE_WIDTH);
122 mLargeCacheHeight = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_HEIGHT,
123 DEFAULT_TEXT_LARGE_CACHE_HEIGHT);
Romain Guy9f5dab32012-09-04 12:55:44 -0700124
125 uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
Chris Craik083e7332015-02-27 17:04:20 -0800126
Chris Craik9db58c02015-08-19 15:19:18 -0700127 mSmallCacheWidth = std::min(mSmallCacheWidth, maxTextureSize);
128 mSmallCacheHeight = std::min(mSmallCacheHeight, maxTextureSize);
129 mLargeCacheWidth = std::min(mLargeCacheWidth, maxTextureSize);
130 mLargeCacheHeight = std::min(mLargeCacheHeight, maxTextureSize);
Romain Guy9f5dab32012-09-04 12:55:44 -0700131
Chet Haaseeb32a492012-08-31 13:54:03 -0700132 if (sLogFontRendererCreate) {
133 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
134 mSmallCacheWidth, mSmallCacheHeight,
135 mLargeCacheWidth, mLargeCacheHeight >> 1,
136 mLargeCacheWidth, mLargeCacheHeight >> 1,
137 mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700138 }
Romain Guy514fb182011-01-19 14:38:29 -0800139
140 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700141}
142
John Reck272a6852015-07-29 16:48:58 -0700143void clearCacheTextures(std::vector<CacheTexture*>& cacheTextures) {
Victoria Lease1e546812013-06-25 14:25:17 -0700144 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
145 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700146 }
Victoria Lease1e546812013-06-25 14:25:17 -0700147 cacheTextures.clear();
148}
149
150FontRenderer::~FontRenderer() {
151 clearCacheTextures(mACacheTextures);
152 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700153
Romain Guye3a9b242013-01-08 11:15:30 -0800154 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
155 while (it.next()) {
156 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700157 }
Romain Guye3a9b242013-01-08 11:15:30 -0800158 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700159}
160
161void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700162 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700163
Romain Guye3a9b242013-01-08 11:15:30 -0800164 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
165 while (it.next()) {
166 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700167 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700168
Victoria Lease1e546812013-06-25 14:25:17 -0700169 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
170 mACacheTextures[i]->init();
sergeyvaf102be2016-09-09 18:02:07 -0700171
172#ifdef BUGREPORT_FONT_CACHE_USAGE
173 mHistoryTracker.glyphsCleared(mACacheTextures[i]);
174#endif
Victoria Lease1e546812013-06-25 14:25:17 -0700175 }
176
177 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
178 mRGBACacheTextures[i]->init();
sergeyvaf102be2016-09-09 18:02:07 -0700179#ifdef BUGREPORT_FONT_CACHE_USAGE
180 mHistoryTracker.glyphsCleared(mRGBACacheTextures[i]);
181#endif
Romain Guy694b5192010-07-21 21:33:20 -0700182 }
chaochen1f61b192014-08-28 18:45:27 -0700183
184 mDrawn = false;
Romain Guy694b5192010-07-21 21:33:20 -0700185}
186
John Reck272a6852015-07-29 16:48:58 -0700187void FontRenderer::flushLargeCaches(std::vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700188 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700189 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
190 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700191 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700192 cacheTexture->init();
sergeyvaf102be2016-09-09 18:02:07 -0700193#ifdef BUGREPORT_FONT_CACHE_USAGE
194 mHistoryTracker.glyphsCleared(cacheTexture);
195#endif
Romain Guye3a9b242013-01-08 11:15:30 -0800196 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
197 while (it.next()) {
198 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700199 }
Chris Craike2bb3802015-03-13 15:07:52 -0700200 cacheTexture->releasePixelBuffer();
Chet Haase9a824562011-12-16 15:44:59 -0800201 }
202 }
Chet Haase9a824562011-12-16 15:44:59 -0800203}
204
Victoria Lease1e546812013-06-25 14:25:17 -0700205void FontRenderer::flushLargeCaches() {
206 flushLargeCaches(mACacheTextures);
207 flushLargeCaches(mRGBACacheTextures);
208}
209
John Reck272a6852015-07-29 16:48:58 -0700210CacheTexture* FontRenderer::cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700211 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
212 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
213 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
214 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700215 }
216 }
217 // Could not fit glyph into current cache textures
Chris Craikd41c4d82015-01-05 15:51:13 -0800218 return nullptr;
Chet Haase378e9192012-08-15 15:54:54 -0700219}
220
Chet Haase7de0cb12011-12-05 16:35:38 -0800221void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700222 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700223 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800224
225 // If the glyph bitmap is empty let's assum the glyph is valid
226 // so we can avoid doing extra work later on
227 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
228 cachedGlyph->mIsValid = true;
Chris Craikd41c4d82015-01-05 15:51:13 -0800229 cachedGlyph->mCacheTexture = nullptr;
Romain Guya4adcf02013-02-28 12:15:35 -0800230 return;
231 }
232
Chet Haase7de0cb12011-12-05 16:35:38 -0800233 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800234
Victoria Lease1e546812013-06-25 14:25:17 -0700235 // choose an appropriate cache texture list for this glyph format
236 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
John Reck272a6852015-07-29 16:48:58 -0700237 std::vector<CacheTexture*>* cacheTextures = nullptr;
Victoria Lease1e546812013-06-25 14:25:17 -0700238 switch (format) {
239 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700240 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700241 cacheTextures = &mACacheTextures;
242 break;
243 case SkMask::kARGB32_Format:
244 cacheTextures = &mRGBACacheTextures;
245 break;
246 default:
247#if DEBUG_FONT_RENDERER
248 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
249#endif
250 return;
251 }
252
Romain Guy694b5192010-07-21 21:33:20 -0700253 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700254 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700255 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700256 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
257 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800258 return;
Romain Guy694b5192010-07-21 21:33:20 -0700259 }
260
261 // Now copy the bitmap into the cache texture
262 uint32_t startX = 0;
263 uint32_t startY = 0;
264
Victoria Lease1e546812013-06-25 14:25:17 -0700265 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700266
Chet Haase378e9192012-08-15 15:54:54 -0700267 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700268 if (!precaching) {
269 // If the new glyph didn't fit and we are not just trying to precache it,
270 // clear out the cache and try again
271 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700272 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700273 }
Romain Guy694b5192010-07-21 21:33:20 -0700274
Chet Haase378e9192012-08-15 15:54:54 -0700275 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700276 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800277 return;
Romain Guy694b5192010-07-21 21:33:20 -0700278 }
279 }
280
Chet Haase378e9192012-08-15 15:54:54 -0700281 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800282
Romain Guy694b5192010-07-21 21:33:20 -0700283 *retOriginX = startX;
284 *retOriginY = startY;
285
286 uint32_t endX = startX + glyph.fWidth;
287 uint32_t endY = startY + glyph.fHeight;
288
Romain Guy80872462012-09-04 16:42:01 -0700289 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700290
Romain Guycf51a412013-04-08 19:40:31 -0700291 if (!cacheTexture->getPixelBuffer()) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800292 Caches::getInstance().textureState().activateTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800293 // Large-glyph texture memory is allocated only as needed
Chris Craike2bb3802015-03-13 15:07:52 -0700294 cacheTexture->allocatePixelBuffer();
Chet Haase7de0cb12011-12-05 16:35:38 -0800295 }
Romain Guy661a87e2013-03-19 15:24:36 -0700296 if (!cacheTexture->mesh()) {
297 cacheTexture->allocateMesh();
298 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700299
Romain Guycf51a412013-04-08 19:40:31 -0700300 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700301 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
302 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700303
Romain Guyb969a0d2013-02-05 14:38:40 -0800304 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800305 switch (format) {
306 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700307 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
308 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
309 - TEXTURE_BORDER_SIZE;
310 // write leading border line
311 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
312 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800313 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700314 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800315 row = cacheY * cacheWidth;
316 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800317 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
318 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800319 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800320 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800321 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800322 }
323 } else {
Victoria Lease1e546812013-06-25 14:25:17 -0700324 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800325 row = cacheY * cacheWidth;
326 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
327 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
328 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800329 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700330 }
Victoria Lease1e546812013-06-25 14:25:17 -0700331 // write trailing border line
332 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
333 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
334 break;
335 }
336 case SkMask::kARGB32_Format: {
337 // prep data lengths
338 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
339 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
340 size_t rowSize = formatSize * glyph.fWidth;
341 // prep advances
342 size_t dstStride = formatSize * cacheWidth;
343 // prep indices
344 // - we actually start one row early, and then increment before first copy
345 uint8_t* src = &bitmapBuffer[0 - srcStride];
346 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
347 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
348 uint8_t* dstL = dst - borderSize;
349 uint8_t* dstR = dst + rowSize;
350 // write leading border line
351 memset(dstL, 0, rowSize + 2 * borderSize);
352 // write glyph data
353 while (dst < dstEnd) {
354 memset(dstL += dstStride, 0, borderSize); // leading border column
355 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
356 memset(dstR += dstStride, 0, borderSize); // trailing border column
357 }
358 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700359 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800360 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700361 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800362 case SkMask::kBW_Format: {
Andreas Gampe1e196742014-11-10 15:23:43 -0800363 uint32_t cacheX = 0, cacheY = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700364 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
365 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800366 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700367 // write leading border line
368 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
369 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800370 for (cacheY = startY; cacheY < endY; cacheY++) {
371 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700372 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800373 uint8_t* buffer = bitmapBuffer;
374
Romain Guy0b58a3d2013-03-05 12:16:27 -0800375 row = cacheY * cacheWidth;
376 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800377 while (--rowBytes >= 0) {
378 uint8_t b = *buffer++;
379 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
380 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
381 }
382 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800383 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800384
Victoria Lease1e546812013-06-25 14:25:17 -0700385 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700386 }
Victoria Lease1e546812013-06-25 14:25:17 -0700387 // write trailing border line
388 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
389 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800390 break;
Romain Guy694b5192010-07-21 21:33:20 -0700391 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800392 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700393 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800394 break;
Romain Guy694b5192010-07-21 21:33:20 -0700395 }
Romain Guy97771732012-02-28 18:17:02 -0800396
Chet Haase7de0cb12011-12-05 16:35:38 -0800397 cachedGlyph->mIsValid = true;
sergeyvaf102be2016-09-09 18:02:07 -0700398
399#ifdef BUGREPORT_FONT_CACHE_USAGE
400 mHistoryTracker.glyphUploaded(cacheTexture, startX, startY, glyph.fWidth, glyph.fHeight);
401#endif
Romain Guy694b5192010-07-21 21:33:20 -0700402}
403
Victoria Lease1e546812013-06-25 14:25:17 -0700404CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
405 bool allocate) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800406 CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700407
Chet Haase2a47c142011-12-14 15:22:56 -0800408 if (allocate) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800409 Caches::getInstance().textureState().activateTexture(0);
Chris Craike2bb3802015-03-13 15:07:52 -0700410 cacheTexture->allocatePixelBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700411 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800412 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700413
Chet Haase2a47c142011-12-14 15:22:56 -0800414 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800415}
416
417void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700418 clearCacheTextures(mACacheTextures);
419 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700420
Chet Haase7de0cb12011-12-05 16:35:38 -0800421 mUploadTexture = false;
John Reck272a6852015-07-29 16:48:58 -0700422 mACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700423 GL_ALPHA, true));
John Reck272a6852015-07-29 16:48:58 -0700424 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700425 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700426 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700427 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700428 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700429 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700430 mRGBACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700431 GL_RGBA, false));
John Reck272a6852015-07-29 16:48:58 -0700432 mRGBACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700433 GL_RGBA, false));
434 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700435}
436
Romain Guy694b5192010-07-21 21:33:20 -0700437// We don't want to allocate anything unless we actually draw text
438void FontRenderer::checkInit() {
439 if (mInitialized) {
440 return;
441 }
442
443 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700444
445 mInitialized = true;
446}
447
John Reck272a6852015-07-29 16:48:58 -0700448void checkTextureUpdateForCache(Caches& caches, std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700449 bool& resetPixelStore, GLuint& lastTextureId) {
450 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
451 CacheTexture* cacheTexture = cacheTextures[i];
452 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
453 if (cacheTexture->getTextureId() != lastTextureId) {
454 lastTextureId = cacheTexture->getTextureId();
Chris Craik44eb2c02015-01-29 09:45:09 -0800455 caches.textureState().activateTexture(0);
456 caches.textureState().bindTexture(lastTextureId);
Victoria Lease1e546812013-06-25 14:25:17 -0700457 }
458
459 if (cacheTexture->upload()) {
460 resetPixelStore = true;
461 }
462 }
463 }
464}
465
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700466void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900467 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700468 return;
Romain Guy694b5192010-07-21 21:33:20 -0700469 }
470
Romain Guy2d4fd362011-12-13 22:00:19 -0800471 Caches& caches = Caches::getInstance();
472 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700473
Romain Guycf51a412013-04-08 19:40:31 -0700474 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700475
Chet Haase378e9192012-08-15 15:54:54 -0700476 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700477 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
478 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700479
Romain Guycf51a412013-04-08 19:40:31 -0700480 // Unbind any PBO we might have used to update textures
Chris Craik44eb2c02015-01-29 09:45:09 -0800481 caches.pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700482
Romain Guy09087642013-04-04 12:27:54 -0700483 // Reset to default unpack row length to avoid affecting texture
484 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700485 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700486 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
487 }
488
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700489 mUploadTexture = false;
490}
491
John Reck272a6852015-07-29 16:48:58 -0700492void FontRenderer::issueDrawCommand(std::vector<CacheTexture*>& cacheTextures) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800493 if (!mFunctor) return;
494
Romain Guy661a87e2013-03-19 15:24:36 -0700495 bool first = true;
Victoria Lease1e546812013-06-25 14:25:17 -0700496 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
497 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700498 if (texture->canDraw()) {
499 if (first) {
Chris Craike2bb3802015-03-13 15:07:52 -0700500 checkTextureUpdate();
Romain Guy661a87e2013-03-19 15:24:36 -0700501 first = false;
Chris Craik083e7332015-02-27 17:04:20 -0800502 mDrawn = true;
Romain Guy661a87e2013-03-19 15:24:36 -0700503 }
Chris Craik82840732015-04-03 09:37:49 -0700504
Chris Craike2bb3802015-03-13 15:07:52 -0700505 mFunctor->draw(*texture, mLinearFiltering);
Romain Guy661a87e2013-03-19 15:24:36 -0700506
Romain Guy661a87e2013-03-19 15:24:36 -0700507 texture->resetMesh();
Romain Guy115096f2013-03-19 11:32:41 -0700508 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900509 }
Victoria Lease1e546812013-06-25 14:25:17 -0700510}
511
512void FontRenderer::issueDrawCommand() {
513 issueDrawCommand(mACacheTextures);
514 issueDrawCommand(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700515}
516
Romain Guy97771732012-02-28 18:17:02 -0800517void FontRenderer::appendMeshQuadNoClip(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,
Chet Haase7de0cb12011-12-05 16:35:38 -0800519 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800520 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800521 // Now use the new texture id
522 mCurrentCacheTexture = texture;
523 }
Romain Guy09147fb2010-07-22 13:08:20 -0700524
Romain Guy661a87e2013-03-19 15:24:36 -0700525 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
526 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800527}
528
529void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
530 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
531 float x4, float y4, float u4, float v4, CacheTexture* texture) {
532
533 if (mClip &&
534 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
535 return;
536 }
537
538 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 -0700539
Romain Guy5b3b3522010-10-27 18:57:51 -0700540 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700541 mBounds->left = std::min(mBounds->left, x1);
542 mBounds->top = std::min(mBounds->top, y3);
543 mBounds->right = std::max(mBounds->right, x3);
544 mBounds->bottom = std::max(mBounds->bottom, y1);
Romain Guy5b3b3522010-10-27 18:57:51 -0700545 }
546
Romain Guy661a87e2013-03-19 15:24:36 -0700547 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700548 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700549 }
550}
551
Romain Guy97771732012-02-28 18:17:02 -0800552void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
553 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
554 float x4, float y4, float u4, float v4, CacheTexture* texture) {
555
556 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
557
558 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700559 mBounds->left = std::min(mBounds->left, std::min(x1, std::min(x2, std::min(x3, x4))));
560 mBounds->top = std::min(mBounds->top, std::min(y1, std::min(y2, std::min(y3, y4))));
561 mBounds->right = std::max(mBounds->right, std::max(x1, std::max(x2, std::max(x3, x4))));
562 mBounds->bottom = std::max(mBounds->bottom, std::max(y1, std::max(y2, std::max(y3, y4))));
Romain Guy97771732012-02-28 18:17:02 -0800563 }
564
Romain Guy661a87e2013-03-19 15:24:36 -0700565 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800566 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800567 }
568}
569
Chris Craik59744b72014-07-01 17:56:52 -0700570void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800571 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700572}
Romain Guy7975fb62010-10-01 16:36:14 -0700573
Chris Craike8c3c812016-02-05 20:10:50 -0800574FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const glyph_t *glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800575 int numGlyphs, float radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700576 checkInit();
577
Romain Guycf51a412013-04-08 19:40:31 -0700578 DropShadow image;
579 image.width = 0;
580 image.height = 0;
Chris Craikd41c4d82015-01-05 15:51:13 -0800581 image.image = nullptr;
Romain Guycf51a412013-04-08 19:40:31 -0700582 image.penX = 0;
583 image.penY = 0;
584
Romain Guy1e45aae2010-08-13 19:39:53 -0700585 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700586 return image;
587 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700588
Romain Guy2d4fd362011-12-13 22:00:19 -0800589 mDrawn = false;
Chris Craikd41c4d82015-01-05 15:51:13 -0800590 mClip = nullptr;
591 mBounds = nullptr;
Romain Guyff98fa52011-11-28 09:35:09 -0800592
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700593 Rect bounds;
Chris Craike8c3c812016-02-05 20:10:50 -0800594 mCurrentFont->measure(paint, glyphs, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800595
Derek Sollenbergere392c812014-05-21 11:25:22 -0400596 uint32_t intRadius = Blur::convertRadiusToInt(radius);
597 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
598 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
Romain Guyff98fa52011-11-28 09:35:09 -0800599
Romain Guycf51a412013-04-08 19:40:31 -0700600 uint32_t maxSize = Caches::getInstance().maxTextureSize;
601 if (paddedWidth > maxSize || paddedHeight > maxSize) {
602 return image;
603 }
604
Dan Morrille4d9a012013-03-28 18:10:43 -0700605#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800606 // Align buffers for renderscript usage
607 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
608 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700609 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800610 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800611 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700612#else
613 int size = paddedWidth * paddedHeight;
614 uint8_t* dataBuffer = (uint8_t*) malloc(size);
615#endif
616
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800617 memset(dataBuffer, 0, size);
618
Derek Sollenbergere392c812014-05-21 11:25:22 -0400619 int penX = intRadius - bounds.left;
620 int penY = intRadius - bounds.bottom;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700621
Chris Craikdd8697c2013-02-22 10:41:36 -0800622 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
623 // text has non-whitespace, so draw and blur to create the shadow
624 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
625 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
Chris Craike8c3c812016-02-05 20:10:50 -0800626 mCurrentFont->render(paint, glyphs, numGlyphs, penX, penY,
Chris Craikd41c4d82015-01-05 15:51:13 -0800627 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
Chris Craikdd8697c2013-02-22 10:41:36 -0800628
Romain Guycf51a412013-04-08 19:40:31 -0700629 // Unbind any PBO we might have used
Chris Craik44eb2c02015-01-29 09:45:09 -0800630 Caches::getInstance().pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700631
Chris Craikdd8697c2013-02-22 10:41:36 -0800632 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
633 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700634
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700635 image.width = paddedWidth;
636 image.height = paddedHeight;
637 image.image = dataBuffer;
638 image.penX = penX;
639 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800640
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700641 return image;
642}
Romain Guy694b5192010-07-21 21:33:20 -0700643
Chris Craik82840732015-04-03 09:37:49 -0700644void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextDrawFunctor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700645 checkInit();
646
Romain Guy5b3b3522010-10-27 18:57:51 -0700647 mDrawn = false;
648 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700649 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700650 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800651}
Romain Guyff98fa52011-11-28 09:35:09 -0800652
Romain Guy671d6cf2012-01-18 12:39:17 -0800653void FontRenderer::finishRender() {
Chris Craikd41c4d82015-01-05 15:51:13 -0800654 mBounds = nullptr;
655 mClip = nullptr;
Romain Guy694b5192010-07-21 21:33:20 -0700656
Romain Guy661a87e2013-03-19 15:24:36 -0700657 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800658}
659
Chris Craike8c3c812016-02-05 20:10:50 -0800660void FontRenderer::precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
Chris Craik59744b72014-07-01 17:56:52 -0700661 const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800662 Font* font = Font::create(this, paint, matrix);
Chris Craike8c3c812016-02-05 20:10:50 -0800663 font->precache(paint, glyphs, numGlyphs);
Chet Haasee816bae2012-08-09 13:39:02 -0700664}
665
Romain Guycf51a412013-04-08 19:40:31 -0700666void FontRenderer::endPrecaching() {
667 checkTextureUpdate();
668}
669
Chris Craike8c3c812016-02-05 20:10:50 -0800670bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800671 int numGlyphs, int x, int y, const float* positions,
672 Rect* bounds, TextDrawFunctor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800673 if (!mCurrentFont) {
674 ALOGE("No font set");
675 return false;
676 }
677
Romain Guy257ae352013-03-20 16:31:12 -0700678 initRender(clip, bounds, functor);
Chris Craike8c3c812016-02-05 20:10:50 -0800679 mCurrentFont->render(paint, glyphs, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800680
681 if (forceFinish) {
682 finishRender();
683 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700684
685 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700686}
687
Chris Craike8c3c812016-02-05 20:10:50 -0800688bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800689 int numGlyphs, const SkPath* path, float hOffset, float vOffset,
690 Rect* bounds, TextDrawFunctor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800691 if (!mCurrentFont) {
692 ALOGE("No font set");
693 return false;
694 }
695
Victoria Lease1e546812013-06-25 14:25:17 -0700696 initRender(clip, bounds, functor);
Chris Craike8c3c812016-02-05 20:10:50 -0800697 mCurrentFont->render(paint, glyphs, numGlyphs, path, hOffset, vOffset);
Romain Guy97771732012-02-28 18:17:02 -0800698 finishRender();
699
700 return mDrawn;
701}
702
Derek Sollenbergere392c812014-05-21 11:25:22 -0400703void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
704 uint32_t intRadius = Blur::convertRadiusToInt(radius);
Dan Morrille4d9a012013-03-28 18:10:43 -0700705#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf3754a82016-04-19 18:13:21 -0700706 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF && radius <= 25.0f) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700707 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700708
Chris Craikd41c4d82015-01-05 15:51:13 -0800709 if (mRs == nullptr) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700710 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800711 // a null path is OK because there are no custom kernels used
712 // hence nothing gets cached by RS
713 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800714 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700715 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800716 } else {
717 mRsElement = RSC::Element::A_8(mRs);
718 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700719 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800720 }
Chris Craikd41c4d82015-01-05 15:51:13 -0800721 if (mRs != nullptr) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800722 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
723 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
724 RS_ALLOCATION_MIPMAP_NONE,
725 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
726 *image);
727 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
728 RS_ALLOCATION_MIPMAP_NONE,
729 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
730 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800731
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800732 mRsScript->setRadius(radius);
733 mRsScript->setInput(ain);
734 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700735
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800736 // replace the original image's pointer, avoiding a copy back to the original buffer
737 free(*image);
738 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700739
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800740 return;
741 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800742 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700743#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800744
Chris Craik51d6a3d2014-12-22 17:16:56 -0800745 std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
huanhuan.x.wanga46ca5e2015-04-14 16:23:15 +0200746 Blur::generateGaussianWeights(gaussian.get(), radius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800747
Chris Craik51d6a3d2014-12-22 17:16:56 -0800748 std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
749 Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
750 Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700751}
752
John Reck272a6852015-07-29 16:48:58 -0700753static uint32_t calculateCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700754 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700755 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
756 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700757 if (cacheTexture && cacheTexture->getPixelBuffer()) {
758 size += cacheTexture->getPixelBuffer()->getSize();
759 }
760 }
761 return size;
762}
763
sergeyvbaf29e72016-09-08 11:09:34 -0700764static uint32_t calculateFreeCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
765 uint32_t size = 0;
766 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
767 CacheTexture* cacheTexture = cacheTextures[i];
768 if (cacheTexture && cacheTexture->getPixelBuffer()) {
769 size += cacheTexture->calculateFreeMemory();
Victoria Lease1e546812013-06-25 14:25:17 -0700770 }
771 }
sergeyvbaf29e72016-09-08 11:09:34 -0700772 return size;
773}
774
775const std::vector<CacheTexture*>& FontRenderer::cacheTexturesForFormat(GLenum format) const {
776 switch (format) {
777 case GL_ALPHA: {
778 return mACacheTextures;
779 }
780 case GL_RGBA: {
781 return mRGBACacheTextures;
782 }
783 default: {
784 LOG_ALWAYS_FATAL("Unsupported format: %d", format);
785 // Impossible to hit this, but the compiler doesn't know that
786 return *(new std::vector<CacheTexture*>());
787 }
788 }
789}
790
791static void dumpTextures(String8& log, const char* tag,
792 const std::vector<CacheTexture*>& cacheTextures) {
793 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
794 CacheTexture* cacheTexture = cacheTextures[i];
795 if (cacheTexture && cacheTexture->getPixelBuffer()) {
796 uint32_t free = cacheTexture->calculateFreeMemory();
797 uint32_t total = cacheTexture->getPixelBuffer()->getSize();
798 log.appendFormat(" %-4s texture %d %8d / %8d\n", tag, i, total - free, total);
799 }
800 }
801}
802
803void FontRenderer::dumpMemoryUsage(String8& log) const {
804 const uint32_t sizeA8 = getCacheSize(GL_ALPHA);
805 const uint32_t usedA8 = sizeA8 - getFreeCacheSize(GL_ALPHA);
806 const uint32_t sizeRGBA = getCacheSize(GL_RGBA);
807 const uint32_t usedRGBA = sizeRGBA - getFreeCacheSize(GL_RGBA);
808 log.appendFormat(" FontRenderer A8 %8d / %8d\n", usedA8, sizeA8);
809 dumpTextures(log, "A8", cacheTexturesForFormat(GL_ALPHA));
810 log.appendFormat(" FontRenderer RGBA %8d / %8d\n", usedRGBA, sizeRGBA);
811 dumpTextures(log, "RGBA", cacheTexturesForFormat(GL_RGBA));
812 log.appendFormat(" FontRenderer total %8d / %8d\n", usedA8 + usedRGBA, sizeA8 + sizeRGBA);
813}
814
815uint32_t FontRenderer::getCacheSize(GLenum format) const {
816 return calculateCacheSize(cacheTexturesForFormat(format));
817}
818
819uint32_t FontRenderer::getFreeCacheSize(GLenum format) const {
820 return calculateFreeCacheSize(cacheTexturesForFormat(format));
821}
822
823uint32_t FontRenderer::getSize() const {
824 return getCacheSize(GL_ALPHA) + getCacheSize(GL_RGBA);
Victoria Lease1e546812013-06-25 14:25:17 -0700825}
826
Romain Guy694b5192010-07-21 21:33:20 -0700827}; // namespace uirenderer
828}; // namespace android