blob: 8a5ab99e8baddc3b1db1c39c7f39b0f5f1a53c2a [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 Sakhartchouk9b949fc2010-06-24 17:15:34 -070023#include FT_BITMAP_H
24
25#include <GLES/gl.h>
26#include <GLES/glext.h>
27#include <GLES2/gl2.h>
28#include <GLES2/gl2ext.h>
29
30using namespace android;
31using namespace android::renderscript;
32
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080033Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070034 mInitialized = false;
35 mHasKerning = false;
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -070036 mFace = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070037}
38
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -080039bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080040 if (mInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070041 LOGE("Reinitialization of fonts not supported");
42 return false;
43 }
44
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -080045 FT_Error error = 0;
46 if (data != NULL && dataLen > 0) {
47 error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
48 } else {
49 error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
50 }
51
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080052 if (error) {
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080053 LOGE("Unable to initialize font %s", name);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070054 return false;
55 }
56
57 mFontName = name;
58 mFontSize = fontSize;
59 mDpi = dpi;
60
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080061 error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080062 if (error) {
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080063 LOGE("Unable to set font size on %s", name);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070064 return false;
65 }
66
67 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070068
69 mInitialized = true;
70 return true;
71}
72
Jason Sams38f8d9d2011-01-27 00:14:13 -080073void Font::preDestroy() const {
74 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
75 if (mRSC->mStateFont.mActiveFonts[ct] == this) {
76 mRSC->mStateFont.mActiveFonts.removeAt(ct);
77 break;
78 }
79 }
80}
81
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080082void Font::invalidateTextureCache() {
83 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070084 mCachedGlyphs.valueAt(i)->mIsValid = false;
85 }
86}
87
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080088void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070089 FontState *state = &mRSC->mStateFont;
90
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070091 int32_t nPenX = x + glyph->mBitmapLeft;
92 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070093
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070094 float u1 = glyph->mBitmapMinU;
95 float u2 = glyph->mBitmapMaxU;
96 float v1 = glyph->mBitmapMinV;
97 float v2 = glyph->mBitmapMaxV;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070098
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070099 int32_t width = (int32_t) glyph->mBitmapWidth;
100 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700101
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700102 state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
103 nPenX + width, nPenY, 0, u2, v2,
104 nPenX + width, nPenY - height, 0, u2, v1,
105 nPenX, nPenY - height, 0, u1, v1);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700106}
107
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700108void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
109 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
110 int32_t nPenX = x + glyph->mBitmapLeft;
111 int32_t nPenY = y + glyph->mBitmapTop;
112
113 uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
114 uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
115
116 FontState *state = &mRSC->mStateFont;
117 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
118 const uint8_t* cacheBuffer = state->getTextTextureData();
119
120 uint32_t cacheX = 0, cacheY = 0;
121 int32_t bX = 0, bY = 0;
122 for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
123 for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
124 if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
125 LOGE("Skipping invalid index");
126 continue;
127 }
128 uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
129 bitmap[bY * bitmapW + bX] = tempCol;
130 }
131 }
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700132}
133
134void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
135 int32_t nPenX = x + glyph->mBitmapLeft;
136 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
137
138 int32_t width = (int32_t) glyph->mBitmapWidth;
139 int32_t height = (int32_t) glyph->mBitmapHeight;
140
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800141 // 0, 0 is top left, so bottom is a positive number
142 if (bounds->bottom < nPenY) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700143 bounds->bottom = nPenY;
144 }
145 if (bounds->left > nPenX) {
146 bounds->left = nPenX;
147 }
148 if (bounds->right < nPenX + width) {
149 bounds->right = nPenX + width;
150 }
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800151 if (bounds->top > nPenY - height) {
152 bounds->top = nPenY - height;
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700153 }
154}
155
156void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
157 uint32_t start, int32_t numGlyphs,
158 RenderMode mode, Rect *bounds,
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800159 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
160 if (!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700161 return;
162 }
163
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800164 if (mode == Font::MEASURE) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700165 if (bounds == NULL) {
166 LOGE("No return rectangle provided to measure text");
167 return;
168 }
169 // Reset min and max of the bounding box to something large
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800170 bounds->set(1e6, -1e6, 1e6, -1e6);
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700171 }
172
173 int32_t penX = x, penY = y;
174 int32_t glyphsLeft = 1;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800175 if (numGlyphs > 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700176 glyphsLeft = numGlyphs;
177 }
178
179 size_t index = start;
180 size_t nextIndex = 0;
181
182 while (glyphsLeft > 0) {
183
Kenny Root300ba682010-11-09 14:37:23 -0800184 int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700185
186 // Reached the end of the string or encountered
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800187 if (utfChar < 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700188 break;
189 }
190
191 // Move to the next character in the array
192 index = nextIndex;
193
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700194 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700195
196 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800197 if (cachedGlyph->mIsValid) {
198 switch (mode) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700199 case FRAMEBUFFER:
200 drawCachedGlyph(cachedGlyph, penX, penY);
201 break;
202 case BITMAP:
203 drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
204 break;
205 case MEASURE:
206 measureCachedGlyph(cachedGlyph, penX, penY, bounds);
207 break;
208 }
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700209 }
210
211 penX += (cachedGlyph->mAdvance.x >> 6);
212
213 // If we were given a specific number of glyphs, decrement
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800214 if (numGlyphs > 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700215 glyphsLeft --;
216 }
217 }
218}
219
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700220Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
221
222 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800223 if (cachedGlyph == NULL) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700224 cachedGlyph = cacheGlyph((uint32_t)utfChar);
225 }
226 // Is the glyph still in texture cache?
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800227 if (!cachedGlyph->mIsValid) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700228 updateGlyphCache(cachedGlyph);
229 }
230
231 return cachedGlyph;
232}
233
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800234void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700235 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800236 if (error) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700237 LOGE("Couldn't load glyph.");
238 return;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700239 }
240
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700241 glyph->mAdvance = mFace->glyph->advance;
242 glyph->mBitmapLeft = mFace->glyph->bitmap_left;
243 glyph->mBitmapTop = mFace->glyph->bitmap_top;
244
245 FT_Bitmap *bitmap = &mFace->glyph->bitmap;
246
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700247 // Now copy the bitmap into the cache texture
248 uint32_t startX = 0;
249 uint32_t startY = 0;
250
251 // Let the font state figure out where to put the bitmap
252 FontState *state = &mRSC->mStateFont;
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700253 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700254
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800255 if (!glyph->mIsValid) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700256 return;
257 }
258
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700259 uint32_t endX = startX + bitmap->width;
260 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700261
262 glyph->mBitmapMinX = startX;
263 glyph->mBitmapMinY = startY;
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700264 glyph->mBitmapWidth = bitmap->width;
265 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700266
267 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
268 uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
269
270 glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
271 glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
272 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
273 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
274}
275
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800276Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700277 CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
278 mCachedGlyphs.add(glyph, newGlyph);
279
280 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
281 newGlyph->mIsValid = false;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700282
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700283 updateGlyphCache(newGlyph);
284
285 return newGlyph;
286}
287
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800288Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
289 const void *data, uint32_t dataLen) {
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700290 rsc->mStateFont.checkInit();
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700291 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
292
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800293 for (uint32_t i = 0; i < activeFonts.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700294 Font *ithFont = activeFonts[i];
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800295 if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700296 return ithFont;
297 }
298 }
299
300 Font *newFont = new Font(rsc);
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800301 bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800302 if (isInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700303 activeFonts.push(newFont);
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700304 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700305 return newFont;
306 }
307
Jason Samsb38d5342010-10-21 14:06:55 -0700308 ObjectBase::checkDelete(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700309 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700310}
311
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800312Font::~Font() {
313 if (mFace) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700314 FT_Done_Face(mFace);
315 }
316
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800317 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700318 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700319 delete glyph;
320 }
321}
322
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800323FontState::FontState() {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700324 mInitialized = false;
325 mMaxNumberOfQuads = 1024;
326 mCurrentQuadIndex = 0;
327 mRSC = NULL;
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700328 mLibrary = NULL;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700329
330 // Get the renderer properties
331 char property[PROPERTY_VALUE_MAX];
332
333 // Get the gamma
334 float gamma = DEFAULT_TEXT_GAMMA;
335 if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700336 gamma = atof(property);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700337 }
338
339 // Get the black gamma threshold
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700340 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700341 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700342 blackThreshold = atoi(property);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700343 }
344 mBlackThreshold = (float)(blackThreshold) / 255.0f;
345
346 // Get the white gamma threshold
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700347 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700348 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700349 whiteThreshold = atoi(property);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700350 }
351 mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
352
353 // Compute the gamma tables
354 mBlackGamma = gamma;
355 mWhiteGamma = 1.0f / gamma;
Alex Sakhartchouk960ae152010-10-12 14:15:17 -0700356
357 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700358}
359
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800360FontState::~FontState() {
361 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700362 delete mCacheLines[i];
363 }
364
365 rsAssert(!mActiveFonts.size());
366}
367
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800368FT_Library FontState::getLib() {
369 if (!mLibrary) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700370 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800371 if (error) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700372 LOGE("Unable to initialize freetype");
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700373 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700374 }
375 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700376
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700377 return mLibrary;
378}
379
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800380void FontState::init(Context *rsc) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700381 mRSC = rsc;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700382}
383
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800384void FontState::flushAllAndInvalidate() {
385 if (mCurrentQuadIndex != 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700386 issueDrawCommand();
387 mCurrentQuadIndex = 0;
388 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800389 for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700390 mActiveFonts[i]->invalidateTextureCache();
391 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800392 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700393 mCacheLines[i]->mCurrentCol = 0;
394 }
395}
396
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800397bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700398 // If the glyph is too tall, don't cache it
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800399 if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700400 LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
401 return false;
402 }
403
404 // Now copy the bitmap into the cache texture
405 uint32_t startX = 0;
406 uint32_t startY = 0;
407
408 bool bitmapFit = false;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800409 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700410 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800411 if (bitmapFit) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700412 break;
413 }
414 }
415
416 // If the new glyph didn't fit, flush the state so far and invalidate everything
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800417 if (!bitmapFit) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700418 flushAllAndInvalidate();
419
420 // Try to fit it again
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800421 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700422 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800423 if (bitmapFit) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700424 break;
425 }
426 }
427
428 // if we still don't fit, something is wrong and we shouldn't draw
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800429 if (!bitmapFit) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700430 LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
431 return false;
432 }
433 }
434
435 *retOriginX = startX;
436 *retOriginY = startY;
437
438 uint32_t endX = startX + bitmap->width;
439 uint32_t endY = startY + bitmap->rows;
440
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700441 uint32_t cacheWidth = getCacheTextureType()->getDimX();
442
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700443 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
444 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700445
446 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800447 for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
448 for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700449 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700450 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
451 }
452 }
453
454 // This will dirty the texture and the shader so next time
455 // we draw it will upload the data
Jason Sams6d8eb262010-12-15 01:41:00 -0800456 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700457 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700458
459 // Some debug code
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800460 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700461 LOGE("Cache Line: H: %u Empty Space: %f",
462 mCacheLines[i]->mMaxHeight,
463 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
464
465 }*/
466
467 return true;
468}
469
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800470void FontState::initRenderState() {
Alex Sakhartchoukd2091632010-10-06 11:15:01 -0700471 String8 shaderString("varying vec2 varTex0;\n");
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700472 shaderString.append("void main() {\n");
473 shaderString.append(" lowp vec4 col = UNI_Color;\n");
474 shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700475 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700476 shaderString.append(" gl_FragColor = col;\n");
477 shaderString.append("}\n");
478
479 const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700480 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700481 mRSC->mStateElement.elementBuilderBegin();
482 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700483 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700484 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
485
Jason Sams31a7e422010-10-26 13:09:17 -0700486 Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700487
488 uint32_t tmp[4];
489 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
490 tmp[1] = (uint32_t)inputType;
Alex Sakhartchouk67f2e442010-11-18 15:22:43 -0800491 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
492 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700493
Jason Sams5476b452010-12-08 16:14:36 -0800494 mFontShaderFConstant.set(new Allocation(mRSC, inputType,
495 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700496 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
497 shaderString.length(), tmp, 4);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700498 mFontShaderF.set(pf);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700499 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700500
501 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
502 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
503 mFontSampler.set(sampler);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700504 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700505
506 ProgramStore *fontStore = new ProgramStore(mRSC);
507 mFontProgramStore.set(fontStore);
508 mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
509 mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
510 mFontProgramStore->setDitherEnable(false);
511 mFontProgramStore->setDepthMask(false);
512}
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
565 indexAlloc->deferedUploadToBufferObject(mRSC);
566 mIndexBuffer.set(indexAlloc);
567
568 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
569 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
570
Alex Sakhartchouk98bfe5d2010-10-18 17:18:50 -0700571 mRSC->mStateElement.elementBuilderBegin();
572 mRSC->mStateElement.elementBuilderAdd(posElem, "position", 1);
573 mRSC->mStateElement.elementBuilderAdd(texElem, "texture0", 1);
574 const Element *vertexDataElem = mRSC->mStateElement.elementBuilderCreate(mRSC);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700575
Jason Sams31a7e422010-10-26 13:09:17 -0700576 Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
577 mMaxNumberOfQuads * 4,
578 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700579
Jason Sams5476b452010-12-08 16:14:36 -0800580 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700581 mTextMeshPtr = (float*)vertexAlloc->getPtr();
582
583 mVertexArray.set(vertexAlloc);
584}
585
586// We don't want to allocate anything unless we actually draw text
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800587void FontState::checkInit() {
588 if (mInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700589 return;
590 }
591
592 initTextTexture();
593 initRenderState();
594
595 initVertexArrayBuffers();
596
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700597 // We store a string with letters in a rough frequency of occurrence
598 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
599 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
600 mLatinPrecache += String8(",.?!()-+@;:`'");
601 mLatinPrecache += String8("0123456789");
602
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700603 mInitialized = true;
604}
605
606void FontState::issueDrawCommand() {
Jason Samsa17af042010-11-17 15:29:32 -0800607 Context::PushState ps(mRSC);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700608
Jason Samsa17af042010-11-17 15:29:32 -0800609 mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
610 mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
611 mRSC->setProgramFragment(mFontShaderF.get());
612 mRSC->setProgramStore(mFontProgramStore.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700613
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800614 if (mConstantsDirty) {
Jason Sams49a05d72010-12-29 14:31:29 -0800615 mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700616 mConstantsDirty = false;
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700617 }
618
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700619 if (!mRSC->setupCheck()) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700620 return;
621 }
622
623 float *vtx = (float*)mVertexArray->getPtr();
624 float *tex = vtx + 3;
625
Alex Sakhartchouk9d71e212010-11-08 15:10:52 -0800626 VertexArray::Attrib attribs[2];
627 attribs[0].set(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
628 attribs[1].set(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
629 VertexArray va(attribs, 2);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700630 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
631
632 mIndexBuffer->uploadCheck(mRSC);
633 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
634 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700635}
636
637void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800638 float u1, float v1,
639 float x2, float y2, float z2,
640 float u2, float v2,
641 float x3, float y3, float z3,
642 float u3, float v3,
643 float x4, float y4, float z4,
644 float u4, float v4) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700645 const uint32_t vertsPerQuad = 4;
646 const uint32_t floatsPerVert = 5;
647 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
648
649 // Cull things that are off the screen
650 float width = (float)mRSC->getWidth();
651 float height = (float)mRSC->getHeight();
652
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800653 if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700654 return;
655 }
656
657 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
658 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
659 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
660 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
661
662 (*currentPos++) = x1;
663 (*currentPos++) = y1;
664 (*currentPos++) = z1;
665 (*currentPos++) = u1;
666 (*currentPos++) = v1;
667
668 (*currentPos++) = x2;
669 (*currentPos++) = y2;
670 (*currentPos++) = z2;
671 (*currentPos++) = u2;
672 (*currentPos++) = v2;
673
674 (*currentPos++) = x3;
675 (*currentPos++) = y3;
676 (*currentPos++) = z3;
677 (*currentPos++) = u3;
678 (*currentPos++) = v3;
679
680 (*currentPos++) = x4;
681 (*currentPos++) = y4;
682 (*currentPos++) = z4;
683 (*currentPos++) = u4;
684 (*currentPos++) = v4;
685
686 mCurrentQuadIndex ++;
687
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800688 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700689 issueDrawCommand();
690 mCurrentQuadIndex = 0;
691 }
692}
693
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700694uint32_t FontState::getRemainingCacheCapacity() {
695 uint32_t remainingCapacity = 0;
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700696 uint32_t totalPixels = 0;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800697 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700698 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
699 totalPixels += mCacheLines[i]->mMaxWidth;
700 }
701 remainingCapacity = (remainingCapacity * 100) / totalPixels;
702 return remainingCapacity;
703}
704
705void FontState::precacheLatin(Font *font) {
706 // Remaining capacity is measured in %
707 uint32_t remainingCapacity = getRemainingCacheCapacity();
708 uint32_t precacheIdx = 0;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800709 while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700710 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
711 remainingCapacity = getRemainingCacheCapacity();
712 precacheIdx ++;
713 }
714}
715
716
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700717void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
718 uint32_t startIndex, int32_t numGlyphs,
719 Font::RenderMode mode,
720 Font::Rect *bounds,
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800721 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700722 checkInit();
723
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700724 // Render code here
725 Font *currentFont = mRSC->getFont();
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800726 if (!currentFont) {
727 if (!mDefault.get()) {
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -0800728 String8 fontsDir("/fonts/DroidSans.ttf");
729 String8 fullPath(getenv("ANDROID_ROOT"));
730 fullPath += fontsDir;
731
732 mDefault.set(Font::create(mRSC, fullPath.string(), 16, 96));
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700733 }
734 currentFont = mDefault.get();
735 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800736 if (!currentFont) {
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700737 LOGE("Unable to initialize any fonts");
738 return;
739 }
740
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700741 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
742 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700743
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800744 if (mCurrentQuadIndex != 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700745 issueDrawCommand();
746 mCurrentQuadIndex = 0;
747 }
748}
749
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700750void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
751 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800752 bounds->bottom = - bounds->bottom;
753 bounds->top = - bounds->top;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700754}
755
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700756void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700757 mConstants.mFontColor[0] = r;
758 mConstants.mFontColor[1] = g;
759 mConstants.mFontColor[2] = b;
760 mConstants.mFontColor[3] = a;
761
762 mConstants.mGamma = 1.0f;
Alex Sakhartchouk76322af2010-10-05 13:23:55 -0700763 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700764 if (luminance <= mBlackThreshold) {
765 mConstants.mGamma = mBlackGamma;
766 } else if (luminance >= mWhiteThreshold) {
767 mConstants.mGamma = mWhiteGamma;
768 }
Alex Sakhartchouk960ae152010-10-12 14:15:17 -0700769
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700770 mConstantsDirty = true;
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700771}
772
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700773void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700774 *r = mConstants.mFontColor[0];
775 *g = mConstants.mFontColor[1];
776 *b = mConstants.mFontColor[2];
777 *a = mConstants.mFontColor[3];
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700778}
779
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800780void FontState::deinit(Context *rsc) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700781 mInitialized = false;
782
Stephen Hines01f0ad72010-09-28 15:45:45 -0700783 mFontShaderFConstant.clear();
784
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700785 mIndexBuffer.clear();
786 mVertexArray.clear();
787
788 mFontShaderF.clear();
789 mFontSampler.clear();
790 mFontProgramStore.clear();
791
792 mTextTexture.clear();
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800793 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700794 delete mCacheLines[i];
795 }
796 mCacheLines.clear();
797
798 mDefault.clear();
799
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800800 if (mLibrary) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700801 FT_Done_FreeType( mLibrary );
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700802 mLibrary = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700803 }
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700804}
805
806namespace android {
807namespace renderscript {
808
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -0800809RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, float fontSize, uint32_t dpi) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700810 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800811 if (newFont) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700812 newFont->incUserRef();
813 }
814 return newFont;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700815}
816
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800817RsFont rsi_FontCreateFromMemory(Context *rsc, char const *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
818 Font *newFont = Font::create(rsc, name, fontSize, dpi, data, dataLen);
819 if (newFont) {
820 newFont->incUserRef();
821 }
822 return newFont;
823}
824
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700825} // renderscript
826} // android