blob: 6bef7c7a807f94a42841dab69af2bf64f94de370 [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 "OpenGLRenderer.h"
25#include "PixelBuffer.h"
26#include "Rect.h"
27#include "renderstate/RenderState.h"
28#include "utils/Blur.h"
Chris Craik083e7332015-02-27 17:04:20 -080029#include "utils/MathUtils.h"
Chris Craik96a5c4c2015-01-27 15:46:35 -080030#include "utils/Timing.h"
Romain Guy694b5192010-07-21 21:33:20 -070031
Derek Sollenbergerca79cf62012-08-14 16:44:52 -040032#include <SkGlyph.h>
Romain Guy694b5192010-07-21 21:33:20 -070033#include <SkUtils.h>
34
Romain Guy51769a62010-07-23 00:28:00 -070035#include <cutils/properties.h>
Romain Guye2d345e2010-09-24 18:39:22 -070036
Romain Guy51769a62010-07-23 00:28:00 -070037#include <utils/Log.h>
38
Dan Morrille4d9a012013-03-28 18:10:43 -070039#ifdef ANDROID_ENABLE_RENDERSCRIPT
Romain Guy6e200402013-03-08 11:28:22 -080040#include <RenderScript.h>
Dan Morrille4d9a012013-03-28 18:10:43 -070041#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -080042
Romain Guy694b5192010-07-21 21:33:20 -070043namespace android {
44namespace uirenderer {
45
Chris Craikf2d8ccc2013-02-13 16:14:17 -080046// blur inputs smaller than this constant will bypass renderscript
47#define RS_MIN_INPUT_CUTOFF 10000
48
Chris Craike2bb3802015-03-13 15:07:52 -070049#define USE_GLOPS true
50
Romain Guy694b5192010-07-21 21:33:20 -070051///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070052// TextSetupFunctor
53///////////////////////////////////////////////////////////////////////////////
Chris Craike2bb3802015-03-13 15:07:52 -070054void TextSetupFunctor::setup(GLenum glyphFormat) {
Victoria Lease1e546812013-06-25 14:25:17 -070055 renderer->setupDraw();
56 renderer->setupDrawTextGamma(paint);
57 renderer->setupDrawDirtyRegionsDisabled();
58 renderer->setupDrawWithTexture(glyphFormat == GL_ALPHA);
59 switch (glyphFormat) {
60 case GL_ALPHA: {
61 renderer->setupDrawAlpha8Color(paint->getColor(), alpha);
62 break;
63 }
64 case GL_RGBA: {
65 float floatAlpha = alpha / 255.0f;
66 renderer->setupDrawColor(floatAlpha, floatAlpha, floatAlpha, floatAlpha);
67 break;
68 }
69 default: {
70#if DEBUG_FONT_RENDERER
71 ALOGD("TextSetupFunctor: called with unknown glyph format %x", glyphFormat);
72#endif
73 break;
74 }
75 }
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -050076 renderer->setupDrawColorFilter(paint->getColorFilter());
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -040077 renderer->setupDrawShader(paint->getShader());
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -050078 renderer->setupDrawBlending(paint);
Victoria Lease1e546812013-06-25 14:25:17 -070079 renderer->setupDrawProgram();
Chris Craik4063a0e2013-11-15 16:06:56 -080080 renderer->setupDrawModelView(kModelViewMode_Translate, false,
81 0.0f, 0.0f, 0.0f, 0.0f, pureTranslate);
Victoria Lease1e546812013-06-25 14:25:17 -070082 // Calling setupDrawTexture with the name 0 will enable the
83 // uv attributes and increase the texture unit count
84 // texture binding will be performed by the font renderer as
85 // needed
86 renderer->setupDrawTexture(0);
87 renderer->setupDrawPureColorUniforms();
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -050088 renderer->setupDrawColorFilterUniforms(paint->getColorFilter());
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -040089 renderer->setupDrawShaderUniforms(paint->getShader(), pureTranslate);
Victoria Lease1e546812013-06-25 14:25:17 -070090 renderer->setupDrawTextGammaUniforms();
Chris Craike2bb3802015-03-13 15:07:52 -070091}
Victoria Lease1e546812013-06-25 14:25:17 -070092
Chris Craike2bb3802015-03-13 15:07:52 -070093void TextSetupFunctor::draw(CacheTexture& texture, bool linearFiltering) {
94 int textureFillFlags = static_cast<int>(texture.getFormat() == GL_ALPHA
95 ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone);
96 if (linearFiltering) {
97 textureFillFlags |= TextureFillFlags::kForceFilter;
98 }
99 const Matrix4& transform = pureTranslate ? Matrix4::identity() : *(renderer->currentTransform());
100 Glop glop;
101 GlopBuilder(renderer->mRenderState, renderer->mCaches, &glop)
102 .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
103 .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, renderer->currentSnapshot()->alpha)
104 .setTransform(renderer->currentSnapshot()->getOrthoMatrix(), transform, false)
105 .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
106 .setRoundRectClipState(renderer->currentSnapshot()->roundRectClipState)
107 .build();
108 renderer->renderGlop(glop);
Victoria Lease1e546812013-06-25 14:25:17 -0700109}
110
111///////////////////////////////////////////////////////////////////////////////
Romain Guy694b5192010-07-21 21:33:20 -0700112// FontRenderer
113///////////////////////////////////////////////////////////////////////////////
114
Romain Guy514fb182011-01-19 14:38:29 -0800115static bool sLogFontRendererCreate = true;
116
Chris Craik083e7332015-02-27 17:04:20 -0800117FontRenderer::FontRenderer()
118 : mGammaTable(nullptr)
119 , mCurrentFont(nullptr)
120 , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity)
121 , mCurrentCacheTexture(nullptr)
122 , mUploadTexture(false)
123 , mFunctor(nullptr)
124 , mClip(nullptr)
125 , mBounds(nullptr)
126 , mDrawn(false)
127 , mInitialized(false)
128 , mLinearFiltering(false) {
Romain Guye3a9b242013-01-08 11:15:30 -0800129
Romain Guyc9855a52011-01-21 21:14:15 -0800130 if (sLogFontRendererCreate) {
131 INIT_LOGD("Creating FontRenderer");
132 }
Romain Guy51769a62010-07-23 00:28:00 -0700133
Chet Haaseeb32a492012-08-31 13:54:03 -0700134 mSmallCacheWidth = DEFAULT_TEXT_SMALL_CACHE_WIDTH;
135 mSmallCacheHeight = DEFAULT_TEXT_SMALL_CACHE_HEIGHT;
136 mLargeCacheWidth = DEFAULT_TEXT_LARGE_CACHE_WIDTH;
137 mLargeCacheHeight = DEFAULT_TEXT_LARGE_CACHE_HEIGHT;
Romain Guy51769a62010-07-23 00:28:00 -0700138
139 char property[PROPERTY_VALUE_MAX];
Chris Craikd41c4d82015-01-05 15:51:13 -0800140 if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, nullptr) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800141 mSmallCacheWidth = atoi(property);
Romain Guy51769a62010-07-23 00:28:00 -0700142 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700143
Chris Craikd41c4d82015-01-05 15:51:13 -0800144 if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, nullptr) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800145 mSmallCacheHeight = atoi(property);
Chet Haaseeb32a492012-08-31 13:54:03 -0700146 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700147
Chris Craikd41c4d82015-01-05 15:51:13 -0800148 if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, nullptr) > 0) {
Chet Haaseeb32a492012-08-31 13:54:03 -0700149 mLargeCacheWidth = atoi(property);
150 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700151
Chris Craikd41c4d82015-01-05 15:51:13 -0800152 if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, nullptr) > 0) {
Chet Haaseeb32a492012-08-31 13:54:03 -0700153 mLargeCacheHeight = atoi(property);
154 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700155
156 uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
Chris Craik083e7332015-02-27 17:04:20 -0800157
158 mSmallCacheWidth = MathUtils::min(mSmallCacheWidth, maxTextureSize);
159 mSmallCacheHeight = MathUtils::min(mSmallCacheHeight, maxTextureSize);
160 mLargeCacheWidth = MathUtils::min(mLargeCacheWidth, maxTextureSize);
161 mLargeCacheHeight = MathUtils::min(mLargeCacheHeight, maxTextureSize);
Romain Guy9f5dab32012-09-04 12:55:44 -0700162
Chet Haaseeb32a492012-08-31 13:54:03 -0700163 if (sLogFontRendererCreate) {
164 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
165 mSmallCacheWidth, mSmallCacheHeight,
166 mLargeCacheWidth, mLargeCacheHeight >> 1,
167 mLargeCacheWidth, mLargeCacheHeight >> 1,
168 mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700169 }
Romain Guy514fb182011-01-19 14:38:29 -0800170
171 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700172}
173
Victoria Lease1e546812013-06-25 14:25:17 -0700174void clearCacheTextures(Vector<CacheTexture*>& cacheTextures) {
175 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
176 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700177 }
Victoria Lease1e546812013-06-25 14:25:17 -0700178 cacheTextures.clear();
179}
180
181FontRenderer::~FontRenderer() {
182 clearCacheTextures(mACacheTextures);
183 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700184
Romain Guye3a9b242013-01-08 11:15:30 -0800185 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
186 while (it.next()) {
187 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700188 }
Romain Guye3a9b242013-01-08 11:15:30 -0800189 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700190}
191
192void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700193 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700194
Romain Guye3a9b242013-01-08 11:15:30 -0800195 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
196 while (it.next()) {
197 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700198 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700199
Victoria Lease1e546812013-06-25 14:25:17 -0700200 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
201 mACacheTextures[i]->init();
202 }
203
204 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
205 mRGBACacheTextures[i]->init();
Romain Guy694b5192010-07-21 21:33:20 -0700206 }
207}
208
Victoria Lease1e546812013-06-25 14:25:17 -0700209void FontRenderer::flushLargeCaches(Vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700210 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700211 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
212 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700213 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700214 cacheTexture->init();
Romain Guye3a9b242013-01-08 11:15:30 -0800215 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
216 while (it.next()) {
217 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700218 }
Chris Craike2bb3802015-03-13 15:07:52 -0700219 cacheTexture->releasePixelBuffer();
Chet Haase9a824562011-12-16 15:44:59 -0800220 }
221 }
Chet Haase9a824562011-12-16 15:44:59 -0800222}
223
Victoria Lease1e546812013-06-25 14:25:17 -0700224void FontRenderer::flushLargeCaches() {
225 flushLargeCaches(mACacheTextures);
226 flushLargeCaches(mRGBACacheTextures);
227}
228
229CacheTexture* FontRenderer::cacheBitmapInTexture(Vector<CacheTexture*>& cacheTextures,
230 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
231 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
232 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
233 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700234 }
235 }
236 // Could not fit glyph into current cache textures
Chris Craikd41c4d82015-01-05 15:51:13 -0800237 return nullptr;
Chet Haase378e9192012-08-15 15:54:54 -0700238}
239
Chet Haase7de0cb12011-12-05 16:35:38 -0800240void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700241 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700242 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800243
244 // If the glyph bitmap is empty let's assum the glyph is valid
245 // so we can avoid doing extra work later on
246 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
247 cachedGlyph->mIsValid = true;
Chris Craikd41c4d82015-01-05 15:51:13 -0800248 cachedGlyph->mCacheTexture = nullptr;
Romain Guya4adcf02013-02-28 12:15:35 -0800249 return;
250 }
251
Chet Haase7de0cb12011-12-05 16:35:38 -0800252 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800253
Victoria Lease1e546812013-06-25 14:25:17 -0700254 // choose an appropriate cache texture list for this glyph format
255 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
Chris Craikd41c4d82015-01-05 15:51:13 -0800256 Vector<CacheTexture*>* cacheTextures = nullptr;
Victoria Lease1e546812013-06-25 14:25:17 -0700257 switch (format) {
258 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700259 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700260 cacheTextures = &mACacheTextures;
261 break;
262 case SkMask::kARGB32_Format:
263 cacheTextures = &mRGBACacheTextures;
264 break;
265 default:
266#if DEBUG_FONT_RENDERER
267 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
268#endif
269 return;
270 }
271
Romain Guy694b5192010-07-21 21:33:20 -0700272 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700273 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700274 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700275 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
276 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800277 return;
Romain Guy694b5192010-07-21 21:33:20 -0700278 }
279
280 // Now copy the bitmap into the cache texture
281 uint32_t startX = 0;
282 uint32_t startY = 0;
283
Victoria Lease1e546812013-06-25 14:25:17 -0700284 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700285
Chet Haase378e9192012-08-15 15:54:54 -0700286 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700287 if (!precaching) {
288 // If the new glyph didn't fit and we are not just trying to precache it,
289 // clear out the cache and try again
290 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700291 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700292 }
Romain Guy694b5192010-07-21 21:33:20 -0700293
Chet Haase378e9192012-08-15 15:54:54 -0700294 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700295 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800296 return;
Romain Guy694b5192010-07-21 21:33:20 -0700297 }
298 }
299
Chet Haase378e9192012-08-15 15:54:54 -0700300 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800301
Romain Guy694b5192010-07-21 21:33:20 -0700302 *retOriginX = startX;
303 *retOriginY = startY;
304
305 uint32_t endX = startX + glyph.fWidth;
306 uint32_t endY = startY + glyph.fHeight;
307
Romain Guy80872462012-09-04 16:42:01 -0700308 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700309
Romain Guycf51a412013-04-08 19:40:31 -0700310 if (!cacheTexture->getPixelBuffer()) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800311 Caches::getInstance().textureState().activateTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800312 // Large-glyph texture memory is allocated only as needed
Chris Craike2bb3802015-03-13 15:07:52 -0700313 cacheTexture->allocatePixelBuffer();
Chet Haase7de0cb12011-12-05 16:35:38 -0800314 }
Romain Guy661a87e2013-03-19 15:24:36 -0700315 if (!cacheTexture->mesh()) {
316 cacheTexture->allocateMesh();
317 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700318
Romain Guycf51a412013-04-08 19:40:31 -0700319 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700320 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
321 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700322
Romain Guyb969a0d2013-02-05 14:38:40 -0800323 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800324 switch (format) {
325 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700326 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
327 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
328 - TEXTURE_BORDER_SIZE;
329 // write leading border line
330 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
331 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800332 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700333 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800334 row = cacheY * cacheWidth;
335 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800336 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
337 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800338 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800339 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800340 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800341 }
342 } else {
Victoria Lease1e546812013-06-25 14:25:17 -0700343 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800344 row = cacheY * cacheWidth;
345 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
346 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
347 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800348 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700349 }
Victoria Lease1e546812013-06-25 14:25:17 -0700350 // write trailing border line
351 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
352 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
353 break;
354 }
355 case SkMask::kARGB32_Format: {
356 // prep data lengths
357 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
358 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
359 size_t rowSize = formatSize * glyph.fWidth;
360 // prep advances
361 size_t dstStride = formatSize * cacheWidth;
362 // prep indices
363 // - we actually start one row early, and then increment before first copy
364 uint8_t* src = &bitmapBuffer[0 - srcStride];
365 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
366 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
367 uint8_t* dstL = dst - borderSize;
368 uint8_t* dstR = dst + rowSize;
369 // write leading border line
370 memset(dstL, 0, rowSize + 2 * borderSize);
371 // write glyph data
372 while (dst < dstEnd) {
373 memset(dstL += dstStride, 0, borderSize); // leading border column
374 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
375 memset(dstR += dstStride, 0, borderSize); // trailing border column
376 }
377 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700378 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800379 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700380 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800381 case SkMask::kBW_Format: {
Andreas Gampe1e196742014-11-10 15:23:43 -0800382 uint32_t cacheX = 0, cacheY = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700383 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
384 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800385 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700386 // write leading border line
387 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
388 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800389 for (cacheY = startY; cacheY < endY; cacheY++) {
390 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700391 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800392 uint8_t* buffer = bitmapBuffer;
393
Romain Guy0b58a3d2013-03-05 12:16:27 -0800394 row = cacheY * cacheWidth;
395 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800396 while (--rowBytes >= 0) {
397 uint8_t b = *buffer++;
398 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
399 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
400 }
401 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800402 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800403
Victoria Lease1e546812013-06-25 14:25:17 -0700404 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700405 }
Victoria Lease1e546812013-06-25 14:25:17 -0700406 // write trailing border line
407 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
408 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800409 break;
Romain Guy694b5192010-07-21 21:33:20 -0700410 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800411 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700412 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800413 break;
Romain Guy694b5192010-07-21 21:33:20 -0700414 }
Romain Guy97771732012-02-28 18:17:02 -0800415
Chet Haase7de0cb12011-12-05 16:35:38 -0800416 cachedGlyph->mIsValid = true;
Romain Guy694b5192010-07-21 21:33:20 -0700417}
418
Victoria Lease1e546812013-06-25 14:25:17 -0700419CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
420 bool allocate) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800421 CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700422
Chet Haase2a47c142011-12-14 15:22:56 -0800423 if (allocate) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800424 Caches::getInstance().textureState().activateTexture(0);
Chris Craike2bb3802015-03-13 15:07:52 -0700425 cacheTexture->allocatePixelBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700426 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800427 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700428
Chet Haase2a47c142011-12-14 15:22:56 -0800429 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800430}
431
432void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700433 clearCacheTextures(mACacheTextures);
434 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700435
Chet Haase7de0cb12011-12-05 16:35:38 -0800436 mUploadTexture = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700437 mACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
438 GL_ALPHA, true));
439 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
440 GL_ALPHA, false));
441 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
442 GL_ALPHA, false));
443 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
444 GL_ALPHA, false));
445 mRGBACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
446 GL_RGBA, false));
447 mRGBACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
448 GL_RGBA, false));
449 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700450}
451
Romain Guy694b5192010-07-21 21:33:20 -0700452// We don't want to allocate anything unless we actually draw text
453void FontRenderer::checkInit() {
454 if (mInitialized) {
455 return;
456 }
457
458 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700459
460 mInitialized = true;
461}
462
Victoria Lease1e546812013-06-25 14:25:17 -0700463void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheTextures,
464 bool& resetPixelStore, GLuint& lastTextureId) {
465 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
466 CacheTexture* cacheTexture = cacheTextures[i];
467 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
468 if (cacheTexture->getTextureId() != lastTextureId) {
469 lastTextureId = cacheTexture->getTextureId();
Chris Craik44eb2c02015-01-29 09:45:09 -0800470 caches.textureState().activateTexture(0);
471 caches.textureState().bindTexture(lastTextureId);
Victoria Lease1e546812013-06-25 14:25:17 -0700472 }
473
474 if (cacheTexture->upload()) {
475 resetPixelStore = true;
476 }
477 }
478 }
479}
480
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700481void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900482 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700483 return;
Romain Guy694b5192010-07-21 21:33:20 -0700484 }
485
Romain Guy2d4fd362011-12-13 22:00:19 -0800486 Caches& caches = Caches::getInstance();
487 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700488
Romain Guycf51a412013-04-08 19:40:31 -0700489 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700490 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
491
Chet Haase378e9192012-08-15 15:54:54 -0700492 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700493 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
494 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700495
Romain Guycf51a412013-04-08 19:40:31 -0700496 // Unbind any PBO we might have used to update textures
Chris Craik44eb2c02015-01-29 09:45:09 -0800497 caches.pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700498
Romain Guy09087642013-04-04 12:27:54 -0700499 // Reset to default unpack row length to avoid affecting texture
500 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700501 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700502 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
503 }
504
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700505 mUploadTexture = false;
506}
507
Victoria Lease1e546812013-06-25 14:25:17 -0700508void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800509 if (!mFunctor) return;
510
Chris Craikc6128ba2015-03-19 10:00:56 -0700511#if !USE_GLOPS
Chris Craik96a5c4c2015-01-27 15:46:35 -0800512 Caches& caches = mFunctor->renderer->getCaches();
513 RenderState& renderState = mFunctor->renderer->renderState();
Chris Craikc6128ba2015-03-19 10:00:56 -0700514#endif
Chris Craik96a5c4c2015-01-27 15:46:35 -0800515
Romain Guy661a87e2013-03-19 15:24:36 -0700516 bool first = true;
Chris Craik96a5c4c2015-01-27 15:46:35 -0800517 bool forceRebind = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700518 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
519 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700520 if (texture->canDraw()) {
521 if (first) {
Chris Craike2bb3802015-03-13 15:07:52 -0700522 checkTextureUpdate();
523#if !USE_GLOPS
Chris Craik083e7332015-02-27 17:04:20 -0800524 mFunctor->setup(texture->getFormat());
Romain Guy257ae352013-03-20 16:31:12 -0700525
Chris Craik96a5c4c2015-01-27 15:46:35 -0800526 renderState.meshState().bindQuadIndicesBuffer();
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900527
Chris Craik083e7332015-02-27 17:04:20 -0800528 // If returns true, a VBO was bound and we must
529 // rebind our vertex attrib pointers even if
530 // they have the same values as the current pointers
531 forceRebind = renderState.meshState().unbindMeshBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700532
Chris Craik44eb2c02015-01-29 09:45:09 -0800533 caches.textureState().activateTexture(0);
Chris Craike2bb3802015-03-13 15:07:52 -0700534#endif
Romain Guy661a87e2013-03-19 15:24:36 -0700535 first = false;
Chris Craik083e7332015-02-27 17:04:20 -0800536 mDrawn = true;
Romain Guy661a87e2013-03-19 15:24:36 -0700537 }
Chris Craike2bb3802015-03-13 15:07:52 -0700538#if USE_GLOPS
539 mFunctor->draw(*texture, mLinearFiltering);
540#endif
Romain Guy661a87e2013-03-19 15:24:36 -0700541
Chris Craike2bb3802015-03-13 15:07:52 -0700542#if !USE_GLOPS
Chris Craik44eb2c02015-01-29 09:45:09 -0800543 caches.textureState().bindTexture(texture->getTextureId());
Chris Craike2bb3802015-03-13 15:07:52 -0700544 texture->setLinearFiltering(mLinearFiltering);
Romain Guy661a87e2013-03-19 15:24:36 -0700545
546 TextureVertex* mesh = texture->mesh();
Chris Craik96a5c4c2015-01-27 15:46:35 -0800547 MeshState& meshState = renderState.meshState();
Chris Craik6c15ffa2015-02-02 13:50:55 -0800548 meshState.bindPositionVertexPointer(forceRebind, &mesh[0].x);
549 meshState.bindTexCoordsVertexPointer(forceRebind, &mesh[0].u);
Romain Guy661a87e2013-03-19 15:24:36 -0700550
551 glDrawElements(GL_TRIANGLES, texture->meshElementCount(),
552 GL_UNSIGNED_SHORT, texture->indices());
Chris Craike2bb3802015-03-13 15:07:52 -0700553#endif
Romain Guy661a87e2013-03-19 15:24:36 -0700554 texture->resetMesh();
Chris Craik96a5c4c2015-01-27 15:46:35 -0800555 forceRebind = false;
Romain Guy115096f2013-03-19 11:32:41 -0700556 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900557 }
Victoria Lease1e546812013-06-25 14:25:17 -0700558}
559
560void FontRenderer::issueDrawCommand() {
561 issueDrawCommand(mACacheTextures);
562 issueDrawCommand(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700563}
564
Romain Guy97771732012-02-28 18:17:02 -0800565void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
566 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800567 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800568 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800569 // Now use the new texture id
570 mCurrentCacheTexture = texture;
571 }
Romain Guy09147fb2010-07-22 13:08:20 -0700572
Romain Guy661a87e2013-03-19 15:24:36 -0700573 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
574 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800575}
576
577void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
578 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
579 float x4, float y4, float u4, float v4, CacheTexture* texture) {
580
581 if (mClip &&
582 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
583 return;
584 }
585
586 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 -0700587
Romain Guy5b3b3522010-10-27 18:57:51 -0700588 if (mBounds) {
589 mBounds->left = fmin(mBounds->left, x1);
590 mBounds->top = fmin(mBounds->top, y3);
591 mBounds->right = fmax(mBounds->right, x3);
592 mBounds->bottom = fmax(mBounds->bottom, y1);
593 }
594
Romain Guy661a87e2013-03-19 15:24:36 -0700595 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700596 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700597 }
598}
599
Romain Guy97771732012-02-28 18:17:02 -0800600void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
601 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
602 float x4, float y4, float u4, float v4, CacheTexture* texture) {
603
604 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
605
606 if (mBounds) {
607 mBounds->left = fmin(mBounds->left, fmin(x1, fmin(x2, fmin(x3, x4))));
608 mBounds->top = fmin(mBounds->top, fmin(y1, fmin(y2, fmin(y3, y4))));
609 mBounds->right = fmax(mBounds->right, fmax(x1, fmax(x2, fmax(x3, x4))));
610 mBounds->bottom = fmax(mBounds->bottom, fmax(y1, fmax(y2, fmax(y3, y4))));
611 }
612
Romain Guy661a87e2013-03-19 15:24:36 -0700613 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800614 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800615 }
616}
617
Chris Craik59744b72014-07-01 17:56:52 -0700618void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800619 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700620}
Romain Guy7975fb62010-10-01 16:36:14 -0700621
Chris Craikd218a922014-01-02 17:13:34 -0800622FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const char *text,
Derek Sollenbergere392c812014-05-21 11:25:22 -0400623 uint32_t startIndex, uint32_t len, int numGlyphs, float radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700624 checkInit();
625
Romain Guycf51a412013-04-08 19:40:31 -0700626 DropShadow image;
627 image.width = 0;
628 image.height = 0;
Chris Craikd41c4d82015-01-05 15:51:13 -0800629 image.image = nullptr;
Romain Guycf51a412013-04-08 19:40:31 -0700630 image.penX = 0;
631 image.penY = 0;
632
Romain Guy1e45aae2010-08-13 19:39:53 -0700633 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700634 return image;
635 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700636
Romain Guy2d4fd362011-12-13 22:00:19 -0800637 mDrawn = false;
Chris Craikd41c4d82015-01-05 15:51:13 -0800638 mClip = nullptr;
639 mBounds = nullptr;
Romain Guyff98fa52011-11-28 09:35:09 -0800640
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700641 Rect bounds;
Raph Levien416a8472012-07-19 22:48:17 -0700642 mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800643
Derek Sollenbergere392c812014-05-21 11:25:22 -0400644 uint32_t intRadius = Blur::convertRadiusToInt(radius);
645 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
646 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
Romain Guyff98fa52011-11-28 09:35:09 -0800647
Romain Guycf51a412013-04-08 19:40:31 -0700648 uint32_t maxSize = Caches::getInstance().maxTextureSize;
649 if (paddedWidth > maxSize || paddedHeight > maxSize) {
650 return image;
651 }
652
Dan Morrille4d9a012013-03-28 18:10:43 -0700653#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800654 // Align buffers for renderscript usage
655 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
656 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700657 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800658 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800659 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700660#else
661 int size = paddedWidth * paddedHeight;
662 uint8_t* dataBuffer = (uint8_t*) malloc(size);
663#endif
664
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800665 memset(dataBuffer, 0, size);
666
Derek Sollenbergere392c812014-05-21 11:25:22 -0400667 int penX = intRadius - bounds.left;
668 int penY = intRadius - bounds.bottom;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700669
Chris Craikdd8697c2013-02-22 10:41:36 -0800670 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
671 // text has non-whitespace, so draw and blur to create the shadow
672 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
673 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
674 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
Chris Craikd41c4d82015-01-05 15:51:13 -0800675 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
Chris Craikdd8697c2013-02-22 10:41:36 -0800676
Romain Guycf51a412013-04-08 19:40:31 -0700677 // Unbind any PBO we might have used
Chris Craik44eb2c02015-01-29 09:45:09 -0800678 Caches::getInstance().pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700679
Chris Craikdd8697c2013-02-22 10:41:36 -0800680 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
681 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700682
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700683 image.width = paddedWidth;
684 image.height = paddedHeight;
685 image.image = dataBuffer;
686 image.penX = penX;
687 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800688
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700689 return image;
690}
Romain Guy694b5192010-07-21 21:33:20 -0700691
Chris Craik96a5c4c2015-01-27 15:46:35 -0800692void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextSetupFunctor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700693 checkInit();
694
Romain Guy5b3b3522010-10-27 18:57:51 -0700695 mDrawn = false;
696 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700697 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700698 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800699}
Romain Guyff98fa52011-11-28 09:35:09 -0800700
Romain Guy671d6cf2012-01-18 12:39:17 -0800701void FontRenderer::finishRender() {
Chris Craikd41c4d82015-01-05 15:51:13 -0800702 mBounds = nullptr;
703 mClip = nullptr;
Romain Guy694b5192010-07-21 21:33:20 -0700704
Romain Guy661a87e2013-03-19 15:24:36 -0700705 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800706}
707
Chris Craikd218a922014-01-02 17:13:34 -0800708void FontRenderer::precache(const SkPaint* paint, const char* text, int numGlyphs,
Chris Craik59744b72014-07-01 17:56:52 -0700709 const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800710 Font* font = Font::create(this, paint, matrix);
Chet Haasee816bae2012-08-09 13:39:02 -0700711 font->precache(paint, text, numGlyphs);
712}
713
Romain Guycf51a412013-04-08 19:40:31 -0700714void FontRenderer::endPrecaching() {
715 checkTextureUpdate();
716}
717
Chris Craikd218a922014-01-02 17:13:34 -0800718bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
Romain Guy671d6cf2012-01-18 12:39:17 -0800719 uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
Chris Craik96a5c4c2015-01-27 15:46:35 -0800720 const float* positions, Rect* bounds, TextSetupFunctor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800721 if (!mCurrentFont) {
722 ALOGE("No font set");
723 return false;
724 }
725
Romain Guy257ae352013-03-20 16:31:12 -0700726 initRender(clip, bounds, functor);
Romain Guy671d6cf2012-01-18 12:39:17 -0800727 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800728
729 if (forceFinish) {
730 finishRender();
731 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700732
733 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700734}
735
Chris Craikd218a922014-01-02 17:13:34 -0800736bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
737 uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
Chris Craik96a5c4c2015-01-27 15:46:35 -0800738 float hOffset, float vOffset, Rect* bounds, TextSetupFunctor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800739 if (!mCurrentFont) {
740 ALOGE("No font set");
741 return false;
742 }
743
Victoria Lease1e546812013-06-25 14:25:17 -0700744 initRender(clip, bounds, functor);
Romain Guy97771732012-02-28 18:17:02 -0800745 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
746 finishRender();
747
748 return mDrawn;
749}
750
Romain Guy9b1204b2012-09-04 15:22:57 -0700751void FontRenderer::removeFont(const Font* font) {
Romain Guye3a9b242013-01-08 11:15:30 -0800752 mActiveFonts.remove(font->getDescription());
Romain Guy9b1204b2012-09-04 15:22:57 -0700753
754 if (mCurrentFont == font) {
Chris Craikd41c4d82015-01-05 15:51:13 -0800755 mCurrentFont = nullptr;
Romain Guy9b1204b2012-09-04 15:22:57 -0700756 }
757}
758
Derek Sollenbergere392c812014-05-21 11:25:22 -0400759void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
760 uint32_t intRadius = Blur::convertRadiusToInt(radius);
Dan Morrille4d9a012013-03-28 18:10:43 -0700761#ifdef ANDROID_ENABLE_RENDERSCRIPT
Derek Sollenbergere392c812014-05-21 11:25:22 -0400762 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700763 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700764
Chris Craikd41c4d82015-01-05 15:51:13 -0800765 if (mRs == nullptr) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700766 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800767 // a null path is OK because there are no custom kernels used
768 // hence nothing gets cached by RS
769 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800770 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700771 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800772 } else {
773 mRsElement = RSC::Element::A_8(mRs);
774 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700775 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800776 }
Chris Craikd41c4d82015-01-05 15:51:13 -0800777 if (mRs != nullptr) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800778 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
779 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
780 RS_ALLOCATION_MIPMAP_NONE,
781 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
782 *image);
783 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
784 RS_ALLOCATION_MIPMAP_NONE,
785 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
786 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800787
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800788 mRsScript->setRadius(radius);
789 mRsScript->setInput(ain);
790 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700791
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800792 // replace the original image's pointer, avoiding a copy back to the original buffer
793 free(*image);
794 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700795
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800796 return;
797 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800798 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700799#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800800
Chris Craik51d6a3d2014-12-22 17:16:56 -0800801 std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
802 Blur::generateGaussianWeights(gaussian.get(), intRadius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800803
Chris Craik51d6a3d2014-12-22 17:16:56 -0800804 std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
805 Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
806 Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700807}
808
Victoria Lease1e546812013-06-25 14:25:17 -0700809static uint32_t calculateCacheSize(const Vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700810 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700811 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
812 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700813 if (cacheTexture && cacheTexture->getPixelBuffer()) {
814 size += cacheTexture->getPixelBuffer()->getSize();
815 }
816 }
817 return size;
818}
819
Victoria Lease1e546812013-06-25 14:25:17 -0700820uint32_t FontRenderer::getCacheSize(GLenum format) const {
821 switch (format) {
822 case GL_ALPHA: {
823 return calculateCacheSize(mACacheTextures);
824 }
825 case GL_RGBA: {
826 return calculateCacheSize(mRGBACacheTextures);
827 }
828 default: {
829 return 0;
830 }
831 }
832}
833
Romain Guy694b5192010-07-21 21:33:20 -0700834}; // namespace uirenderer
835}; // namespace android