blob: 4f9a3de64fc2ffcdc3553f8136aecc76d3f446e7 [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"
Derek Sollenbergerb29b16e2017-01-04 14:57:43 -050025#include "font/Font.h"
Chris Craike2bb3802015-03-13 15:07:52 -070026#include "Glop.h"
27#include "GlopBuilder.h"
Chris Craik96a5c4c2015-01-27 15:46:35 -080028#include "PixelBuffer.h"
29#include "Rect.h"
30#include "renderstate/RenderState.h"
31#include "utils/Blur.h"
32#include "utils/Timing.h"
Romain Guy694b5192010-07-21 21:33:20 -070033
Chris Craik9db58c02015-08-19 15:19:18 -070034#include <algorithm>
35#include <cutils/properties.h>
Derek Sollenbergerca79cf62012-08-14 16:44:52 -040036#include <SkGlyph.h>
Romain Guy694b5192010-07-21 21:33:20 -070037#include <SkUtils.h>
Romain Guy51769a62010-07-23 00:28:00 -070038#include <utils/Log.h>
39
Dan Morrille4d9a012013-03-28 18:10:43 -070040#ifdef ANDROID_ENABLE_RENDERSCRIPT
Romain Guy6e200402013-03-08 11:28:22 -080041#include <RenderScript.h>
Dan Morrille4d9a012013-03-28 18:10:43 -070042#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -080043
Romain Guy694b5192010-07-21 21:33:20 -070044namespace android {
45namespace uirenderer {
46
Chris Craikf2d8ccc2013-02-13 16:14:17 -080047// blur inputs smaller than this constant will bypass renderscript
48#define RS_MIN_INPUT_CUTOFF 10000
49
Romain Guy694b5192010-07-21 21:33:20 -070050///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070051// TextSetupFunctor
52///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070053
Chris Craik82840732015-04-03 09:37:49 -070054void TextDrawFunctor::draw(CacheTexture& texture, bool linearFiltering) {
Chris Craik53e51e42015-06-01 10:35:35 -070055 int textureFillFlags = TextureFillFlags::None;
56 if (texture.getFormat() == GL_ALPHA) {
57 textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture;
Chris Craike2bb3802015-03-13 15:07:52 -070058 }
Chris Craik53e51e42015-06-01 10:35:35 -070059 if (linearFiltering) {
60 textureFillFlags |= TextureFillFlags::ForceFilter;
61 }
62 int transformFlags = pureTranslate
63 ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
Romain Guy253f2c22016-09-28 17:34:42 -070064#ifdef ANDROID_ENABLE_LINEAR_BLENDING
65 bool gammaCorrection = true;
66#else
67 bool gammaCorrection = false;
68#endif
Chris Craike2bb3802015-03-13 15:07:52 -070069 Glop glop;
Chris Craika1717272015-11-19 13:02:43 -080070 GlopBuilder(renderer->renderState(), renderer->caches(), &glop)
71 .setRoundRectClipState(bakedState->roundRectClipState)
72 .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
73 .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, bakedState->alpha)
Romain Guy253f2c22016-09-28 17:34:42 -070074 .setGammaCorrection(gammaCorrection)
Chris Craika1717272015-11-19 13:02:43 -080075 .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);
Victoria Lease1e546812013-06-25 14:25:17 -070080}
81
82///////////////////////////////////////////////////////////////////////////////
Romain Guy694b5192010-07-21 21:33:20 -070083// FontRenderer
84///////////////////////////////////////////////////////////////////////////////
85
Romain Guy514fb182011-01-19 14:38:29 -080086static bool sLogFontRendererCreate = true;
87
Chris Craikc08820f2015-09-22 14:22:29 -070088FontRenderer::FontRenderer(const uint8_t* gammaTable)
89 : mGammaTable(gammaTable)
Chris Craik083e7332015-02-27 17:04:20 -080090 , mCurrentFont(nullptr)
91 , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity)
92 , mCurrentCacheTexture(nullptr)
93 , mUploadTexture(false)
94 , mFunctor(nullptr)
95 , mClip(nullptr)
96 , mBounds(nullptr)
97 , mDrawn(false)
98 , mInitialized(false)
99 , mLinearFiltering(false) {
Romain Guye3a9b242013-01-08 11:15:30 -0800100
Romain Guyc9855a52011-01-21 21:14:15 -0800101 if (sLogFontRendererCreate) {
102 INIT_LOGD("Creating FontRenderer");
103 }
Romain Guy51769a62010-07-23 00:28:00 -0700104
Chris Craikc08820f2015-09-22 14:22:29 -0700105 mSmallCacheWidth = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_WIDTH,
106 DEFAULT_TEXT_SMALL_CACHE_WIDTH);
107 mSmallCacheHeight = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_HEIGHT,
108 DEFAULT_TEXT_SMALL_CACHE_HEIGHT);
Romain Guy51769a62010-07-23 00:28:00 -0700109
Chris Craikc08820f2015-09-22 14:22:29 -0700110 mLargeCacheWidth = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_WIDTH,
111 DEFAULT_TEXT_LARGE_CACHE_WIDTH);
112 mLargeCacheHeight = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_HEIGHT,
113 DEFAULT_TEXT_LARGE_CACHE_HEIGHT);
Romain Guy9f5dab32012-09-04 12:55:44 -0700114
115 uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
Chris Craik083e7332015-02-27 17:04:20 -0800116
Chris Craik9db58c02015-08-19 15:19:18 -0700117 mSmallCacheWidth = std::min(mSmallCacheWidth, maxTextureSize);
118 mSmallCacheHeight = std::min(mSmallCacheHeight, maxTextureSize);
119 mLargeCacheWidth = std::min(mLargeCacheWidth, maxTextureSize);
120 mLargeCacheHeight = std::min(mLargeCacheHeight, maxTextureSize);
Romain Guy9f5dab32012-09-04 12:55:44 -0700121
Chet Haaseeb32a492012-08-31 13:54:03 -0700122 if (sLogFontRendererCreate) {
123 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
124 mSmallCacheWidth, mSmallCacheHeight,
125 mLargeCacheWidth, mLargeCacheHeight >> 1,
126 mLargeCacheWidth, mLargeCacheHeight >> 1,
127 mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700128 }
Romain Guy514fb182011-01-19 14:38:29 -0800129
130 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700131}
132
John Reck272a6852015-07-29 16:48:58 -0700133void clearCacheTextures(std::vector<CacheTexture*>& cacheTextures) {
Victoria Lease1e546812013-06-25 14:25:17 -0700134 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
135 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700136 }
Victoria Lease1e546812013-06-25 14:25:17 -0700137 cacheTextures.clear();
138}
139
140FontRenderer::~FontRenderer() {
141 clearCacheTextures(mACacheTextures);
142 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700143
Romain Guye3a9b242013-01-08 11:15:30 -0800144 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
145 while (it.next()) {
146 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700147 }
Romain Guye3a9b242013-01-08 11:15:30 -0800148 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700149}
150
151void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700152 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700153
Romain Guye3a9b242013-01-08 11:15:30 -0800154 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
155 while (it.next()) {
156 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700157 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700158
Victoria Lease1e546812013-06-25 14:25:17 -0700159 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
160 mACacheTextures[i]->init();
sergeyvaf102be2016-09-09 18:02:07 -0700161
162#ifdef BUGREPORT_FONT_CACHE_USAGE
163 mHistoryTracker.glyphsCleared(mACacheTextures[i]);
164#endif
Victoria Lease1e546812013-06-25 14:25:17 -0700165 }
166
167 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
168 mRGBACacheTextures[i]->init();
sergeyvaf102be2016-09-09 18:02:07 -0700169#ifdef BUGREPORT_FONT_CACHE_USAGE
170 mHistoryTracker.glyphsCleared(mRGBACacheTextures[i]);
171#endif
Romain Guy694b5192010-07-21 21:33:20 -0700172 }
chaochen1f61b192014-08-28 18:45:27 -0700173
174 mDrawn = false;
Romain Guy694b5192010-07-21 21:33:20 -0700175}
176
John Reck272a6852015-07-29 16:48:58 -0700177void FontRenderer::flushLargeCaches(std::vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700178 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700179 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
180 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700181 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700182 cacheTexture->init();
sergeyvaf102be2016-09-09 18:02:07 -0700183#ifdef BUGREPORT_FONT_CACHE_USAGE
184 mHistoryTracker.glyphsCleared(cacheTexture);
185#endif
Romain Guye3a9b242013-01-08 11:15:30 -0800186 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
187 while (it.next()) {
188 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700189 }
Chris Craike2bb3802015-03-13 15:07:52 -0700190 cacheTexture->releasePixelBuffer();
Chet Haase9a824562011-12-16 15:44:59 -0800191 }
192 }
Chet Haase9a824562011-12-16 15:44:59 -0800193}
194
Victoria Lease1e546812013-06-25 14:25:17 -0700195void FontRenderer::flushLargeCaches() {
196 flushLargeCaches(mACacheTextures);
197 flushLargeCaches(mRGBACacheTextures);
198}
199
John Reck272a6852015-07-29 16:48:58 -0700200CacheTexture* FontRenderer::cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700201 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
202 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
203 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
204 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700205 }
206 }
207 // Could not fit glyph into current cache textures
Chris Craikd41c4d82015-01-05 15:51:13 -0800208 return nullptr;
Chet Haase378e9192012-08-15 15:54:54 -0700209}
210
Chet Haase7de0cb12011-12-05 16:35:38 -0800211void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700212 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700213 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800214
215 // If the glyph bitmap is empty let's assum the glyph is valid
216 // so we can avoid doing extra work later on
217 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
218 cachedGlyph->mIsValid = true;
Chris Craikd41c4d82015-01-05 15:51:13 -0800219 cachedGlyph->mCacheTexture = nullptr;
Romain Guya4adcf02013-02-28 12:15:35 -0800220 return;
221 }
222
Chet Haase7de0cb12011-12-05 16:35:38 -0800223 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800224
Victoria Lease1e546812013-06-25 14:25:17 -0700225 // choose an appropriate cache texture list for this glyph format
226 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
John Reck272a6852015-07-29 16:48:58 -0700227 std::vector<CacheTexture*>* cacheTextures = nullptr;
Victoria Lease1e546812013-06-25 14:25:17 -0700228 switch (format) {
229 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700230 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700231 cacheTextures = &mACacheTextures;
232 break;
233 case SkMask::kARGB32_Format:
234 cacheTextures = &mRGBACacheTextures;
235 break;
236 default:
237#if DEBUG_FONT_RENDERER
238 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
239#endif
240 return;
241 }
242
Romain Guy694b5192010-07-21 21:33:20 -0700243 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700244 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700245 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700246 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
247 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800248 return;
Romain Guy694b5192010-07-21 21:33:20 -0700249 }
250
251 // Now copy the bitmap into the cache texture
252 uint32_t startX = 0;
253 uint32_t startY = 0;
254
Victoria Lease1e546812013-06-25 14:25:17 -0700255 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700256
Chet Haase378e9192012-08-15 15:54:54 -0700257 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700258 if (!precaching) {
259 // If the new glyph didn't fit and we are not just trying to precache it,
260 // clear out the cache and try again
261 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700262 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700263 }
Romain Guy694b5192010-07-21 21:33:20 -0700264
Chet Haase378e9192012-08-15 15:54:54 -0700265 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700266 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800267 return;
Romain Guy694b5192010-07-21 21:33:20 -0700268 }
269 }
270
Chet Haase378e9192012-08-15 15:54:54 -0700271 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800272
Romain Guy694b5192010-07-21 21:33:20 -0700273 *retOriginX = startX;
274 *retOriginY = startY;
275
276 uint32_t endX = startX + glyph.fWidth;
277 uint32_t endY = startY + glyph.fHeight;
278
Romain Guy80872462012-09-04 16:42:01 -0700279 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700280
Romain Guycf51a412013-04-08 19:40:31 -0700281 if (!cacheTexture->getPixelBuffer()) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800282 Caches::getInstance().textureState().activateTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800283 // Large-glyph texture memory is allocated only as needed
Chris Craike2bb3802015-03-13 15:07:52 -0700284 cacheTexture->allocatePixelBuffer();
Chet Haase7de0cb12011-12-05 16:35:38 -0800285 }
Romain Guy661a87e2013-03-19 15:24:36 -0700286 if (!cacheTexture->mesh()) {
287 cacheTexture->allocateMesh();
288 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700289
Romain Guycf51a412013-04-08 19:40:31 -0700290 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700291 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
292 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700293
Romain Guyb969a0d2013-02-05 14:38:40 -0800294 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800295 switch (format) {
296 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700297 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) {
Romain Guy253f2c22016-09-28 17:34:42 -0700303 for (uint32_t 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 Guy253f2c22016-09-28 17:34:42 -0700306 for (uint32_t cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
Romain Guyb969a0d2013-02-05 14:38:40 -0800307 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 {
Romain Guy253f2c22016-09-28 17:34:42 -0700313 for (uint32_t 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;
sergeyvaf102be2016-09-09 18:02:07 -0700387
388#ifdef BUGREPORT_FONT_CACHE_USAGE
389 mHistoryTracker.glyphUploaded(cacheTexture, startX, startY, glyph.fWidth, glyph.fHeight);
390#endif
Romain Guy694b5192010-07-21 21:33:20 -0700391}
392
Victoria Lease1e546812013-06-25 14:25:17 -0700393CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
394 bool allocate) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800395 CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700396
Chet Haase2a47c142011-12-14 15:22:56 -0800397 if (allocate) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800398 Caches::getInstance().textureState().activateTexture(0);
Chris Craike2bb3802015-03-13 15:07:52 -0700399 cacheTexture->allocatePixelBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700400 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800401 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700402
Chet Haase2a47c142011-12-14 15:22:56 -0800403 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800404}
405
406void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700407 clearCacheTextures(mACacheTextures);
408 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700409
Chet Haase7de0cb12011-12-05 16:35:38 -0800410 mUploadTexture = false;
John Reck272a6852015-07-29 16:48:58 -0700411 mACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700412 GL_ALPHA, true));
John Reck272a6852015-07-29 16:48:58 -0700413 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700414 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700415 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700416 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700417 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700418 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700419 mRGBACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700420 GL_RGBA, false));
John Reck272a6852015-07-29 16:48:58 -0700421 mRGBACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700422 GL_RGBA, false));
423 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700424}
425
Romain Guy694b5192010-07-21 21:33:20 -0700426// We don't want to allocate anything unless we actually draw text
427void FontRenderer::checkInit() {
428 if (mInitialized) {
429 return;
430 }
431
432 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700433
434 mInitialized = true;
435}
436
John Reck272a6852015-07-29 16:48:58 -0700437void checkTextureUpdateForCache(Caches& caches, std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700438 bool& resetPixelStore, GLuint& lastTextureId) {
439 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
440 CacheTexture* cacheTexture = cacheTextures[i];
441 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
442 if (cacheTexture->getTextureId() != lastTextureId) {
443 lastTextureId = cacheTexture->getTextureId();
Chris Craik44eb2c02015-01-29 09:45:09 -0800444 caches.textureState().activateTexture(0);
445 caches.textureState().bindTexture(lastTextureId);
Victoria Lease1e546812013-06-25 14:25:17 -0700446 }
447
448 if (cacheTexture->upload()) {
449 resetPixelStore = true;
450 }
451 }
452 }
453}
454
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700455void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900456 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700457 return;
Romain Guy694b5192010-07-21 21:33:20 -0700458 }
459
Romain Guy2d4fd362011-12-13 22:00:19 -0800460 Caches& caches = Caches::getInstance();
461 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700462
Romain Guycf51a412013-04-08 19:40:31 -0700463 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700464
Chet Haase378e9192012-08-15 15:54:54 -0700465 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700466 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
467 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700468
Romain Guycf51a412013-04-08 19:40:31 -0700469 // Unbind any PBO we might have used to update textures
Chris Craik44eb2c02015-01-29 09:45:09 -0800470 caches.pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700471
Romain Guy09087642013-04-04 12:27:54 -0700472 // Reset to default unpack row length to avoid affecting texture
473 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700474 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700475 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
476 }
477
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700478 mUploadTexture = false;
479}
480
John Reck272a6852015-07-29 16:48:58 -0700481void FontRenderer::issueDrawCommand(std::vector<CacheTexture*>& cacheTextures) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800482 if (!mFunctor) return;
483
Romain Guy661a87e2013-03-19 15:24:36 -0700484 bool first = true;
Victoria Lease1e546812013-06-25 14:25:17 -0700485 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
486 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700487 if (texture->canDraw()) {
488 if (first) {
Chris Craike2bb3802015-03-13 15:07:52 -0700489 checkTextureUpdate();
Romain Guy661a87e2013-03-19 15:24:36 -0700490 first = false;
Chris Craik083e7332015-02-27 17:04:20 -0800491 mDrawn = true;
Romain Guy661a87e2013-03-19 15:24:36 -0700492 }
Chris Craik82840732015-04-03 09:37:49 -0700493
Chris Craike2bb3802015-03-13 15:07:52 -0700494 mFunctor->draw(*texture, mLinearFiltering);
Romain Guy661a87e2013-03-19 15:24:36 -0700495
Romain Guy661a87e2013-03-19 15:24:36 -0700496 texture->resetMesh();
Romain Guy115096f2013-03-19 11:32:41 -0700497 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900498 }
Victoria Lease1e546812013-06-25 14:25:17 -0700499}
500
501void FontRenderer::issueDrawCommand() {
502 issueDrawCommand(mACacheTextures);
503 issueDrawCommand(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700504}
505
Romain Guy97771732012-02-28 18:17:02 -0800506void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
507 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800508 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800509 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800510 // Now use the new texture id
511 mCurrentCacheTexture = texture;
512 }
Romain Guy09147fb2010-07-22 13:08:20 -0700513
Romain Guy661a87e2013-03-19 15:24:36 -0700514 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
515 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800516}
517
518void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
519 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
520 float x4, float y4, float u4, float v4, CacheTexture* texture) {
521
522 if (mClip &&
523 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
524 return;
525 }
526
527 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 -0700528
Romain Guy5b3b3522010-10-27 18:57:51 -0700529 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700530 mBounds->left = std::min(mBounds->left, x1);
531 mBounds->top = std::min(mBounds->top, y3);
532 mBounds->right = std::max(mBounds->right, x3);
533 mBounds->bottom = std::max(mBounds->bottom, y1);
Romain Guy5b3b3522010-10-27 18:57:51 -0700534 }
535
Romain Guy661a87e2013-03-19 15:24:36 -0700536 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700537 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700538 }
539}
540
Romain Guy97771732012-02-28 18:17:02 -0800541void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
542 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
543 float x4, float y4, float u4, float v4, CacheTexture* texture) {
544
545 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
546
547 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700548 mBounds->left = std::min(mBounds->left, std::min(x1, std::min(x2, std::min(x3, x4))));
549 mBounds->top = std::min(mBounds->top, std::min(y1, std::min(y2, std::min(y3, y4))));
550 mBounds->right = std::max(mBounds->right, std::max(x1, std::max(x2, std::max(x3, x4))));
551 mBounds->bottom = std::max(mBounds->bottom, std::max(y1, std::max(y2, std::max(y3, y4))));
Romain Guy97771732012-02-28 18:17:02 -0800552 }
553
Romain Guy661a87e2013-03-19 15:24:36 -0700554 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800555 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800556 }
557}
558
Chris Craik59744b72014-07-01 17:56:52 -0700559void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800560 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700561}
Romain Guy7975fb62010-10-01 16:36:14 -0700562
Chris Craike8c3c812016-02-05 20:10:50 -0800563FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const glyph_t *glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800564 int numGlyphs, float radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700565 checkInit();
566
Romain Guycf51a412013-04-08 19:40:31 -0700567 DropShadow image;
568 image.width = 0;
569 image.height = 0;
Chris Craikd41c4d82015-01-05 15:51:13 -0800570 image.image = nullptr;
Romain Guycf51a412013-04-08 19:40:31 -0700571 image.penX = 0;
572 image.penY = 0;
573
Romain Guy1e45aae2010-08-13 19:39:53 -0700574 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700575 return image;
576 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700577
Romain Guy2d4fd362011-12-13 22:00:19 -0800578 mDrawn = false;
Chris Craikd41c4d82015-01-05 15:51:13 -0800579 mClip = nullptr;
580 mBounds = nullptr;
Romain Guyff98fa52011-11-28 09:35:09 -0800581
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700582 Rect bounds;
Chris Craike8c3c812016-02-05 20:10:50 -0800583 mCurrentFont->measure(paint, glyphs, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800584
Derek Sollenbergere392c812014-05-21 11:25:22 -0400585 uint32_t intRadius = Blur::convertRadiusToInt(radius);
586 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
587 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
Romain Guyff98fa52011-11-28 09:35:09 -0800588
Romain Guycf51a412013-04-08 19:40:31 -0700589 uint32_t maxSize = Caches::getInstance().maxTextureSize;
590 if (paddedWidth > maxSize || paddedHeight > maxSize) {
591 return image;
592 }
593
Dan Morrille4d9a012013-03-28 18:10:43 -0700594#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800595 // Align buffers for renderscript usage
596 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
597 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700598 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800599 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800600 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700601#else
602 int size = paddedWidth * paddedHeight;
603 uint8_t* dataBuffer = (uint8_t*) malloc(size);
604#endif
605
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800606 memset(dataBuffer, 0, size);
607
Derek Sollenbergere392c812014-05-21 11:25:22 -0400608 int penX = intRadius - bounds.left;
609 int penY = intRadius - bounds.bottom;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700610
Chris Craikdd8697c2013-02-22 10:41:36 -0800611 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
612 // text has non-whitespace, so draw and blur to create the shadow
613 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
614 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
Chris Craike8c3c812016-02-05 20:10:50 -0800615 mCurrentFont->render(paint, glyphs, numGlyphs, penX, penY,
Chris Craikd41c4d82015-01-05 15:51:13 -0800616 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
Chris Craikdd8697c2013-02-22 10:41:36 -0800617
Romain Guycf51a412013-04-08 19:40:31 -0700618 // Unbind any PBO we might have used
Chris Craik44eb2c02015-01-29 09:45:09 -0800619 Caches::getInstance().pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700620
Chris Craikdd8697c2013-02-22 10:41:36 -0800621 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
622 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700623
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700624 image.width = paddedWidth;
625 image.height = paddedHeight;
626 image.image = dataBuffer;
627 image.penX = penX;
628 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800629
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700630 return image;
631}
Romain Guy694b5192010-07-21 21:33:20 -0700632
Chris Craik82840732015-04-03 09:37:49 -0700633void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextDrawFunctor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700634 checkInit();
635
Romain Guy5b3b3522010-10-27 18:57:51 -0700636 mDrawn = false;
637 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700638 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700639 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800640}
Romain Guyff98fa52011-11-28 09:35:09 -0800641
Romain Guy671d6cf2012-01-18 12:39:17 -0800642void FontRenderer::finishRender() {
Chris Craikd41c4d82015-01-05 15:51:13 -0800643 mBounds = nullptr;
644 mClip = nullptr;
Romain Guy694b5192010-07-21 21:33:20 -0700645
Romain Guy661a87e2013-03-19 15:24:36 -0700646 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800647}
648
Chris Craike8c3c812016-02-05 20:10:50 -0800649void FontRenderer::precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
Chris Craik59744b72014-07-01 17:56:52 -0700650 const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800651 Font* font = Font::create(this, paint, matrix);
Chris Craike8c3c812016-02-05 20:10:50 -0800652 font->precache(paint, glyphs, numGlyphs);
Chet Haasee816bae2012-08-09 13:39:02 -0700653}
654
Romain Guycf51a412013-04-08 19:40:31 -0700655void FontRenderer::endPrecaching() {
656 checkTextureUpdate();
657}
658
Chris Craike8c3c812016-02-05 20:10:50 -0800659bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800660 int numGlyphs, int x, int y, const float* positions,
661 Rect* bounds, TextDrawFunctor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800662 if (!mCurrentFont) {
663 ALOGE("No font set");
664 return false;
665 }
666
Romain Guy257ae352013-03-20 16:31:12 -0700667 initRender(clip, bounds, functor);
Chris Craike8c3c812016-02-05 20:10:50 -0800668 mCurrentFont->render(paint, glyphs, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800669
670 if (forceFinish) {
671 finishRender();
672 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700673
674 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700675}
676
Chris Craike8c3c812016-02-05 20:10:50 -0800677bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800678 int numGlyphs, const SkPath* path, float hOffset, float vOffset,
679 Rect* bounds, TextDrawFunctor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800680 if (!mCurrentFont) {
681 ALOGE("No font set");
682 return false;
683 }
684
Victoria Lease1e546812013-06-25 14:25:17 -0700685 initRender(clip, bounds, functor);
Chris Craike8c3c812016-02-05 20:10:50 -0800686 mCurrentFont->render(paint, glyphs, numGlyphs, path, hOffset, vOffset);
Romain Guy97771732012-02-28 18:17:02 -0800687 finishRender();
688
689 return mDrawn;
690}
691
Derek Sollenbergere392c812014-05-21 11:25:22 -0400692void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
693 uint32_t intRadius = Blur::convertRadiusToInt(radius);
Dan Morrille4d9a012013-03-28 18:10:43 -0700694#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf3754a82016-04-19 18:13:21 -0700695 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF && radius <= 25.0f) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700696 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700697
Chris Craikd41c4d82015-01-05 15:51:13 -0800698 if (mRs == nullptr) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700699 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800700 // a null path is OK because there are no custom kernels used
701 // hence nothing gets cached by RS
702 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800703 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700704 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800705 } else {
706 mRsElement = RSC::Element::A_8(mRs);
707 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700708 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800709 }
Chris Craikd41c4d82015-01-05 15:51:13 -0800710 if (mRs != nullptr) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800711 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
712 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
713 RS_ALLOCATION_MIPMAP_NONE,
714 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
715 *image);
716 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
717 RS_ALLOCATION_MIPMAP_NONE,
718 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
719 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800720
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800721 mRsScript->setRadius(radius);
722 mRsScript->setInput(ain);
723 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700724
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800725 // replace the original image's pointer, avoiding a copy back to the original buffer
726 free(*image);
727 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700728
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800729 return;
730 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800731 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700732#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800733
Chris Craik51d6a3d2014-12-22 17:16:56 -0800734 std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
huanhuan.x.wanga46ca5e2015-04-14 16:23:15 +0200735 Blur::generateGaussianWeights(gaussian.get(), radius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800736
Chris Craik51d6a3d2014-12-22 17:16:56 -0800737 std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
738 Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
739 Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700740}
741
John Reck272a6852015-07-29 16:48:58 -0700742static uint32_t calculateCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700743 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700744 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
745 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700746 if (cacheTexture && cacheTexture->getPixelBuffer()) {
747 size += cacheTexture->getPixelBuffer()->getSize();
748 }
749 }
750 return size;
751}
752
sergeyvbaf29e72016-09-08 11:09:34 -0700753static uint32_t calculateFreeCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
754 uint32_t size = 0;
755 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
756 CacheTexture* cacheTexture = cacheTextures[i];
757 if (cacheTexture && cacheTexture->getPixelBuffer()) {
758 size += cacheTexture->calculateFreeMemory();
Victoria Lease1e546812013-06-25 14:25:17 -0700759 }
760 }
sergeyvbaf29e72016-09-08 11:09:34 -0700761 return size;
762}
763
764const std::vector<CacheTexture*>& FontRenderer::cacheTexturesForFormat(GLenum format) const {
765 switch (format) {
766 case GL_ALPHA: {
767 return mACacheTextures;
768 }
769 case GL_RGBA: {
770 return mRGBACacheTextures;
771 }
772 default: {
773 LOG_ALWAYS_FATAL("Unsupported format: %d", format);
774 // Impossible to hit this, but the compiler doesn't know that
775 return *(new std::vector<CacheTexture*>());
776 }
777 }
778}
779
780static void dumpTextures(String8& log, const char* tag,
781 const std::vector<CacheTexture*>& cacheTextures) {
782 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
783 CacheTexture* cacheTexture = cacheTextures[i];
784 if (cacheTexture && cacheTexture->getPixelBuffer()) {
785 uint32_t free = cacheTexture->calculateFreeMemory();
786 uint32_t total = cacheTexture->getPixelBuffer()->getSize();
787 log.appendFormat(" %-4s texture %d %8d / %8d\n", tag, i, total - free, total);
788 }
789 }
790}
791
792void FontRenderer::dumpMemoryUsage(String8& log) const {
793 const uint32_t sizeA8 = getCacheSize(GL_ALPHA);
794 const uint32_t usedA8 = sizeA8 - getFreeCacheSize(GL_ALPHA);
795 const uint32_t sizeRGBA = getCacheSize(GL_RGBA);
796 const uint32_t usedRGBA = sizeRGBA - getFreeCacheSize(GL_RGBA);
797 log.appendFormat(" FontRenderer A8 %8d / %8d\n", usedA8, sizeA8);
798 dumpTextures(log, "A8", cacheTexturesForFormat(GL_ALPHA));
799 log.appendFormat(" FontRenderer RGBA %8d / %8d\n", usedRGBA, sizeRGBA);
800 dumpTextures(log, "RGBA", cacheTexturesForFormat(GL_RGBA));
801 log.appendFormat(" FontRenderer total %8d / %8d\n", usedA8 + usedRGBA, sizeA8 + sizeRGBA);
802}
803
804uint32_t FontRenderer::getCacheSize(GLenum format) const {
805 return calculateCacheSize(cacheTexturesForFormat(format));
806}
807
808uint32_t FontRenderer::getFreeCacheSize(GLenum format) const {
809 return calculateFreeCacheSize(cacheTexturesForFormat(format));
810}
811
812uint32_t FontRenderer::getSize() const {
813 return getCacheSize(GL_ALPHA) + getCacheSize(GL_RGBA);
Victoria Lease1e546812013-06-25 14:25:17 -0700814}
815
Romain Guy694b5192010-07-21 21:33:20 -0700816}; // namespace uirenderer
817}; // namespace android