blob: d1d2fccb55aad197c28cdca2493ea8b0a1982657 [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"
22#include "OpenGLRenderer.h"
23#include "PixelBuffer.h"
24#include "Rect.h"
25#include "renderstate/RenderState.h"
26#include "utils/Blur.h"
Chris Craik083e7332015-02-27 17:04:20 -080027#include "utils/MathUtils.h"
Chris Craik96a5c4c2015-01-27 15:46:35 -080028#include "utils/Timing.h"
Romain Guy694b5192010-07-21 21:33:20 -070029
Derek Sollenbergerca79cf62012-08-14 16:44:52 -040030#include <SkGlyph.h>
Romain Guy694b5192010-07-21 21:33:20 -070031#include <SkUtils.h>
32
Romain Guy51769a62010-07-23 00:28:00 -070033#include <cutils/properties.h>
Romain Guye2d345e2010-09-24 18:39:22 -070034
Romain Guy51769a62010-07-23 00:28:00 -070035#include <utils/Log.h>
36
Dan Morrille4d9a012013-03-28 18:10:43 -070037#ifdef ANDROID_ENABLE_RENDERSCRIPT
Romain Guy6e200402013-03-08 11:28:22 -080038#include <RenderScript.h>
Dan Morrille4d9a012013-03-28 18:10:43 -070039#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -080040
Romain Guy694b5192010-07-21 21:33:20 -070041namespace android {
42namespace uirenderer {
43
Chris Craikf2d8ccc2013-02-13 16:14:17 -080044// blur inputs smaller than this constant will bypass renderscript
45#define RS_MIN_INPUT_CUTOFF 10000
46
Romain Guy694b5192010-07-21 21:33:20 -070047///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070048// TextSetupFunctor
49///////////////////////////////////////////////////////////////////////////////
Chris Craik96a5c4c2015-01-27 15:46:35 -080050status_t TextSetupFunctor::setup(GLenum glyphFormat) {
Victoria Lease1e546812013-06-25 14:25:17 -070051 renderer->setupDraw();
52 renderer->setupDrawTextGamma(paint);
53 renderer->setupDrawDirtyRegionsDisabled();
54 renderer->setupDrawWithTexture(glyphFormat == GL_ALPHA);
55 switch (glyphFormat) {
56 case GL_ALPHA: {
57 renderer->setupDrawAlpha8Color(paint->getColor(), alpha);
58 break;
59 }
60 case GL_RGBA: {
61 float floatAlpha = alpha / 255.0f;
62 renderer->setupDrawColor(floatAlpha, floatAlpha, floatAlpha, floatAlpha);
63 break;
64 }
65 default: {
66#if DEBUG_FONT_RENDERER
67 ALOGD("TextSetupFunctor: called with unknown glyph format %x", glyphFormat);
68#endif
69 break;
70 }
71 }
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -050072 renderer->setupDrawColorFilter(paint->getColorFilter());
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -040073 renderer->setupDrawShader(paint->getShader());
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -050074 renderer->setupDrawBlending(paint);
Victoria Lease1e546812013-06-25 14:25:17 -070075 renderer->setupDrawProgram();
Chris Craik4063a0e2013-11-15 16:06:56 -080076 renderer->setupDrawModelView(kModelViewMode_Translate, false,
77 0.0f, 0.0f, 0.0f, 0.0f, pureTranslate);
Victoria Lease1e546812013-06-25 14:25:17 -070078 // Calling setupDrawTexture with the name 0 will enable the
79 // uv attributes and increase the texture unit count
80 // texture binding will be performed by the font renderer as
81 // needed
82 renderer->setupDrawTexture(0);
83 renderer->setupDrawPureColorUniforms();
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -050084 renderer->setupDrawColorFilterUniforms(paint->getColorFilter());
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -040085 renderer->setupDrawShaderUniforms(paint->getShader(), pureTranslate);
Victoria Lease1e546812013-06-25 14:25:17 -070086 renderer->setupDrawTextGammaUniforms();
87
88 return NO_ERROR;
89}
90
91///////////////////////////////////////////////////////////////////////////////
Romain Guy694b5192010-07-21 21:33:20 -070092// FontRenderer
93///////////////////////////////////////////////////////////////////////////////
94
Romain Guy514fb182011-01-19 14:38:29 -080095static bool sLogFontRendererCreate = true;
96
Chris Craik083e7332015-02-27 17:04:20 -080097FontRenderer::FontRenderer()
98 : mGammaTable(nullptr)
99 , mCurrentFont(nullptr)
100 , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity)
101 , mCurrentCacheTexture(nullptr)
102 , mUploadTexture(false)
103 , mFunctor(nullptr)
104 , mClip(nullptr)
105 , mBounds(nullptr)
106 , mDrawn(false)
107 , mInitialized(false)
108 , mLinearFiltering(false) {
Romain Guye3a9b242013-01-08 11:15:30 -0800109
Romain Guyc9855a52011-01-21 21:14:15 -0800110 if (sLogFontRendererCreate) {
111 INIT_LOGD("Creating FontRenderer");
112 }
Romain Guy51769a62010-07-23 00:28:00 -0700113
Chet Haaseeb32a492012-08-31 13:54:03 -0700114 mSmallCacheWidth = DEFAULT_TEXT_SMALL_CACHE_WIDTH;
115 mSmallCacheHeight = DEFAULT_TEXT_SMALL_CACHE_HEIGHT;
116 mLargeCacheWidth = DEFAULT_TEXT_LARGE_CACHE_WIDTH;
117 mLargeCacheHeight = DEFAULT_TEXT_LARGE_CACHE_HEIGHT;
Romain Guy51769a62010-07-23 00:28:00 -0700118
119 char property[PROPERTY_VALUE_MAX];
Chris Craikd41c4d82015-01-05 15:51:13 -0800120 if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, nullptr) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800121 mSmallCacheWidth = atoi(property);
Romain Guy51769a62010-07-23 00:28:00 -0700122 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700123
Chris Craikd41c4d82015-01-05 15:51:13 -0800124 if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, nullptr) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800125 mSmallCacheHeight = atoi(property);
Chet Haaseeb32a492012-08-31 13:54:03 -0700126 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700127
Chris Craikd41c4d82015-01-05 15:51:13 -0800128 if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, nullptr) > 0) {
Chet Haaseeb32a492012-08-31 13:54:03 -0700129 mLargeCacheWidth = atoi(property);
130 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700131
Chris Craikd41c4d82015-01-05 15:51:13 -0800132 if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, nullptr) > 0) {
Chet Haaseeb32a492012-08-31 13:54:03 -0700133 mLargeCacheHeight = atoi(property);
134 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700135
136 uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
Chris Craik083e7332015-02-27 17:04:20 -0800137
138 mSmallCacheWidth = MathUtils::min(mSmallCacheWidth, maxTextureSize);
139 mSmallCacheHeight = MathUtils::min(mSmallCacheHeight, maxTextureSize);
140 mLargeCacheWidth = MathUtils::min(mLargeCacheWidth, maxTextureSize);
141 mLargeCacheHeight = MathUtils::min(mLargeCacheHeight, maxTextureSize);
Romain Guy9f5dab32012-09-04 12:55:44 -0700142
Chet Haaseeb32a492012-08-31 13:54:03 -0700143 if (sLogFontRendererCreate) {
144 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
145 mSmallCacheWidth, mSmallCacheHeight,
146 mLargeCacheWidth, mLargeCacheHeight >> 1,
147 mLargeCacheWidth, mLargeCacheHeight >> 1,
148 mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700149 }
Romain Guy514fb182011-01-19 14:38:29 -0800150
151 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700152}
153
Victoria Lease1e546812013-06-25 14:25:17 -0700154void clearCacheTextures(Vector<CacheTexture*>& cacheTextures) {
155 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
156 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700157 }
Victoria Lease1e546812013-06-25 14:25:17 -0700158 cacheTextures.clear();
159}
160
161FontRenderer::~FontRenderer() {
162 clearCacheTextures(mACacheTextures);
163 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700164
Romain Guye3a9b242013-01-08 11:15:30 -0800165 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
166 while (it.next()) {
167 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700168 }
Romain Guye3a9b242013-01-08 11:15:30 -0800169 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700170}
171
172void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700173 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700174
Romain Guye3a9b242013-01-08 11:15:30 -0800175 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
176 while (it.next()) {
177 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700178 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700179
Victoria Lease1e546812013-06-25 14:25:17 -0700180 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
181 mACacheTextures[i]->init();
182 }
183
184 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
185 mRGBACacheTextures[i]->init();
Romain Guy694b5192010-07-21 21:33:20 -0700186 }
187}
188
Victoria Lease1e546812013-06-25 14:25:17 -0700189void FontRenderer::flushLargeCaches(Vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700190 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700191 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
192 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700193 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700194 cacheTexture->init();
Romain Guye3a9b242013-01-08 11:15:30 -0800195 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
196 while (it.next()) {
197 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700198 }
Romain Guy80872462012-09-04 16:42:01 -0700199 cacheTexture->releaseTexture();
Chet Haase9a824562011-12-16 15:44:59 -0800200 }
201 }
Chet Haase9a824562011-12-16 15:44:59 -0800202}
203
Victoria Lease1e546812013-06-25 14:25:17 -0700204void FontRenderer::flushLargeCaches() {
205 flushLargeCaches(mACacheTextures);
206 flushLargeCaches(mRGBACacheTextures);
207}
208
209CacheTexture* FontRenderer::cacheBitmapInTexture(Vector<CacheTexture*>& cacheTextures,
210 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
211 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
212 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
213 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700214 }
215 }
216 // Could not fit glyph into current cache textures
Chris Craikd41c4d82015-01-05 15:51:13 -0800217 return nullptr;
Chet Haase378e9192012-08-15 15:54:54 -0700218}
219
Chet Haase7de0cb12011-12-05 16:35:38 -0800220void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700221 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700222 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800223
224 // If the glyph bitmap is empty let's assum the glyph is valid
225 // so we can avoid doing extra work later on
226 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
227 cachedGlyph->mIsValid = true;
Chris Craikd41c4d82015-01-05 15:51:13 -0800228 cachedGlyph->mCacheTexture = nullptr;
Romain Guya4adcf02013-02-28 12:15:35 -0800229 return;
230 }
231
Chet Haase7de0cb12011-12-05 16:35:38 -0800232 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800233
Victoria Lease1e546812013-06-25 14:25:17 -0700234 // choose an appropriate cache texture list for this glyph format
235 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
Chris Craikd41c4d82015-01-05 15:51:13 -0800236 Vector<CacheTexture*>* cacheTextures = nullptr;
Victoria Lease1e546812013-06-25 14:25:17 -0700237 switch (format) {
238 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700239 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700240 cacheTextures = &mACacheTextures;
241 break;
242 case SkMask::kARGB32_Format:
243 cacheTextures = &mRGBACacheTextures;
244 break;
245 default:
246#if DEBUG_FONT_RENDERER
247 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
248#endif
249 return;
250 }
251
Romain Guy694b5192010-07-21 21:33:20 -0700252 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700253 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700254 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700255 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
256 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800257 return;
Romain Guy694b5192010-07-21 21:33:20 -0700258 }
259
260 // Now copy the bitmap into the cache texture
261 uint32_t startX = 0;
262 uint32_t startY = 0;
263
Victoria Lease1e546812013-06-25 14:25:17 -0700264 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700265
Chet Haase378e9192012-08-15 15:54:54 -0700266 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700267 if (!precaching) {
268 // If the new glyph didn't fit and we are not just trying to precache it,
269 // clear out the cache and try again
270 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700271 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700272 }
Romain Guy694b5192010-07-21 21:33:20 -0700273
Chet Haase378e9192012-08-15 15:54:54 -0700274 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700275 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800276 return;
Romain Guy694b5192010-07-21 21:33:20 -0700277 }
278 }
279
Chet Haase378e9192012-08-15 15:54:54 -0700280 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800281
Romain Guy694b5192010-07-21 21:33:20 -0700282 *retOriginX = startX;
283 *retOriginY = startY;
284
285 uint32_t endX = startX + glyph.fWidth;
286 uint32_t endY = startY + glyph.fHeight;
287
Romain Guy80872462012-09-04 16:42:01 -0700288 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700289
Romain Guycf51a412013-04-08 19:40:31 -0700290 if (!cacheTexture->getPixelBuffer()) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800291 Caches::getInstance().textureState().activateTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800292 // Large-glyph texture memory is allocated only as needed
Romain Guy80872462012-09-04 16:42:01 -0700293 cacheTexture->allocateTexture();
Chet Haase7de0cb12011-12-05 16:35:38 -0800294 }
Romain Guy661a87e2013-03-19 15:24:36 -0700295 if (!cacheTexture->mesh()) {
296 cacheTexture->allocateMesh();
297 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700298
Romain Guycf51a412013-04-08 19:40:31 -0700299 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700300 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
301 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700302
Romain Guyb969a0d2013-02-05 14:38:40 -0800303 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800304 switch (format) {
305 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700306 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
307 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
308 - TEXTURE_BORDER_SIZE;
309 // write leading border line
310 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
311 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800312 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700313 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800314 row = cacheY * cacheWidth;
315 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800316 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
317 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800318 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800319 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800320 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800321 }
322 } else {
Victoria Lease1e546812013-06-25 14:25:17 -0700323 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800324 row = cacheY * cacheWidth;
325 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
326 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
327 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800328 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700329 }
Victoria Lease1e546812013-06-25 14:25:17 -0700330 // write trailing border line
331 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
332 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
333 break;
334 }
335 case SkMask::kARGB32_Format: {
336 // prep data lengths
337 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
338 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
339 size_t rowSize = formatSize * glyph.fWidth;
340 // prep advances
341 size_t dstStride = formatSize * cacheWidth;
342 // prep indices
343 // - we actually start one row early, and then increment before first copy
344 uint8_t* src = &bitmapBuffer[0 - srcStride];
345 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
346 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
347 uint8_t* dstL = dst - borderSize;
348 uint8_t* dstR = dst + rowSize;
349 // write leading border line
350 memset(dstL, 0, rowSize + 2 * borderSize);
351 // write glyph data
352 while (dst < dstEnd) {
353 memset(dstL += dstStride, 0, borderSize); // leading border column
354 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
355 memset(dstR += dstStride, 0, borderSize); // trailing border column
356 }
357 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700358 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800359 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700360 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800361 case SkMask::kBW_Format: {
Andreas Gampe1e196742014-11-10 15:23:43 -0800362 uint32_t cacheX = 0, cacheY = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700363 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
364 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800365 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700366 // write leading border line
367 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
368 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800369 for (cacheY = startY; cacheY < endY; cacheY++) {
370 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700371 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800372 uint8_t* buffer = bitmapBuffer;
373
Romain Guy0b58a3d2013-03-05 12:16:27 -0800374 row = cacheY * cacheWidth;
375 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800376 while (--rowBytes >= 0) {
377 uint8_t b = *buffer++;
378 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
379 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
380 }
381 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800382 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800383
Victoria Lease1e546812013-06-25 14:25:17 -0700384 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700385 }
Victoria Lease1e546812013-06-25 14:25:17 -0700386 // write trailing border line
387 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
388 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800389 break;
Romain Guy694b5192010-07-21 21:33:20 -0700390 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800391 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700392 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800393 break;
Romain Guy694b5192010-07-21 21:33:20 -0700394 }
Romain Guy97771732012-02-28 18:17:02 -0800395
Chet Haase7de0cb12011-12-05 16:35:38 -0800396 cachedGlyph->mIsValid = true;
Romain Guy694b5192010-07-21 21:33:20 -0700397}
398
Victoria Lease1e546812013-06-25 14:25:17 -0700399CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
400 bool allocate) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800401 CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700402
Chet Haase2a47c142011-12-14 15:22:56 -0800403 if (allocate) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800404 Caches::getInstance().textureState().activateTexture(0);
Romain Guy80872462012-09-04 16:42:01 -0700405 cacheTexture->allocateTexture();
Romain Guy661a87e2013-03-19 15:24:36 -0700406 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800407 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700408
Chet Haase2a47c142011-12-14 15:22:56 -0800409 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800410}
411
412void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700413 clearCacheTextures(mACacheTextures);
414 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700415
Chet Haase7de0cb12011-12-05 16:35:38 -0800416 mUploadTexture = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700417 mACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
418 GL_ALPHA, true));
419 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
420 GL_ALPHA, false));
421 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
422 GL_ALPHA, false));
423 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
424 GL_ALPHA, false));
425 mRGBACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
426 GL_RGBA, false));
427 mRGBACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
428 GL_RGBA, false));
429 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700430}
431
Romain Guy694b5192010-07-21 21:33:20 -0700432// We don't want to allocate anything unless we actually draw text
433void FontRenderer::checkInit() {
434 if (mInitialized) {
435 return;
436 }
437
438 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700439
440 mInitialized = true;
441}
442
Victoria Lease1e546812013-06-25 14:25:17 -0700443void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheTextures,
444 bool& resetPixelStore, GLuint& lastTextureId) {
445 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
446 CacheTexture* cacheTexture = cacheTextures[i];
447 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
448 if (cacheTexture->getTextureId() != lastTextureId) {
449 lastTextureId = cacheTexture->getTextureId();
Chris Craik44eb2c02015-01-29 09:45:09 -0800450 caches.textureState().activateTexture(0);
451 caches.textureState().bindTexture(lastTextureId);
Victoria Lease1e546812013-06-25 14:25:17 -0700452 }
453
454 if (cacheTexture->upload()) {
455 resetPixelStore = true;
456 }
457 }
458 }
459}
460
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700461void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900462 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700463 return;
Romain Guy694b5192010-07-21 21:33:20 -0700464 }
465
Romain Guy2d4fd362011-12-13 22:00:19 -0800466 Caches& caches = Caches::getInstance();
467 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700468
Romain Guycf51a412013-04-08 19:40:31 -0700469 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700470 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
471
Chet Haase378e9192012-08-15 15:54:54 -0700472 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700473 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
474 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700475
Romain Guycf51a412013-04-08 19:40:31 -0700476 // Unbind any PBO we might have used to update textures
Chris Craik44eb2c02015-01-29 09:45:09 -0800477 caches.pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700478
Romain Guy09087642013-04-04 12:27:54 -0700479 // Reset to default unpack row length to avoid affecting texture
480 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700481 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700482 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
483 }
484
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700485 mUploadTexture = false;
486}
487
Victoria Lease1e546812013-06-25 14:25:17 -0700488void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800489 if (!mFunctor) return;
490
491 Caches& caches = mFunctor->renderer->getCaches();
492 RenderState& renderState = mFunctor->renderer->renderState();
493
Romain Guy661a87e2013-03-19 15:24:36 -0700494 bool first = true;
Chris Craik96a5c4c2015-01-27 15:46:35 -0800495 bool forceRebind = false;
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 Craik083e7332015-02-27 17:04:20 -0800500 mFunctor->setup(texture->getFormat());
Romain Guy257ae352013-03-20 16:31:12 -0700501
Romain Guy661a87e2013-03-19 15:24:36 -0700502 checkTextureUpdate();
Chris Craik96a5c4c2015-01-27 15:46:35 -0800503 renderState.meshState().bindQuadIndicesBuffer();
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900504
Chris Craik083e7332015-02-27 17:04:20 -0800505 // If returns true, a VBO was bound and we must
506 // rebind our vertex attrib pointers even if
507 // they have the same values as the current pointers
508 forceRebind = renderState.meshState().unbindMeshBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700509
Chris Craik44eb2c02015-01-29 09:45:09 -0800510 caches.textureState().activateTexture(0);
Romain Guy661a87e2013-03-19 15:24:36 -0700511 first = false;
Chris Craik083e7332015-02-27 17:04:20 -0800512 mDrawn = true;
Romain Guy661a87e2013-03-19 15:24:36 -0700513 }
514
Chris Craik44eb2c02015-01-29 09:45:09 -0800515 caches.textureState().bindTexture(texture->getTextureId());
Romain Guy661a87e2013-03-19 15:24:36 -0700516 texture->setLinearFiltering(mLinearFiltering, false);
517
518 TextureVertex* mesh = texture->mesh();
Chris Craik96a5c4c2015-01-27 15:46:35 -0800519 MeshState& meshState = renderState.meshState();
Chris Craik6c15ffa2015-02-02 13:50:55 -0800520 meshState.bindPositionVertexPointer(forceRebind, &mesh[0].x);
521 meshState.bindTexCoordsVertexPointer(forceRebind, &mesh[0].u);
Romain Guy661a87e2013-03-19 15:24:36 -0700522
523 glDrawElements(GL_TRIANGLES, texture->meshElementCount(),
524 GL_UNSIGNED_SHORT, texture->indices());
525
526 texture->resetMesh();
Chris Craik96a5c4c2015-01-27 15:46:35 -0800527 forceRebind = false;
Romain Guy115096f2013-03-19 11:32:41 -0700528 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900529 }
Victoria Lease1e546812013-06-25 14:25:17 -0700530}
531
532void FontRenderer::issueDrawCommand() {
533 issueDrawCommand(mACacheTextures);
534 issueDrawCommand(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700535}
536
Romain Guy97771732012-02-28 18:17:02 -0800537void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
538 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800539 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800540 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800541 // Now use the new texture id
542 mCurrentCacheTexture = texture;
543 }
Romain Guy09147fb2010-07-22 13:08:20 -0700544
Romain Guy661a87e2013-03-19 15:24:36 -0700545 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
546 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800547}
548
549void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
550 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
551 float x4, float y4, float u4, float v4, CacheTexture* texture) {
552
553 if (mClip &&
554 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
555 return;
556 }
557
558 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 -0700559
Romain Guy5b3b3522010-10-27 18:57:51 -0700560 if (mBounds) {
561 mBounds->left = fmin(mBounds->left, x1);
562 mBounds->top = fmin(mBounds->top, y3);
563 mBounds->right = fmax(mBounds->right, x3);
564 mBounds->bottom = fmax(mBounds->bottom, y1);
565 }
566
Romain Guy661a87e2013-03-19 15:24:36 -0700567 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700568 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700569 }
570}
571
Romain Guy97771732012-02-28 18:17:02 -0800572void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
573 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
574 float x4, float y4, float u4, float v4, CacheTexture* texture) {
575
576 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
577
578 if (mBounds) {
579 mBounds->left = fmin(mBounds->left, fmin(x1, fmin(x2, fmin(x3, x4))));
580 mBounds->top = fmin(mBounds->top, fmin(y1, fmin(y2, fmin(y3, y4))));
581 mBounds->right = fmax(mBounds->right, fmax(x1, fmax(x2, fmax(x3, x4))));
582 mBounds->bottom = fmax(mBounds->bottom, fmax(y1, fmax(y2, fmax(y3, y4))));
583 }
584
Romain Guy661a87e2013-03-19 15:24:36 -0700585 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800586 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800587 }
588}
589
Chris Craik59744b72014-07-01 17:56:52 -0700590void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800591 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700592}
Romain Guy7975fb62010-10-01 16:36:14 -0700593
Chris Craikd218a922014-01-02 17:13:34 -0800594FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const char *text,
Derek Sollenbergere392c812014-05-21 11:25:22 -0400595 uint32_t startIndex, uint32_t len, int numGlyphs, float radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700596 checkInit();
597
Romain Guycf51a412013-04-08 19:40:31 -0700598 DropShadow image;
599 image.width = 0;
600 image.height = 0;
Chris Craikd41c4d82015-01-05 15:51:13 -0800601 image.image = nullptr;
Romain Guycf51a412013-04-08 19:40:31 -0700602 image.penX = 0;
603 image.penY = 0;
604
Romain Guy1e45aae2010-08-13 19:39:53 -0700605 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700606 return image;
607 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700608
Romain Guy2d4fd362011-12-13 22:00:19 -0800609 mDrawn = false;
Chris Craikd41c4d82015-01-05 15:51:13 -0800610 mClip = nullptr;
611 mBounds = nullptr;
Romain Guyff98fa52011-11-28 09:35:09 -0800612
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700613 Rect bounds;
Raph Levien416a8472012-07-19 22:48:17 -0700614 mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800615
Derek Sollenbergere392c812014-05-21 11:25:22 -0400616 uint32_t intRadius = Blur::convertRadiusToInt(radius);
617 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
618 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
Romain Guyff98fa52011-11-28 09:35:09 -0800619
Romain Guycf51a412013-04-08 19:40:31 -0700620 uint32_t maxSize = Caches::getInstance().maxTextureSize;
621 if (paddedWidth > maxSize || paddedHeight > maxSize) {
622 return image;
623 }
624
Dan Morrille4d9a012013-03-28 18:10:43 -0700625#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800626 // Align buffers for renderscript usage
627 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
628 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700629 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800630 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800631 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700632#else
633 int size = paddedWidth * paddedHeight;
634 uint8_t* dataBuffer = (uint8_t*) malloc(size);
635#endif
636
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800637 memset(dataBuffer, 0, size);
638
Derek Sollenbergere392c812014-05-21 11:25:22 -0400639 int penX = intRadius - bounds.left;
640 int penY = intRadius - bounds.bottom;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700641
Chris Craikdd8697c2013-02-22 10:41:36 -0800642 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
643 // text has non-whitespace, so draw and blur to create the shadow
644 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
645 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
646 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
Chris Craikd41c4d82015-01-05 15:51:13 -0800647 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
Chris Craikdd8697c2013-02-22 10:41:36 -0800648
Romain Guycf51a412013-04-08 19:40:31 -0700649 // Unbind any PBO we might have used
Chris Craik44eb2c02015-01-29 09:45:09 -0800650 Caches::getInstance().pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700651
Chris Craikdd8697c2013-02-22 10:41:36 -0800652 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
653 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700654
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700655 image.width = paddedWidth;
656 image.height = paddedHeight;
657 image.image = dataBuffer;
658 image.penX = penX;
659 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800660
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700661 return image;
662}
Romain Guy694b5192010-07-21 21:33:20 -0700663
Chris Craik96a5c4c2015-01-27 15:46:35 -0800664void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextSetupFunctor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700665 checkInit();
666
Romain Guy5b3b3522010-10-27 18:57:51 -0700667 mDrawn = false;
668 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700669 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700670 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800671}
Romain Guyff98fa52011-11-28 09:35:09 -0800672
Romain Guy671d6cf2012-01-18 12:39:17 -0800673void FontRenderer::finishRender() {
Chris Craikd41c4d82015-01-05 15:51:13 -0800674 mBounds = nullptr;
675 mClip = nullptr;
Romain Guy694b5192010-07-21 21:33:20 -0700676
Romain Guy661a87e2013-03-19 15:24:36 -0700677 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800678}
679
Chris Craikd218a922014-01-02 17:13:34 -0800680void FontRenderer::precache(const SkPaint* paint, const char* text, int numGlyphs,
Chris Craik59744b72014-07-01 17:56:52 -0700681 const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800682 Font* font = Font::create(this, paint, matrix);
Chet Haasee816bae2012-08-09 13:39:02 -0700683 font->precache(paint, text, numGlyphs);
684}
685
Romain Guycf51a412013-04-08 19:40:31 -0700686void FontRenderer::endPrecaching() {
687 checkTextureUpdate();
688}
689
Chris Craikd218a922014-01-02 17:13:34 -0800690bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
Romain Guy671d6cf2012-01-18 12:39:17 -0800691 uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
Chris Craik96a5c4c2015-01-27 15:46:35 -0800692 const float* positions, Rect* bounds, TextSetupFunctor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800693 if (!mCurrentFont) {
694 ALOGE("No font set");
695 return false;
696 }
697
Romain Guy257ae352013-03-20 16:31:12 -0700698 initRender(clip, bounds, functor);
Romain Guy671d6cf2012-01-18 12:39:17 -0800699 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800700
701 if (forceFinish) {
702 finishRender();
703 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700704
705 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700706}
707
Chris Craikd218a922014-01-02 17:13:34 -0800708bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
709 uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
Chris Craik96a5c4c2015-01-27 15:46:35 -0800710 float hOffset, float vOffset, Rect* bounds, TextSetupFunctor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800711 if (!mCurrentFont) {
712 ALOGE("No font set");
713 return false;
714 }
715
Victoria Lease1e546812013-06-25 14:25:17 -0700716 initRender(clip, bounds, functor);
Romain Guy97771732012-02-28 18:17:02 -0800717 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
718 finishRender();
719
720 return mDrawn;
721}
722
Romain Guy9b1204b2012-09-04 15:22:57 -0700723void FontRenderer::removeFont(const Font* font) {
Romain Guye3a9b242013-01-08 11:15:30 -0800724 mActiveFonts.remove(font->getDescription());
Romain Guy9b1204b2012-09-04 15:22:57 -0700725
726 if (mCurrentFont == font) {
Chris Craikd41c4d82015-01-05 15:51:13 -0800727 mCurrentFont = nullptr;
Romain Guy9b1204b2012-09-04 15:22:57 -0700728 }
729}
730
Derek Sollenbergere392c812014-05-21 11:25:22 -0400731void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
732 uint32_t intRadius = Blur::convertRadiusToInt(radius);
Dan Morrille4d9a012013-03-28 18:10:43 -0700733#ifdef ANDROID_ENABLE_RENDERSCRIPT
Derek Sollenbergere392c812014-05-21 11:25:22 -0400734 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700735 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700736
Chris Craikd41c4d82015-01-05 15:51:13 -0800737 if (mRs == nullptr) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700738 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800739 // a null path is OK because there are no custom kernels used
740 // hence nothing gets cached by RS
741 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800742 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700743 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800744 } else {
745 mRsElement = RSC::Element::A_8(mRs);
746 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700747 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800748 }
Chris Craikd41c4d82015-01-05 15:51:13 -0800749 if (mRs != nullptr) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800750 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
751 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
752 RS_ALLOCATION_MIPMAP_NONE,
753 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
754 *image);
755 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
756 RS_ALLOCATION_MIPMAP_NONE,
757 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
758 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800759
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800760 mRsScript->setRadius(radius);
761 mRsScript->setInput(ain);
762 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700763
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800764 // replace the original image's pointer, avoiding a copy back to the original buffer
765 free(*image);
766 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700767
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800768 return;
769 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800770 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700771#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800772
Chris Craik51d6a3d2014-12-22 17:16:56 -0800773 std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
774 Blur::generateGaussianWeights(gaussian.get(), intRadius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800775
Chris Craik51d6a3d2014-12-22 17:16:56 -0800776 std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
777 Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
778 Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700779}
780
Victoria Lease1e546812013-06-25 14:25:17 -0700781static uint32_t calculateCacheSize(const Vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700782 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700783 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
784 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700785 if (cacheTexture && cacheTexture->getPixelBuffer()) {
786 size += cacheTexture->getPixelBuffer()->getSize();
787 }
788 }
789 return size;
790}
791
Victoria Lease1e546812013-06-25 14:25:17 -0700792uint32_t FontRenderer::getCacheSize(GLenum format) const {
793 switch (format) {
794 case GL_ALPHA: {
795 return calculateCacheSize(mACacheTextures);
796 }
797 case GL_RGBA: {
798 return calculateCacheSize(mRGBACacheTextures);
799 }
800 default: {
801 return 0;
802 }
803 }
804}
805
Romain Guy694b5192010-07-21 21:33:20 -0700806}; // namespace uirenderer
807}; // namespace android