blob: c30b8573a87241a2871e887c93dcfab1834a2674 [file] [log] [blame]
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -07001
2/*
3 * Copyright (C) 2009 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070018#include "rsContext.h"
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070019
20#include "rsFont.h"
21#include "rsProgramFragment.h"
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -070022#include <cutils/properties.h>
Alex Sakhartchouk02000b32011-02-25 09:34:33 -080023
24#include <ft2build.h>
25#include FT_FREETYPE_H
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070026#include FT_BITMAP_H
27
28#include <GLES/gl.h>
29#include <GLES/glext.h>
30#include <GLES2/gl2.h>
31#include <GLES2/gl2ext.h>
32
33using namespace android;
34using namespace android::renderscript;
35
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080036Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070037 mInitialized = false;
38 mHasKerning = false;
Alex Sakhartchouk3659d942010-06-30 16:53:43 -070039 mFace = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070040}
41
Alex Sakhartchouk5224a272011-01-07 11:12:08 -080042bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080043 if (mInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070044 LOGE("Reinitialization of fonts not supported");
45 return false;
46 }
47
Alex Sakhartchouk5224a272011-01-07 11:12:08 -080048 FT_Error error = 0;
49 if (data != NULL && dataLen > 0) {
50 error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
51 } else {
52 error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
53 }
54
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080055 if (error) {
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -080056 LOGE("Unable to initialize font %s", name);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070057 return false;
58 }
59
60 mFontName = name;
61 mFontSize = fontSize;
62 mDpi = dpi;
63
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -080064 error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080065 if (error) {
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -080066 LOGE("Unable to set font size on %s", name);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070067 return false;
68 }
69
70 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070071
72 mInitialized = true;
73 return true;
74}
75
Jason Sams2e8665d2011-01-27 00:14:13 -080076void Font::preDestroy() const {
77 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
78 if (mRSC->mStateFont.mActiveFonts[ct] == this) {
79 mRSC->mStateFont.mActiveFonts.removeAt(ct);
80 break;
81 }
82 }
83}
84
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080085void Font::invalidateTextureCache() {
86 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070087 mCachedGlyphs.valueAt(i)->mIsValid = false;
88 }
89}
90
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080091void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070092 FontState *state = &mRSC->mStateFont;
93
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070094 int32_t nPenX = x + glyph->mBitmapLeft;
95 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070096
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070097 float u1 = glyph->mBitmapMinU;
98 float u2 = glyph->mBitmapMaxU;
99 float v1 = glyph->mBitmapMinV;
100 float v2 = glyph->mBitmapMaxV;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700101
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700102 int32_t width = (int32_t) glyph->mBitmapWidth;
103 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700104
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700105 state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
106 nPenX + width, nPenY, 0, u2, v2,
107 nPenX + width, nPenY - height, 0, u2, v1,
108 nPenX, nPenY - height, 0, u1, v1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700109}
110
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700111void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
112 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
113 int32_t nPenX = x + glyph->mBitmapLeft;
114 int32_t nPenY = y + glyph->mBitmapTop;
115
116 uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
117 uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
118
119 FontState *state = &mRSC->mStateFont;
120 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
121 const uint8_t* cacheBuffer = state->getTextTextureData();
122
123 uint32_t cacheX = 0, cacheY = 0;
124 int32_t bX = 0, bY = 0;
125 for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
126 for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
127 if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
128 LOGE("Skipping invalid index");
129 continue;
130 }
131 uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
132 bitmap[bY * bitmapW + bX] = tempCol;
133 }
134 }
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700135}
136
137void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
138 int32_t nPenX = x + glyph->mBitmapLeft;
139 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
140
141 int32_t width = (int32_t) glyph->mBitmapWidth;
142 int32_t height = (int32_t) glyph->mBitmapHeight;
143
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800144 // 0, 0 is top left, so bottom is a positive number
145 if (bounds->bottom < nPenY) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700146 bounds->bottom = nPenY;
147 }
148 if (bounds->left > nPenX) {
149 bounds->left = nPenX;
150 }
151 if (bounds->right < nPenX + width) {
152 bounds->right = nPenX + width;
153 }
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800154 if (bounds->top > nPenY - height) {
155 bounds->top = nPenY - height;
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700156 }
157}
158
159void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
160 uint32_t start, int32_t numGlyphs,
161 RenderMode mode, Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800162 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
163 if (!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700164 return;
165 }
166
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800167 if (mode == Font::MEASURE) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700168 if (bounds == NULL) {
169 LOGE("No return rectangle provided to measure text");
170 return;
171 }
172 // Reset min and max of the bounding box to something large
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800173 bounds->set(1e6, -1e6, 1e6, -1e6);
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700174 }
175
176 int32_t penX = x, penY = y;
177 int32_t glyphsLeft = 1;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800178 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700179 glyphsLeft = numGlyphs;
180 }
181
182 size_t index = start;
183 size_t nextIndex = 0;
184
185 while (glyphsLeft > 0) {
186
Kenny Rootc9c38dd2010-11-09 14:37:23 -0800187 int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700188
189 // Reached the end of the string or encountered
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800190 if (utfChar < 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700191 break;
192 }
193
194 // Move to the next character in the array
195 index = nextIndex;
196
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700197 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700198
199 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800200 if (cachedGlyph->mIsValid) {
201 switch (mode) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700202 case FRAMEBUFFER:
203 drawCachedGlyph(cachedGlyph, penX, penY);
204 break;
205 case BITMAP:
206 drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
207 break;
208 case MEASURE:
209 measureCachedGlyph(cachedGlyph, penX, penY, bounds);
210 break;
211 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700212 }
213
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800214 penX += (cachedGlyph->mAdvanceX >> 6);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700215
216 // If we were given a specific number of glyphs, decrement
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800217 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700218 glyphsLeft --;
219 }
220 }
221}
222
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700223Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
224
225 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800226 if (cachedGlyph == NULL) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700227 cachedGlyph = cacheGlyph((uint32_t)utfChar);
228 }
229 // Is the glyph still in texture cache?
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800230 if (!cachedGlyph->mIsValid) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700231 updateGlyphCache(cachedGlyph);
232 }
233
234 return cachedGlyph;
235}
236
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800237void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700238 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800239 if (error) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700240 LOGE("Couldn't load glyph.");
241 return;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700242 }
243
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800244 glyph->mAdvanceX = mFace->glyph->advance.x;
245 glyph->mAdvanceY = mFace->glyph->advance.y;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700246 glyph->mBitmapLeft = mFace->glyph->bitmap_left;
247 glyph->mBitmapTop = mFace->glyph->bitmap_top;
248
249 FT_Bitmap *bitmap = &mFace->glyph->bitmap;
250
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700251 // Now copy the bitmap into the cache texture
252 uint32_t startX = 0;
253 uint32_t startY = 0;
254
255 // Let the font state figure out where to put the bitmap
256 FontState *state = &mRSC->mStateFont;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700257 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700258
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800259 if (!glyph->mIsValid) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700260 return;
261 }
262
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700263 uint32_t endX = startX + bitmap->width;
264 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700265
266 glyph->mBitmapMinX = startX;
267 glyph->mBitmapMinY = startY;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700268 glyph->mBitmapWidth = bitmap->width;
269 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700270
271 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
272 uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
273
274 glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
275 glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
276 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
277 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
278}
279
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800280Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700281 CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
282 mCachedGlyphs.add(glyph, newGlyph);
283
284 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
285 newGlyph->mIsValid = false;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700286
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700287 updateGlyphCache(newGlyph);
288
289 return newGlyph;
290}
291
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800292Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
293 const void *data, uint32_t dataLen) {
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700294 rsc->mStateFont.checkInit();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700295 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
296
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800297 for (uint32_t i = 0; i < activeFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700298 Font *ithFont = activeFonts[i];
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800299 if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700300 return ithFont;
301 }
302 }
303
304 Font *newFont = new Font(rsc);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800305 bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800306 if (isInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700307 activeFonts.push(newFont);
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700308 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700309 return newFont;
310 }
311
Jason Sams225afd32010-10-21 14:06:55 -0700312 ObjectBase::checkDelete(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700313 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700314}
315
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800316Font::~Font() {
317 if (mFace) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700318 FT_Done_Face(mFace);
319 }
320
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800321 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700322 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700323 delete glyph;
324 }
325}
326
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800327FontState::FontState() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700328 mInitialized = false;
329 mMaxNumberOfQuads = 1024;
330 mCurrentQuadIndex = 0;
331 mRSC = NULL;
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700332 mLibrary = NULL;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700333
334 // Get the renderer properties
335 char property[PROPERTY_VALUE_MAX];
336
337 // Get the gamma
338 float gamma = DEFAULT_TEXT_GAMMA;
339 if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700340 gamma = atof(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700341 }
342
343 // Get the black gamma threshold
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700344 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700345 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700346 blackThreshold = atoi(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700347 }
348 mBlackThreshold = (float)(blackThreshold) / 255.0f;
349
350 // Get the white gamma threshold
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700351 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700352 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700353 whiteThreshold = atoi(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700354 }
355 mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
356
357 // Compute the gamma tables
358 mBlackGamma = gamma;
359 mWhiteGamma = 1.0f / gamma;
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700360
361 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700362}
363
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800364FontState::~FontState() {
365 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700366 delete mCacheLines[i];
367 }
368
369 rsAssert(!mActiveFonts.size());
370}
371
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800372FT_Library FontState::getLib() {
373 if (!mLibrary) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700374 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800375 if (error) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700376 LOGE("Unable to initialize freetype");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700377 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700378 }
379 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700380
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700381 return mLibrary;
382}
383
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800384void FontState::init(Context *rsc) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700385 mRSC = rsc;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700386}
387
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800388void FontState::flushAllAndInvalidate() {
389 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700390 issueDrawCommand();
391 mCurrentQuadIndex = 0;
392 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800393 for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700394 mActiveFonts[i]->invalidateTextureCache();
395 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800396 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700397 mCacheLines[i]->mCurrentCol = 0;
398 }
399}
400
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800401bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700402 // If the glyph is too tall, don't cache it
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800403 if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700404 LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
405 return false;
406 }
407
408 // Now copy the bitmap into the cache texture
409 uint32_t startX = 0;
410 uint32_t startY = 0;
411
412 bool bitmapFit = false;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800413 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700414 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800415 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700416 break;
417 }
418 }
419
420 // If the new glyph didn't fit, flush the state so far and invalidate everything
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800421 if (!bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700422 flushAllAndInvalidate();
423
424 // Try to fit it again
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800425 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700426 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800427 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700428 break;
429 }
430 }
431
432 // if we still don't fit, something is wrong and we shouldn't draw
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800433 if (!bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700434 LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
435 return false;
436 }
437 }
438
439 *retOriginX = startX;
440 *retOriginY = startY;
441
442 uint32_t endX = startX + bitmap->width;
443 uint32_t endY = startY + bitmap->rows;
444
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700445 uint32_t cacheWidth = getCacheTextureType()->getDimX();
446
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700447 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
448 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700449
450 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800451 for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
452 for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700453 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700454 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
455 }
456 }
457
458 // This will dirty the texture and the shader so next time
459 // we draw it will upload the data
Jason Samsb7e83bd2010-12-15 01:41:00 -0800460 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700461 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700462
463 // Some debug code
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800464 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700465 LOGE("Cache Line: H: %u Empty Space: %f",
466 mCacheLines[i]->mMaxHeight,
467 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
468
469 }*/
470
471 return true;
472}
473
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800474void FontState::initRenderState() {
Alex Sakhartchouk7ffcaf22010-10-06 11:15:01 -0700475 String8 shaderString("varying vec2 varTex0;\n");
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700476 shaderString.append("void main() {\n");
477 shaderString.append(" lowp vec4 col = UNI_Color;\n");
478 shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700479 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700480 shaderString.append(" gl_FragColor = col;\n");
481 shaderString.append("}\n");
482
483 const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700484 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700485 mRSC->mStateElement.elementBuilderBegin();
486 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700487 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700488 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
489
Jason Samsf0c1df42010-10-26 13:09:17 -0700490 Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700491
492 uint32_t tmp[4];
493 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
494 tmp[1] = (uint32_t)inputType;
Alex Sakhartchouk84e40272010-11-18 15:22:43 -0800495 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
496 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700497
Jason Sams366c9c82010-12-08 16:14:36 -0800498 mFontShaderFConstant.set(new Allocation(mRSC, inputType,
499 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700500 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
501 shaderString.length(), tmp, 4);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700502 mFontShaderF.set(pf);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700503 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700504
505 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
506 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
507 mFontSampler.set(sampler);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700508 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700509
Jason Sams721acc42011-04-06 11:23:54 -0700510 ProgramStore *fontStore = new ProgramStore(mRSC, true, true, true, true,
511 false, false,
Jason Sams00237f12011-04-06 11:44:47 -0700512 RS_BLEND_SRC_SRC_ALPHA,
513 RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
Jason Sams721acc42011-04-06 11:23:54 -0700514 RS_DEPTH_FUNC_ALWAYS);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700515 mFontProgramStore.set(fontStore);
Jason Sams8feea4e2011-03-18 15:03:25 -0700516 mFontProgramStore->init();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700517}
518
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800519void FontState::initTextTexture() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700520 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
521
522 // We will allocate a texture to initially hold 32 character bitmaps
Jason Samsf0c1df42010-10-26 13:09:17 -0700523 Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700524
Jason Sams366c9c82010-12-08 16:14:36 -0800525 Allocation *cacheAlloc = new Allocation(mRSC, texType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700526 mTextTexture.set(cacheAlloc);
Jason Samsb7e83bd2010-12-15 01:41:00 -0800527 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700528
529 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700530 int32_t nextLine = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700531 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
532 nextLine += mCacheLines.top()->mMaxHeight;
533 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
534 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700535 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
536 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700537 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
538 nextLine += mCacheLines.top()->mMaxHeight;
539 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
540 nextLine += mCacheLines.top()->mMaxHeight;
541 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
542 nextLine += mCacheLines.top()->mMaxHeight;
543 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
544}
545
546// Avoid having to reallocate memory and render quad by quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800547void FontState::initVertexArrayBuffers() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700548 // Now lets write index data
549 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700550 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Jason Samsf0c1df42010-10-26 13:09:17 -0700551 Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700552
Jason Sams366c9c82010-12-08 16:14:36 -0800553 Allocation *indexAlloc = new Allocation(mRSC, indexType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700554 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
555
556 // Four verts, two triangles , six indices per quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800557 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700558 int32_t i6 = i * 6;
559 int32_t i4 = i * 4;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700560
561 indexPtr[i6 + 0] = i4 + 0;
562 indexPtr[i6 + 1] = i4 + 1;
563 indexPtr[i6 + 2] = i4 + 2;
564
565 indexPtr[i6 + 3] = i4 + 0;
566 indexPtr[i6 + 4] = i4 + 2;
567 indexPtr[i6 + 5] = i4 + 3;
568 }
569
Alex Sakhartchouk7d9c5ff2011-04-01 14:19:01 -0700570 indexAlloc->deferredUploadToBufferObject(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700571 mIndexBuffer.set(indexAlloc);
572
573 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
574 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
575
Alex Sakhartchouk64cd98e2010-10-18 17:18:50 -0700576 mRSC->mStateElement.elementBuilderBegin();
577 mRSC->mStateElement.elementBuilderAdd(posElem, "position", 1);
578 mRSC->mStateElement.elementBuilderAdd(texElem, "texture0", 1);
579 const Element *vertexDataElem = mRSC->mStateElement.elementBuilderCreate(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700580
Jason Samsf0c1df42010-10-26 13:09:17 -0700581 Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
582 mMaxNumberOfQuads * 4,
583 0, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700584
Jason Sams366c9c82010-12-08 16:14:36 -0800585 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700586 mTextMeshPtr = (float*)vertexAlloc->getPtr();
587
588 mVertexArray.set(vertexAlloc);
589}
590
591// We don't want to allocate anything unless we actually draw text
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800592void FontState::checkInit() {
593 if (mInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700594 return;
595 }
596
597 initTextTexture();
598 initRenderState();
599
600 initVertexArrayBuffers();
601
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700602 // We store a string with letters in a rough frequency of occurrence
603 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
604 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
605 mLatinPrecache += String8(",.?!()-+@;:`'");
606 mLatinPrecache += String8("0123456789");
607
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700608 mInitialized = true;
609}
610
611void FontState::issueDrawCommand() {
Jason Sams60709252010-11-17 15:29:32 -0800612 Context::PushState ps(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700613
Jason Sams60709252010-11-17 15:29:32 -0800614 mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
615 mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
616 mRSC->setProgramFragment(mFontShaderF.get());
617 mRSC->setProgramStore(mFontProgramStore.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700618
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800619 if (mConstantsDirty) {
Jason Sams4b45b892010-12-29 14:31:29 -0800620 mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700621 mConstantsDirty = false;
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700622 }
623
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700624 if (!mRSC->setupCheck()) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700625 return;
626 }
627
628 float *vtx = (float*)mVertexArray->getPtr();
629 float *tex = vtx + 3;
630
Alex Sakhartchouk54929cc2010-11-08 15:10:52 -0800631 VertexArray::Attrib attribs[2];
632 attribs[0].set(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
633 attribs[1].set(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
634 VertexArray va(attribs, 2);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700635 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
636
637 mIndexBuffer->uploadCheck(mRSC);
638 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
639 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700640}
641
642void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800643 float u1, float v1,
644 float x2, float y2, float z2,
645 float u2, float v2,
646 float x3, float y3, float z3,
647 float u3, float v3,
648 float x4, float y4, float z4,
649 float u4, float v4) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700650 const uint32_t vertsPerQuad = 4;
651 const uint32_t floatsPerVert = 5;
652 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
653
654 // Cull things that are off the screen
655 float width = (float)mRSC->getWidth();
656 float height = (float)mRSC->getHeight();
657
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800658 if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700659 return;
660 }
661
662 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
663 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
664 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
665 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
666
667 (*currentPos++) = x1;
668 (*currentPos++) = y1;
669 (*currentPos++) = z1;
670 (*currentPos++) = u1;
671 (*currentPos++) = v1;
672
673 (*currentPos++) = x2;
674 (*currentPos++) = y2;
675 (*currentPos++) = z2;
676 (*currentPos++) = u2;
677 (*currentPos++) = v2;
678
679 (*currentPos++) = x3;
680 (*currentPos++) = y3;
681 (*currentPos++) = z3;
682 (*currentPos++) = u3;
683 (*currentPos++) = v3;
684
685 (*currentPos++) = x4;
686 (*currentPos++) = y4;
687 (*currentPos++) = z4;
688 (*currentPos++) = u4;
689 (*currentPos++) = v4;
690
691 mCurrentQuadIndex ++;
692
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800693 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700694 issueDrawCommand();
695 mCurrentQuadIndex = 0;
696 }
697}
698
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700699uint32_t FontState::getRemainingCacheCapacity() {
700 uint32_t remainingCapacity = 0;
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700701 uint32_t totalPixels = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800702 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700703 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
704 totalPixels += mCacheLines[i]->mMaxWidth;
705 }
706 remainingCapacity = (remainingCapacity * 100) / totalPixels;
707 return remainingCapacity;
708}
709
710void FontState::precacheLatin(Font *font) {
711 // Remaining capacity is measured in %
712 uint32_t remainingCapacity = getRemainingCacheCapacity();
713 uint32_t precacheIdx = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800714 while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700715 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
716 remainingCapacity = getRemainingCacheCapacity();
717 precacheIdx ++;
718 }
719}
720
721
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700722void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
723 uint32_t startIndex, int32_t numGlyphs,
724 Font::RenderMode mode,
725 Font::Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800726 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700727 checkInit();
728
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700729 // Render code here
730 Font *currentFont = mRSC->getFont();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800731 if (!currentFont) {
732 if (!mDefault.get()) {
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -0800733 String8 fontsDir("/fonts/DroidSans.ttf");
734 String8 fullPath(getenv("ANDROID_ROOT"));
735 fullPath += fontsDir;
736
Alex Sakhartchouk7b3e9bd2011-03-16 19:28:25 -0700737 mDefault.set(Font::create(mRSC, fullPath.string(), 8, mRSC->getDPI()));
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700738 }
739 currentFont = mDefault.get();
740 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800741 if (!currentFont) {
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700742 LOGE("Unable to initialize any fonts");
743 return;
744 }
745
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700746 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
747 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700748
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800749 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700750 issueDrawCommand();
751 mCurrentQuadIndex = 0;
752 }
753}
754
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700755void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
756 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800757 bounds->bottom = - bounds->bottom;
758 bounds->top = - bounds->top;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700759}
760
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700761void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700762 mConstants.mFontColor[0] = r;
763 mConstants.mFontColor[1] = g;
764 mConstants.mFontColor[2] = b;
765 mConstants.mFontColor[3] = a;
766
767 mConstants.mGamma = 1.0f;
Alex Sakhartchoukc8fb69e2010-10-05 13:23:55 -0700768 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700769 if (luminance <= mBlackThreshold) {
770 mConstants.mGamma = mBlackGamma;
771 } else if (luminance >= mWhiteThreshold) {
772 mConstants.mGamma = mWhiteGamma;
773 }
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700774
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700775 mConstantsDirty = true;
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700776}
777
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700778void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700779 *r = mConstants.mFontColor[0];
780 *g = mConstants.mFontColor[1];
781 *b = mConstants.mFontColor[2];
782 *a = mConstants.mFontColor[3];
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700783}
784
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800785void FontState::deinit(Context *rsc) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700786 mInitialized = false;
787
Stephen Hines01b7d292010-09-28 15:45:45 -0700788 mFontShaderFConstant.clear();
789
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700790 mIndexBuffer.clear();
791 mVertexArray.clear();
792
793 mFontShaderF.clear();
794 mFontSampler.clear();
795 mFontProgramStore.clear();
796
797 mTextTexture.clear();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800798 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700799 delete mCacheLines[i];
800 }
801 mCacheLines.clear();
802
803 mDefault.clear();
804
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800805 if (mLibrary) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700806 FT_Done_FreeType( mLibrary );
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700807 mLibrary = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700808 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700809}
810
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800811bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
812 if ((uint32_t)bitmap->rows > mMaxHeight) {
813 return false;
814 }
815
816 if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
817 *retOriginX = mCurrentCol;
818 *retOriginY = mCurrentRow;
819 mCurrentCol += bitmap->width;
820 mDirty = true;
821 return true;
822 }
823
824 return false;
825}
826
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700827namespace android {
828namespace renderscript {
829
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -0800830RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, float fontSize, uint32_t dpi) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700831 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800832 if (newFont) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700833 newFont->incUserRef();
834 }
835 return newFont;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700836}
837
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800838RsFont rsi_FontCreateFromMemory(Context *rsc, char const *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
839 Font *newFont = Font::create(rsc, name, fontSize, dpi, data, dataLen);
840 if (newFont) {
841 newFont->incUserRef();
842 }
843 return newFont;
844}
845
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700846} // renderscript
847} // android