blob: 9c8649fc9775cb6080d3cb1878c34529a7369765 [file] [log] [blame]
Romain Guy694b5192010-07-21 21:33:20 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Chris Craik96a5c4c2015-01-27 15:46:35 -080017#include "FontRenderer.h"
18
19#include "Caches.h"
20#include "Debug.h"
21#include "Extensions.h"
Chris Craike2bb3802015-03-13 15:07:52 -070022#include "Glop.h"
23#include "GlopBuilder.h"
Chris Craik96a5c4c2015-01-27 15:46:35 -080024#include "PixelBuffer.h"
25#include "Rect.h"
26#include "renderstate/RenderState.h"
27#include "utils/Blur.h"
28#include "utils/Timing.h"
Romain Guy694b5192010-07-21 21:33:20 -070029
Chris Craika1717272015-11-19 13:02:43 -080030
31#if HWUI_NEW_OPS
Chris Craik9e7fcfd2015-11-25 13:27:33 -080032#include "BakedOpDispatcher.h"
Chris Craika1717272015-11-19 13:02:43 -080033#include "BakedOpRenderer.h"
Chris Craik9e7fcfd2015-11-25 13:27:33 -080034#include "BakedOpState.h"
Chris Craika1717272015-11-19 13:02:43 -080035#else
36#include "OpenGLRenderer.h"
37#endif
38
Chris Craik9db58c02015-08-19 15:19:18 -070039#include <algorithm>
40#include <cutils/properties.h>
Derek Sollenbergerca79cf62012-08-14 16:44:52 -040041#include <SkGlyph.h>
Romain Guy694b5192010-07-21 21:33:20 -070042#include <SkUtils.h>
Romain Guy51769a62010-07-23 00:28:00 -070043#include <utils/Log.h>
44
Dan Morrille4d9a012013-03-28 18:10:43 -070045#ifdef ANDROID_ENABLE_RENDERSCRIPT
Romain Guy6e200402013-03-08 11:28:22 -080046#include <RenderScript.h>
Dan Morrille4d9a012013-03-28 18:10:43 -070047#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -080048
Romain Guy694b5192010-07-21 21:33:20 -070049namespace android {
50namespace uirenderer {
51
Chris Craikf2d8ccc2013-02-13 16:14:17 -080052// blur inputs smaller than this constant will bypass renderscript
53#define RS_MIN_INPUT_CUTOFF 10000
54
Romain Guy694b5192010-07-21 21:33:20 -070055///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070056// TextSetupFunctor
57///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070058
Chris Craik82840732015-04-03 09:37:49 -070059void TextDrawFunctor::draw(CacheTexture& texture, bool linearFiltering) {
Chris Craik53e51e42015-06-01 10:35:35 -070060 int textureFillFlags = TextureFillFlags::None;
61 if (texture.getFormat() == GL_ALPHA) {
62 textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture;
Chris Craike2bb3802015-03-13 15:07:52 -070063 }
Chris Craik53e51e42015-06-01 10:35:35 -070064 if (linearFiltering) {
65 textureFillFlags |= TextureFillFlags::ForceFilter;
66 }
67 int transformFlags = pureTranslate
68 ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
Chris Craike2bb3802015-03-13 15:07:52 -070069 Glop glop;
Chris Craika1717272015-11-19 13:02:43 -080070#if HWUI_NEW_OPS
71 GlopBuilder(renderer->renderState(), renderer->caches(), &glop)
72 .setRoundRectClipState(bakedState->roundRectClipState)
73 .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
74 .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, bakedState->alpha)
75 .setTransform(bakedState->computedState.transform, transformFlags)
76 .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
77 .build();
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 Craike2bb3802015-03-13 15:07:52 -070086 .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
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();
171 }
172
173 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
174 mRGBACacheTextures[i]->init();
Romain Guy694b5192010-07-21 21:33:20 -0700175 }
chaochen1f61b192014-08-28 18:45:27 -0700176
177 mDrawn = false;
Romain Guy694b5192010-07-21 21:33:20 -0700178}
179
John Reck272a6852015-07-29 16:48:58 -0700180void FontRenderer::flushLargeCaches(std::vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700181 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700182 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
183 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700184 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700185 cacheTexture->init();
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 cacheX = 0, bX = 0, cacheY = 0, bY = 0;
298 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
299 - TEXTURE_BORDER_SIZE;
300 // write leading border line
301 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
302 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800303 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700304 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800305 row = cacheY * cacheWidth;
306 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800307 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
308 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800309 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800310 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800311 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800312 }
313 } else {
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 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
317 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
318 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800319 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700320 }
Victoria Lease1e546812013-06-25 14:25:17 -0700321 // write trailing border line
322 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
323 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
324 break;
325 }
326 case SkMask::kARGB32_Format: {
327 // prep data lengths
328 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
329 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
330 size_t rowSize = formatSize * glyph.fWidth;
331 // prep advances
332 size_t dstStride = formatSize * cacheWidth;
333 // prep indices
334 // - we actually start one row early, and then increment before first copy
335 uint8_t* src = &bitmapBuffer[0 - srcStride];
336 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
337 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
338 uint8_t* dstL = dst - borderSize;
339 uint8_t* dstR = dst + rowSize;
340 // write leading border line
341 memset(dstL, 0, rowSize + 2 * borderSize);
342 // write glyph data
343 while (dst < dstEnd) {
344 memset(dstL += dstStride, 0, borderSize); // leading border column
345 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
346 memset(dstR += dstStride, 0, borderSize); // trailing border column
347 }
348 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700349 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800350 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700351 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800352 case SkMask::kBW_Format: {
Andreas Gampe1e196742014-11-10 15:23:43 -0800353 uint32_t cacheX = 0, cacheY = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700354 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
355 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800356 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700357 // write leading border line
358 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
359 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800360 for (cacheY = startY; cacheY < endY; cacheY++) {
361 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700362 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800363 uint8_t* buffer = bitmapBuffer;
364
Romain Guy0b58a3d2013-03-05 12:16:27 -0800365 row = cacheY * cacheWidth;
366 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800367 while (--rowBytes >= 0) {
368 uint8_t b = *buffer++;
369 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
370 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
371 }
372 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800373 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800374
Victoria Lease1e546812013-06-25 14:25:17 -0700375 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700376 }
Victoria Lease1e546812013-06-25 14:25:17 -0700377 // write trailing border line
378 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
379 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800380 break;
Romain Guy694b5192010-07-21 21:33:20 -0700381 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800382 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700383 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800384 break;
Romain Guy694b5192010-07-21 21:33:20 -0700385 }
Romain Guy97771732012-02-28 18:17:02 -0800386
Chet Haase7de0cb12011-12-05 16:35:38 -0800387 cachedGlyph->mIsValid = true;
Romain Guy694b5192010-07-21 21:33:20 -0700388}
389
Victoria Lease1e546812013-06-25 14:25:17 -0700390CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
391 bool allocate) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800392 CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700393
Chet Haase2a47c142011-12-14 15:22:56 -0800394 if (allocate) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800395 Caches::getInstance().textureState().activateTexture(0);
Chris Craike2bb3802015-03-13 15:07:52 -0700396 cacheTexture->allocatePixelBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700397 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800398 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700399
Chet Haase2a47c142011-12-14 15:22:56 -0800400 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800401}
402
403void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700404 clearCacheTextures(mACacheTextures);
405 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700406
Chet Haase7de0cb12011-12-05 16:35:38 -0800407 mUploadTexture = false;
John Reck272a6852015-07-29 16:48:58 -0700408 mACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700409 GL_ALPHA, true));
John Reck272a6852015-07-29 16:48:58 -0700410 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700411 GL_ALPHA, false));
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,
Victoria Lease1e546812013-06-25 14:25:17 -0700415 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700416 mRGBACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700417 GL_RGBA, false));
John Reck272a6852015-07-29 16:48:58 -0700418 mRGBACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700419 GL_RGBA, false));
420 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700421}
422
Romain Guy694b5192010-07-21 21:33:20 -0700423// We don't want to allocate anything unless we actually draw text
424void FontRenderer::checkInit() {
425 if (mInitialized) {
426 return;
427 }
428
429 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700430
431 mInitialized = true;
432}
433
John Reck272a6852015-07-29 16:48:58 -0700434void checkTextureUpdateForCache(Caches& caches, std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700435 bool& resetPixelStore, GLuint& lastTextureId) {
436 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
437 CacheTexture* cacheTexture = cacheTextures[i];
438 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
439 if (cacheTexture->getTextureId() != lastTextureId) {
440 lastTextureId = cacheTexture->getTextureId();
Chris Craik44eb2c02015-01-29 09:45:09 -0800441 caches.textureState().activateTexture(0);
442 caches.textureState().bindTexture(lastTextureId);
Victoria Lease1e546812013-06-25 14:25:17 -0700443 }
444
445 if (cacheTexture->upload()) {
446 resetPixelStore = true;
447 }
448 }
449 }
450}
451
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700452void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900453 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700454 return;
Romain Guy694b5192010-07-21 21:33:20 -0700455 }
456
Romain Guy2d4fd362011-12-13 22:00:19 -0800457 Caches& caches = Caches::getInstance();
458 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700459
Romain Guycf51a412013-04-08 19:40:31 -0700460 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700461 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
462
Chet Haase378e9192012-08-15 15:54:54 -0700463 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700464 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
465 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700466
Romain Guycf51a412013-04-08 19:40:31 -0700467 // Unbind any PBO we might have used to update textures
Chris Craik44eb2c02015-01-29 09:45:09 -0800468 caches.pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700469
Romain Guy09087642013-04-04 12:27:54 -0700470 // Reset to default unpack row length to avoid affecting texture
471 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700472 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700473 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
474 }
475
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700476 mUploadTexture = false;
477}
478
John Reck272a6852015-07-29 16:48:58 -0700479void FontRenderer::issueDrawCommand(std::vector<CacheTexture*>& cacheTextures) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800480 if (!mFunctor) return;
481
Romain Guy661a87e2013-03-19 15:24:36 -0700482 bool first = true;
Victoria Lease1e546812013-06-25 14:25:17 -0700483 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
484 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700485 if (texture->canDraw()) {
486 if (first) {
Chris Craike2bb3802015-03-13 15:07:52 -0700487 checkTextureUpdate();
Romain Guy661a87e2013-03-19 15:24:36 -0700488 first = false;
Chris Craik083e7332015-02-27 17:04:20 -0800489 mDrawn = true;
Romain Guy661a87e2013-03-19 15:24:36 -0700490 }
Chris Craik82840732015-04-03 09:37:49 -0700491
Chris Craike2bb3802015-03-13 15:07:52 -0700492 mFunctor->draw(*texture, mLinearFiltering);
Romain Guy661a87e2013-03-19 15:24:36 -0700493
Romain Guy661a87e2013-03-19 15:24:36 -0700494 texture->resetMesh();
Romain Guy115096f2013-03-19 11:32:41 -0700495 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900496 }
Victoria Lease1e546812013-06-25 14:25:17 -0700497}
498
499void FontRenderer::issueDrawCommand() {
500 issueDrawCommand(mACacheTextures);
501 issueDrawCommand(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700502}
503
Romain Guy97771732012-02-28 18:17:02 -0800504void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
505 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800506 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800507 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800508 // Now use the new texture id
509 mCurrentCacheTexture = texture;
510 }
Romain Guy09147fb2010-07-22 13:08:20 -0700511
Romain Guy661a87e2013-03-19 15:24:36 -0700512 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
513 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800514}
515
516void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
517 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
518 float x4, float y4, float u4, float v4, CacheTexture* texture) {
519
520 if (mClip &&
521 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
522 return;
523 }
524
525 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 -0700526
Romain Guy5b3b3522010-10-27 18:57:51 -0700527 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700528 mBounds->left = std::min(mBounds->left, x1);
529 mBounds->top = std::min(mBounds->top, y3);
530 mBounds->right = std::max(mBounds->right, x3);
531 mBounds->bottom = std::max(mBounds->bottom, y1);
Romain Guy5b3b3522010-10-27 18:57:51 -0700532 }
533
Romain Guy661a87e2013-03-19 15:24:36 -0700534 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700535 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700536 }
537}
538
Romain Guy97771732012-02-28 18:17:02 -0800539void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
540 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
541 float x4, float y4, float u4, float v4, CacheTexture* texture) {
542
543 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
544
545 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700546 mBounds->left = std::min(mBounds->left, std::min(x1, std::min(x2, std::min(x3, x4))));
547 mBounds->top = std::min(mBounds->top, std::min(y1, std::min(y2, std::min(y3, y4))));
548 mBounds->right = std::max(mBounds->right, std::max(x1, std::max(x2, std::max(x3, x4))));
549 mBounds->bottom = std::max(mBounds->bottom, std::max(y1, std::max(y2, std::max(y3, y4))));
Romain Guy97771732012-02-28 18:17:02 -0800550 }
551
Romain Guy661a87e2013-03-19 15:24:36 -0700552 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800553 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800554 }
555}
556
Chris Craik59744b72014-07-01 17:56:52 -0700557void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800558 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700559}
Romain Guy7975fb62010-10-01 16:36:14 -0700560
Chris Craikd218a922014-01-02 17:13:34 -0800561FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const char *text,
Chris Craika1717272015-11-19 13:02:43 -0800562 int numGlyphs, float radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700563 checkInit();
564
Romain Guycf51a412013-04-08 19:40:31 -0700565 DropShadow image;
566 image.width = 0;
567 image.height = 0;
Chris Craikd41c4d82015-01-05 15:51:13 -0800568 image.image = nullptr;
Romain Guycf51a412013-04-08 19:40:31 -0700569 image.penX = 0;
570 image.penY = 0;
571
Romain Guy1e45aae2010-08-13 19:39:53 -0700572 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700573 return image;
574 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700575
Romain Guy2d4fd362011-12-13 22:00:19 -0800576 mDrawn = false;
Chris Craikd41c4d82015-01-05 15:51:13 -0800577 mClip = nullptr;
578 mBounds = nullptr;
Romain Guyff98fa52011-11-28 09:35:09 -0800579
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700580 Rect bounds;
Chris Craika1717272015-11-19 13:02:43 -0800581 mCurrentFont->measure(paint, text, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800582
Derek Sollenbergere392c812014-05-21 11:25:22 -0400583 uint32_t intRadius = Blur::convertRadiusToInt(radius);
584 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
585 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
Romain Guyff98fa52011-11-28 09:35:09 -0800586
Romain Guycf51a412013-04-08 19:40:31 -0700587 uint32_t maxSize = Caches::getInstance().maxTextureSize;
588 if (paddedWidth > maxSize || paddedHeight > maxSize) {
589 return image;
590 }
591
Dan Morrille4d9a012013-03-28 18:10:43 -0700592#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800593 // Align buffers for renderscript usage
594 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
595 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700596 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800597 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800598 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700599#else
600 int size = paddedWidth * paddedHeight;
601 uint8_t* dataBuffer = (uint8_t*) malloc(size);
602#endif
603
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800604 memset(dataBuffer, 0, size);
605
Derek Sollenbergere392c812014-05-21 11:25:22 -0400606 int penX = intRadius - bounds.left;
607 int penY = intRadius - bounds.bottom;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700608
Chris Craikdd8697c2013-02-22 10:41:36 -0800609 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
610 // text has non-whitespace, so draw and blur to create the shadow
611 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
612 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
Chris Craika1717272015-11-19 13:02:43 -0800613 mCurrentFont->render(paint, text, numGlyphs, penX, penY,
Chris Craikd41c4d82015-01-05 15:51:13 -0800614 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
Chris Craikdd8697c2013-02-22 10:41:36 -0800615
Romain Guycf51a412013-04-08 19:40:31 -0700616 // Unbind any PBO we might have used
Chris Craik44eb2c02015-01-29 09:45:09 -0800617 Caches::getInstance().pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700618
Chris Craikdd8697c2013-02-22 10:41:36 -0800619 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
620 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700621
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700622 image.width = paddedWidth;
623 image.height = paddedHeight;
624 image.image = dataBuffer;
625 image.penX = penX;
626 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800627
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700628 return image;
629}
Romain Guy694b5192010-07-21 21:33:20 -0700630
Chris Craik82840732015-04-03 09:37:49 -0700631void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextDrawFunctor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700632 checkInit();
633
Romain Guy5b3b3522010-10-27 18:57:51 -0700634 mDrawn = false;
635 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700636 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700637 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800638}
Romain Guyff98fa52011-11-28 09:35:09 -0800639
Romain Guy671d6cf2012-01-18 12:39:17 -0800640void FontRenderer::finishRender() {
Chris Craikd41c4d82015-01-05 15:51:13 -0800641 mBounds = nullptr;
642 mClip = nullptr;
Romain Guy694b5192010-07-21 21:33:20 -0700643
Romain Guy661a87e2013-03-19 15:24:36 -0700644 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800645}
646
Chris Craikd218a922014-01-02 17:13:34 -0800647void FontRenderer::precache(const SkPaint* paint, const char* text, int numGlyphs,
Chris Craik59744b72014-07-01 17:56:52 -0700648 const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800649 Font* font = Font::create(this, paint, matrix);
Chet Haasee816bae2012-08-09 13:39:02 -0700650 font->precache(paint, text, numGlyphs);
651}
652
Romain Guycf51a412013-04-08 19:40:31 -0700653void FontRenderer::endPrecaching() {
654 checkTextureUpdate();
655}
656
Chris Craikd218a922014-01-02 17:13:34 -0800657bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
Chris Craika1717272015-11-19 13:02:43 -0800658 int numGlyphs, int x, int y, const float* positions,
659 Rect* bounds, TextDrawFunctor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800660 if (!mCurrentFont) {
661 ALOGE("No font set");
662 return false;
663 }
664
Romain Guy257ae352013-03-20 16:31:12 -0700665 initRender(clip, bounds, functor);
Chris Craika1717272015-11-19 13:02:43 -0800666 mCurrentFont->render(paint, text, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800667
668 if (forceFinish) {
669 finishRender();
670 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700671
672 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700673}
674
Chris Craikd218a922014-01-02 17:13:34 -0800675bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
Chris Craika1717272015-11-19 13:02:43 -0800676 int numGlyphs, const SkPath* path, float hOffset, float vOffset,
677 Rect* bounds, TextDrawFunctor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800678 if (!mCurrentFont) {
679 ALOGE("No font set");
680 return false;
681 }
682
Victoria Lease1e546812013-06-25 14:25:17 -0700683 initRender(clip, bounds, functor);
Chris Craika1717272015-11-19 13:02:43 -0800684 mCurrentFont->render(paint, text, numGlyphs, path, hOffset, vOffset);
Romain Guy97771732012-02-28 18:17:02 -0800685 finishRender();
686
687 return mDrawn;
688}
689
Derek Sollenbergere392c812014-05-21 11:25:22 -0400690void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
691 uint32_t intRadius = Blur::convertRadiusToInt(radius);
Dan Morrille4d9a012013-03-28 18:10:43 -0700692#ifdef ANDROID_ENABLE_RENDERSCRIPT
Derek Sollenbergere392c812014-05-21 11:25:22 -0400693 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700694 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700695
Chris Craikd41c4d82015-01-05 15:51:13 -0800696 if (mRs == nullptr) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700697 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800698 // a null path is OK because there are no custom kernels used
699 // hence nothing gets cached by RS
700 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800701 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700702 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800703 } else {
704 mRsElement = RSC::Element::A_8(mRs);
705 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700706 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800707 }
Chris Craikd41c4d82015-01-05 15:51:13 -0800708 if (mRs != nullptr) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800709 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
710 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
711 RS_ALLOCATION_MIPMAP_NONE,
712 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
713 *image);
714 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
715 RS_ALLOCATION_MIPMAP_NONE,
716 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
717 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800718
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800719 mRsScript->setRadius(radius);
720 mRsScript->setInput(ain);
721 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700722
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800723 // replace the original image's pointer, avoiding a copy back to the original buffer
724 free(*image);
725 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700726
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800727 return;
728 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800729 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700730#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800731
Chris Craik51d6a3d2014-12-22 17:16:56 -0800732 std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
huanhuan.x.wanga46ca5e2015-04-14 16:23:15 +0200733 Blur::generateGaussianWeights(gaussian.get(), radius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800734
Chris Craik51d6a3d2014-12-22 17:16:56 -0800735 std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
736 Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
737 Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700738}
739
John Reck272a6852015-07-29 16:48:58 -0700740static uint32_t calculateCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700741 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700742 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
743 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700744 if (cacheTexture && cacheTexture->getPixelBuffer()) {
745 size += cacheTexture->getPixelBuffer()->getSize();
746 }
747 }
748 return size;
749}
750
Victoria Lease1e546812013-06-25 14:25:17 -0700751uint32_t FontRenderer::getCacheSize(GLenum format) const {
752 switch (format) {
753 case GL_ALPHA: {
754 return calculateCacheSize(mACacheTextures);
755 }
756 case GL_RGBA: {
757 return calculateCacheSize(mRGBACacheTextures);
758 }
759 default: {
760 return 0;
761 }
762 }
763}
764
Romain Guy694b5192010-07-21 21:33:20 -0700765}; // namespace uirenderer
766}; // namespace android