blob: 5e47ddb175364c930365b93a7e9dbb6c073b4324 [file] [log] [blame]
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -070018#include "rsContext.h"
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070019
20#include "rsFont.h"
21#include "rsProgramFragment.h"
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -070022#include <cutils/properties.h>
Alex Sakhartchoukebd65bb2011-02-25 09:34:33 -080023
24#include <ft2build.h>
25#include FT_FREETYPE_H
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070026#include FT_BITMAP_H
27
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070028using namespace android;
29using namespace android::renderscript;
30
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080031Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070032 mInitialized = false;
33 mHasKerning = false;
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -070034 mFace = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070035}
36
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -080037bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080038 if (mInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070039 LOGE("Reinitialization of fonts not supported");
40 return false;
41 }
42
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -080043 FT_Error error = 0;
44 if (data != NULL && dataLen > 0) {
45 error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
46 } else {
47 error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
48 }
49
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080050 if (error) {
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080051 LOGE("Unable to initialize font %s", name);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070052 return false;
53 }
54
55 mFontName = name;
56 mFontSize = fontSize;
57 mDpi = dpi;
58
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080059 error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080060 if (error) {
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080061 LOGE("Unable to set font size on %s", name);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070062 return false;
63 }
64
65 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070066
67 mInitialized = true;
68 return true;
69}
70
Jason Sams38f8d9d2011-01-27 00:14:13 -080071void Font::preDestroy() const {
72 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
73 if (mRSC->mStateFont.mActiveFonts[ct] == this) {
74 mRSC->mStateFont.mActiveFonts.removeAt(ct);
75 break;
76 }
77 }
78}
79
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080080void Font::invalidateTextureCache() {
81 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070082 mCachedGlyphs.valueAt(i)->mIsValid = false;
83 }
84}
85
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080086void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070087 FontState *state = &mRSC->mStateFont;
88
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070089 int32_t nPenX = x + glyph->mBitmapLeft;
90 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070091
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070092 float u1 = glyph->mBitmapMinU;
93 float u2 = glyph->mBitmapMaxU;
94 float v1 = glyph->mBitmapMinV;
95 float v2 = glyph->mBitmapMaxV;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070096
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070097 int32_t width = (int32_t) glyph->mBitmapWidth;
98 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070099
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700100 state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
101 nPenX + width, nPenY, 0, u2, v2,
102 nPenX + width, nPenY - height, 0, u2, v1,
103 nPenX, nPenY - height, 0, u1, v1);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700104}
105
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700106void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
107 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
108 int32_t nPenX = x + glyph->mBitmapLeft;
109 int32_t nPenY = y + glyph->mBitmapTop;
110
111 uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
112 uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
113
114 FontState *state = &mRSC->mStateFont;
115 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
116 const uint8_t* cacheBuffer = state->getTextTextureData();
117
118 uint32_t cacheX = 0, cacheY = 0;
119 int32_t bX = 0, bY = 0;
120 for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
121 for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
122 if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
123 LOGE("Skipping invalid index");
124 continue;
125 }
126 uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
127 bitmap[bY * bitmapW + bX] = tempCol;
128 }
129 }
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700130}
131
132void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
133 int32_t nPenX = x + glyph->mBitmapLeft;
134 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
135
136 int32_t width = (int32_t) glyph->mBitmapWidth;
137 int32_t height = (int32_t) glyph->mBitmapHeight;
138
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800139 // 0, 0 is top left, so bottom is a positive number
140 if (bounds->bottom < nPenY) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700141 bounds->bottom = nPenY;
142 }
143 if (bounds->left > nPenX) {
144 bounds->left = nPenX;
145 }
146 if (bounds->right < nPenX + width) {
147 bounds->right = nPenX + width;
148 }
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800149 if (bounds->top > nPenY - height) {
150 bounds->top = nPenY - height;
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700151 }
152}
153
154void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
155 uint32_t start, int32_t numGlyphs,
156 RenderMode mode, Rect *bounds,
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800157 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
158 if (!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700159 return;
160 }
161
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800162 if (mode == Font::MEASURE) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700163 if (bounds == NULL) {
164 LOGE("No return rectangle provided to measure text");
165 return;
166 }
167 // Reset min and max of the bounding box to something large
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800168 bounds->set(1e6, -1e6, 1e6, -1e6);
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700169 }
170
171 int32_t penX = x, penY = y;
172 int32_t glyphsLeft = 1;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800173 if (numGlyphs > 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700174 glyphsLeft = numGlyphs;
175 }
176
177 size_t index = start;
178 size_t nextIndex = 0;
179
180 while (glyphsLeft > 0) {
181
Kenny Root300ba682010-11-09 14:37:23 -0800182 int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700183
184 // Reached the end of the string or encountered
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800185 if (utfChar < 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700186 break;
187 }
188
189 // Move to the next character in the array
190 index = nextIndex;
191
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700192 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700193
194 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800195 if (cachedGlyph->mIsValid) {
196 switch (mode) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700197 case FRAMEBUFFER:
198 drawCachedGlyph(cachedGlyph, penX, penY);
199 break;
200 case BITMAP:
201 drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
202 break;
203 case MEASURE:
204 measureCachedGlyph(cachedGlyph, penX, penY, bounds);
205 break;
206 }
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700207 }
208
Alex Sakhartchoukebd65bb2011-02-25 09:34:33 -0800209 penX += (cachedGlyph->mAdvanceX >> 6);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700210
211 // If we were given a specific number of glyphs, decrement
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800212 if (numGlyphs > 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700213 glyphsLeft --;
214 }
215 }
216}
217
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700218Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
219
220 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800221 if (cachedGlyph == NULL) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700222 cachedGlyph = cacheGlyph((uint32_t)utfChar);
223 }
224 // Is the glyph still in texture cache?
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800225 if (!cachedGlyph->mIsValid) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700226 updateGlyphCache(cachedGlyph);
227 }
228
229 return cachedGlyph;
230}
231
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800232void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700233 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800234 if (error) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700235 LOGE("Couldn't load glyph.");
236 return;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700237 }
238
Alex Sakhartchoukebd65bb2011-02-25 09:34:33 -0800239 glyph->mAdvanceX = mFace->glyph->advance.x;
240 glyph->mAdvanceY = mFace->glyph->advance.y;
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700241 glyph->mBitmapLeft = mFace->glyph->bitmap_left;
242 glyph->mBitmapTop = mFace->glyph->bitmap_top;
243
244 FT_Bitmap *bitmap = &mFace->glyph->bitmap;
245
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700246 // Now copy the bitmap into the cache texture
247 uint32_t startX = 0;
248 uint32_t startY = 0;
249
250 // Let the font state figure out where to put the bitmap
251 FontState *state = &mRSC->mStateFont;
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700252 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700253
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800254 if (!glyph->mIsValid) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700255 return;
256 }
257
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700258 uint32_t endX = startX + bitmap->width;
259 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700260
261 glyph->mBitmapMinX = startX;
262 glyph->mBitmapMinY = startY;
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700263 glyph->mBitmapWidth = bitmap->width;
264 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700265
266 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
267 uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
268
269 glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
270 glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
271 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
272 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
273}
274
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800275Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700276 CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
277 mCachedGlyphs.add(glyph, newGlyph);
278
279 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
280 newGlyph->mIsValid = false;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700281
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700282 updateGlyphCache(newGlyph);
283
284 return newGlyph;
285}
286
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800287Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
288 const void *data, uint32_t dataLen) {
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700289 rsc->mStateFont.checkInit();
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700290 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
291
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800292 for (uint32_t i = 0; i < activeFonts.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700293 Font *ithFont = activeFonts[i];
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800294 if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700295 return ithFont;
296 }
297 }
298
299 Font *newFont = new Font(rsc);
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800300 bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800301 if (isInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700302 activeFonts.push(newFont);
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700303 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700304 return newFont;
305 }
306
Jason Samsb38d5342010-10-21 14:06:55 -0700307 ObjectBase::checkDelete(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700308 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700309}
310
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800311Font::~Font() {
312 if (mFace) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700313 FT_Done_Face(mFace);
314 }
315
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800316 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700317 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700318 delete glyph;
319 }
320}
321
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800322FontState::FontState() {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700323 mInitialized = false;
324 mMaxNumberOfQuads = 1024;
325 mCurrentQuadIndex = 0;
326 mRSC = NULL;
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700327 mLibrary = NULL;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700328
329 // Get the renderer properties
330 char property[PROPERTY_VALUE_MAX];
331
332 // Get the gamma
333 float gamma = DEFAULT_TEXT_GAMMA;
334 if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700335 gamma = atof(property);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700336 }
337
338 // Get the black gamma threshold
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700339 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700340 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700341 blackThreshold = atoi(property);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700342 }
343 mBlackThreshold = (float)(blackThreshold) / 255.0f;
344
345 // Get the white gamma threshold
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700346 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700347 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700348 whiteThreshold = atoi(property);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700349 }
350 mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
351
352 // Compute the gamma tables
353 mBlackGamma = gamma;
354 mWhiteGamma = 1.0f / gamma;
Alex Sakhartchouk960ae152010-10-12 14:15:17 -0700355
356 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700357}
358
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800359FontState::~FontState() {
360 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700361 delete mCacheLines[i];
362 }
363
364 rsAssert(!mActiveFonts.size());
365}
366
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800367FT_Library FontState::getLib() {
368 if (!mLibrary) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700369 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800370 if (error) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700371 LOGE("Unable to initialize freetype");
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700372 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700373 }
374 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700375
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700376 return mLibrary;
377}
378
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800379void FontState::init(Context *rsc) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700380 mRSC = rsc;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700381}
382
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800383void FontState::flushAllAndInvalidate() {
384 if (mCurrentQuadIndex != 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700385 issueDrawCommand();
386 mCurrentQuadIndex = 0;
387 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800388 for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700389 mActiveFonts[i]->invalidateTextureCache();
390 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800391 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700392 mCacheLines[i]->mCurrentCol = 0;
393 }
394}
395
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800396bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700397 // If the glyph is too tall, don't cache it
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800398 if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700399 LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
400 return false;
401 }
402
403 // Now copy the bitmap into the cache texture
404 uint32_t startX = 0;
405 uint32_t startY = 0;
406
407 bool bitmapFit = false;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800408 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700409 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800410 if (bitmapFit) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700411 break;
412 }
413 }
414
415 // If the new glyph didn't fit, flush the state so far and invalidate everything
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800416 if (!bitmapFit) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700417 flushAllAndInvalidate();
418
419 // Try to fit it again
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800420 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700421 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800422 if (bitmapFit) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700423 break;
424 }
425 }
426
427 // if we still don't fit, something is wrong and we shouldn't draw
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800428 if (!bitmapFit) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700429 LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
430 return false;
431 }
432 }
433
434 *retOriginX = startX;
435 *retOriginY = startY;
436
437 uint32_t endX = startX + bitmap->width;
438 uint32_t endY = startY + bitmap->rows;
439
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700440 uint32_t cacheWidth = getCacheTextureType()->getDimX();
441
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700442 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
443 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700444
445 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800446 for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
447 for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700448 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700449 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
450 }
451 }
452
453 // This will dirty the texture and the shader so next time
454 // we draw it will upload the data
Alex Sakhartchouk4a36b452011-04-29 16:49:08 -0700455 mTextTexture->deferredUploadToTexture(mRSC);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700456 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700457
458 // Some debug code
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800459 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700460 LOGE("Cache Line: H: %u Empty Space: %f",
461 mCacheLines[i]->mMaxHeight,
462 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
463
464 }*/
465
466 return true;
467}
468
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800469void FontState::initRenderState() {
Alex Sakhartchoukd2091632010-10-06 11:15:01 -0700470 String8 shaderString("varying vec2 varTex0;\n");
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700471 shaderString.append("void main() {\n");
472 shaderString.append(" lowp vec4 col = UNI_Color;\n");
473 shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700474 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700475 shaderString.append(" gl_FragColor = col;\n");
476 shaderString.append("}\n");
477
478 const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700479 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700480 mRSC->mStateElement.elementBuilderBegin();
481 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700482 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700483 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
484
Jason Sams31a7e422010-10-26 13:09:17 -0700485 Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700486
487 uint32_t tmp[4];
488 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
489 tmp[1] = (uint32_t)inputType;
Alex Sakhartchouk67f2e442010-11-18 15:22:43 -0800490 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
491 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700492
Jason Sams5476b452010-12-08 16:14:36 -0800493 mFontShaderFConstant.set(new Allocation(mRSC, inputType,
494 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700495 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
496 shaderString.length(), tmp, 4);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700497 mFontShaderF.set(pf);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700498 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700499
500 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
501 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
502 mFontSampler.set(sampler);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700503 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700504
Jason Sams331bf9b2011-04-06 11:23:54 -0700505 ProgramStore *fontStore = new ProgramStore(mRSC, true, true, true, true,
506 false, false,
Jason Samsbd184c52011-04-06 11:44:47 -0700507 RS_BLEND_SRC_SRC_ALPHA,
508 RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
Jason Sams331bf9b2011-04-06 11:23:54 -0700509 RS_DEPTH_FUNC_ALWAYS);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700510 mFontProgramStore.set(fontStore);
Jason Sams48f50562011-03-18 15:03:25 -0700511 mFontProgramStore->init();
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700512}
513
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800514void FontState::initTextTexture() {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700515 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
516
517 // We will allocate a texture to initially hold 32 character bitmaps
Jason Sams31a7e422010-10-26 13:09:17 -0700518 Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700519
Jason Sams5476b452010-12-08 16:14:36 -0800520 Allocation *cacheAlloc = new Allocation(mRSC, texType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700521 mTextTexture.set(cacheAlloc);
Jason Sams6d8eb262010-12-15 01:41:00 -0800522 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700523
524 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700525 int32_t nextLine = 0;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700526 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
527 nextLine += mCacheLines.top()->mMaxHeight;
528 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
529 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700530 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
531 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700532 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
533 nextLine += mCacheLines.top()->mMaxHeight;
534 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
535 nextLine += mCacheLines.top()->mMaxHeight;
536 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
537 nextLine += mCacheLines.top()->mMaxHeight;
538 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
539}
540
541// Avoid having to reallocate memory and render quad by quad
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800542void FontState::initVertexArrayBuffers() {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700543 // Now lets write index data
544 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700545 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Jason Sams31a7e422010-10-26 13:09:17 -0700546 Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700547
Jason Sams5476b452010-12-08 16:14:36 -0800548 Allocation *indexAlloc = new Allocation(mRSC, indexType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700549 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
550
551 // Four verts, two triangles , six indices per quad
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800552 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700553 int32_t i6 = i * 6;
554 int32_t i4 = i * 4;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700555
556 indexPtr[i6 + 0] = i4 + 0;
557 indexPtr[i6 + 1] = i4 + 1;
558 indexPtr[i6 + 2] = i4 + 2;
559
560 indexPtr[i6 + 3] = i4 + 0;
561 indexPtr[i6 + 4] = i4 + 2;
562 indexPtr[i6 + 5] = i4 + 3;
563 }
564
Alex Sakhartchouk8e90f2b2011-04-01 14:19:01 -0700565 indexAlloc->deferredUploadToBufferObject(mRSC);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700566
567 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
568 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
569
Alex Sakhartchouk98bfe5d2010-10-18 17:18:50 -0700570 mRSC->mStateElement.elementBuilderBegin();
571 mRSC->mStateElement.elementBuilderAdd(posElem, "position", 1);
572 mRSC->mStateElement.elementBuilderAdd(texElem, "texture0", 1);
573 const Element *vertexDataElem = mRSC->mStateElement.elementBuilderCreate(mRSC);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700574
Jason Sams31a7e422010-10-26 13:09:17 -0700575 Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
576 mMaxNumberOfQuads * 4,
577 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700578
Jason Sams5476b452010-12-08 16:14:36 -0800579 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700580 mTextMeshPtr = (float*)vertexAlloc->getPtr();
581
Alex Sakhartchouk4a36b452011-04-29 16:49:08 -0700582 mMesh.set(new Mesh(mRSC, 1, 1));
583 mMesh->setVertexBuffer(vertexAlloc, 0);
584 mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
585 mMesh->init();
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700586}
587
588// We don't want to allocate anything unless we actually draw text
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800589void FontState::checkInit() {
590 if (mInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700591 return;
592 }
593
594 initTextTexture();
595 initRenderState();
596
597 initVertexArrayBuffers();
598
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700599 // We store a string with letters in a rough frequency of occurrence
600 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
601 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
602 mLatinPrecache += String8(",.?!()-+@;:`'");
603 mLatinPrecache += String8("0123456789");
604
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700605 mInitialized = true;
606}
607
608void FontState::issueDrawCommand() {
Jason Samsa17af042010-11-17 15:29:32 -0800609 Context::PushState ps(mRSC);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700610
Jason Samsa17af042010-11-17 15:29:32 -0800611 mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
612 mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
613 mRSC->setProgramFragment(mFontShaderF.get());
614 mRSC->setProgramStore(mFontProgramStore.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700615
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800616 if (mConstantsDirty) {
Jason Sams49a05d72010-12-29 14:31:29 -0800617 mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700618 mConstantsDirty = false;
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700619 }
620
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700621 if (!mRSC->setupCheck()) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700622 return;
623 }
624
Alex Sakhartchouk4a36b452011-04-29 16:49:08 -0700625 mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700626}
627
628void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800629 float u1, float v1,
630 float x2, float y2, float z2,
631 float u2, float v2,
632 float x3, float y3, float z3,
633 float u3, float v3,
634 float x4, float y4, float z4,
635 float u4, float v4) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700636 const uint32_t vertsPerQuad = 4;
637 const uint32_t floatsPerVert = 5;
638 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
639
640 // Cull things that are off the screen
641 float width = (float)mRSC->getWidth();
642 float height = (float)mRSC->getHeight();
643
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800644 if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700645 return;
646 }
647
648 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
649 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
650 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
651 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
652
653 (*currentPos++) = x1;
654 (*currentPos++) = y1;
655 (*currentPos++) = z1;
656 (*currentPos++) = u1;
657 (*currentPos++) = v1;
658
659 (*currentPos++) = x2;
660 (*currentPos++) = y2;
661 (*currentPos++) = z2;
662 (*currentPos++) = u2;
663 (*currentPos++) = v2;
664
665 (*currentPos++) = x3;
666 (*currentPos++) = y3;
667 (*currentPos++) = z3;
668 (*currentPos++) = u3;
669 (*currentPos++) = v3;
670
671 (*currentPos++) = x4;
672 (*currentPos++) = y4;
673 (*currentPos++) = z4;
674 (*currentPos++) = u4;
675 (*currentPos++) = v4;
676
677 mCurrentQuadIndex ++;
678
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800679 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700680 issueDrawCommand();
681 mCurrentQuadIndex = 0;
682 }
683}
684
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700685uint32_t FontState::getRemainingCacheCapacity() {
686 uint32_t remainingCapacity = 0;
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700687 uint32_t totalPixels = 0;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800688 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700689 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
690 totalPixels += mCacheLines[i]->mMaxWidth;
691 }
692 remainingCapacity = (remainingCapacity * 100) / totalPixels;
693 return remainingCapacity;
694}
695
696void FontState::precacheLatin(Font *font) {
697 // Remaining capacity is measured in %
698 uint32_t remainingCapacity = getRemainingCacheCapacity();
699 uint32_t precacheIdx = 0;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800700 while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700701 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
702 remainingCapacity = getRemainingCacheCapacity();
703 precacheIdx ++;
704 }
705}
706
707
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700708void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
709 uint32_t startIndex, int32_t numGlyphs,
710 Font::RenderMode mode,
711 Font::Rect *bounds,
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800712 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700713 checkInit();
714
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700715 // Render code here
716 Font *currentFont = mRSC->getFont();
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800717 if (!currentFont) {
718 if (!mDefault.get()) {
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -0800719 String8 fontsDir("/fonts/DroidSans.ttf");
720 String8 fullPath(getenv("ANDROID_ROOT"));
721 fullPath += fontsDir;
722
Alex Sakhartchouk2c74ad92011-03-16 19:28:25 -0700723 mDefault.set(Font::create(mRSC, fullPath.string(), 8, mRSC->getDPI()));
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700724 }
725 currentFont = mDefault.get();
726 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800727 if (!currentFont) {
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700728 LOGE("Unable to initialize any fonts");
729 return;
730 }
731
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700732 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
733 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700734
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800735 if (mCurrentQuadIndex != 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700736 issueDrawCommand();
737 mCurrentQuadIndex = 0;
738 }
739}
740
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700741void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
742 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800743 bounds->bottom = - bounds->bottom;
744 bounds->top = - bounds->top;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700745}
746
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700747void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700748 mConstants.mFontColor[0] = r;
749 mConstants.mFontColor[1] = g;
750 mConstants.mFontColor[2] = b;
751 mConstants.mFontColor[3] = a;
752
753 mConstants.mGamma = 1.0f;
Alex Sakhartchouk76322af2010-10-05 13:23:55 -0700754 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700755 if (luminance <= mBlackThreshold) {
756 mConstants.mGamma = mBlackGamma;
757 } else if (luminance >= mWhiteThreshold) {
758 mConstants.mGamma = mWhiteGamma;
759 }
Alex Sakhartchouk960ae152010-10-12 14:15:17 -0700760
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700761 mConstantsDirty = true;
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700762}
763
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700764void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700765 *r = mConstants.mFontColor[0];
766 *g = mConstants.mFontColor[1];
767 *b = mConstants.mFontColor[2];
768 *a = mConstants.mFontColor[3];
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700769}
770
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800771void FontState::deinit(Context *rsc) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700772 mInitialized = false;
773
Stephen Hines01f0ad72010-09-28 15:45:45 -0700774 mFontShaderFConstant.clear();
775
Alex Sakhartchouk4a36b452011-04-29 16:49:08 -0700776 mMesh.clear();
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700777
778 mFontShaderF.clear();
779 mFontSampler.clear();
780 mFontProgramStore.clear();
781
782 mTextTexture.clear();
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800783 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700784 delete mCacheLines[i];
785 }
786 mCacheLines.clear();
787
788 mDefault.clear();
789
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800790 if (mLibrary) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700791 FT_Done_FreeType( mLibrary );
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700792 mLibrary = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700793 }
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700794}
795
Alex Sakhartchoukebd65bb2011-02-25 09:34:33 -0800796bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
797 if ((uint32_t)bitmap->rows > mMaxHeight) {
798 return false;
799 }
800
801 if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
802 *retOriginX = mCurrentCol;
803 *retOriginY = mCurrentRow;
804 mCurrentCol += bitmap->width;
805 mDirty = true;
806 return true;
807 }
808
809 return false;
810}
811
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700812namespace android {
813namespace renderscript {
814
Alex Sakhartchouke7c4a752011-04-06 10:57:51 -0700815RsFont rsi_FontCreateFromFile(Context *rsc,
816 char const *name, size_t name_length,
817 float fontSize, uint32_t dpi) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700818 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800819 if (newFont) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700820 newFont->incUserRef();
821 }
822 return newFont;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700823}
824
Alex Sakhartchouke7c4a752011-04-06 10:57:51 -0700825RsFont rsi_FontCreateFromMemory(Context *rsc,
826 char const *name, size_t name_length,
827 float fontSize, uint32_t dpi,
828 const void *data, size_t data_length) {
829 Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800830 if (newFont) {
831 newFont->incUserRef();
832 }
833 return newFont;
834}
835
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700836} // renderscript
837} // android