blob: 7fdfbe05f287f2ec811d2fa814c9a97190913690 [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
18#ifndef ANDROID_RS_BUILD_FOR_HOST
19#include "rsContext.h"
20#else
21#include "rsContextHostStub.h"
22#endif
23
24#include "rsFont.h"
25#include "rsProgramFragment.h"
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -070026#include <cutils/properties.h>
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070027#include FT_BITMAP_H
28
29#include <GLES/gl.h>
30#include <GLES/glext.h>
31#include <GLES2/gl2.h>
32#include <GLES2/gl2ext.h>
33
34using namespace android;
35using namespace android::renderscript;
36
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080037Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070038 mInitialized = false;
39 mHasKerning = false;
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -070040 mFace = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070041}
42
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -080043bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080044 if (mInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070045 LOGE("Reinitialization of fonts not supported");
46 return false;
47 }
48
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -080049 FT_Error error = 0;
50 if (data != NULL && dataLen > 0) {
51 error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
52 } else {
53 error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
54 }
55
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080056 if (error) {
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080057 LOGE("Unable to initialize font %s", name);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070058 return false;
59 }
60
61 mFontName = name;
62 mFontSize = fontSize;
63 mDpi = dpi;
64
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080065 error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080066 if (error) {
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080067 LOGE("Unable to set font size on %s", name);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070068 return false;
69 }
70
71 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070072
73 mInitialized = true;
74 return true;
75}
76
Jason Sams38f8d9d2011-01-27 00:14:13 -080077void Font::preDestroy() const {
78 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
79 if (mRSC->mStateFont.mActiveFonts[ct] == this) {
80 mRSC->mStateFont.mActiveFonts.removeAt(ct);
81 break;
82 }
83 }
84}
85
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080086void Font::invalidateTextureCache() {
87 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070088 mCachedGlyphs.valueAt(i)->mIsValid = false;
89 }
90}
91
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080092void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070093 FontState *state = &mRSC->mStateFont;
94
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070095 int32_t nPenX = x + glyph->mBitmapLeft;
96 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070097
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070098 float u1 = glyph->mBitmapMinU;
99 float u2 = glyph->mBitmapMaxU;
100 float v1 = glyph->mBitmapMinV;
101 float v2 = glyph->mBitmapMaxV;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700102
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700103 int32_t width = (int32_t) glyph->mBitmapWidth;
104 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700105
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700106 state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
107 nPenX + width, nPenY, 0, u2, v2,
108 nPenX + width, nPenY - height, 0, u2, v1,
109 nPenX, nPenY - height, 0, u1, v1);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700110}
111
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700112void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
113 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
114 int32_t nPenX = x + glyph->mBitmapLeft;
115 int32_t nPenY = y + glyph->mBitmapTop;
116
117 uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
118 uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
119
120 FontState *state = &mRSC->mStateFont;
121 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
122 const uint8_t* cacheBuffer = state->getTextTextureData();
123
124 uint32_t cacheX = 0, cacheY = 0;
125 int32_t bX = 0, bY = 0;
126 for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
127 for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
128 if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
129 LOGE("Skipping invalid index");
130 continue;
131 }
132 uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
133 bitmap[bY * bitmapW + bX] = tempCol;
134 }
135 }
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700136}
137
138void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
139 int32_t nPenX = x + glyph->mBitmapLeft;
140 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
141
142 int32_t width = (int32_t) glyph->mBitmapWidth;
143 int32_t height = (int32_t) glyph->mBitmapHeight;
144
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800145 // 0, 0 is top left, so bottom is a positive number
146 if (bounds->bottom < nPenY) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700147 bounds->bottom = nPenY;
148 }
149 if (bounds->left > nPenX) {
150 bounds->left = nPenX;
151 }
152 if (bounds->right < nPenX + width) {
153 bounds->right = nPenX + width;
154 }
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800155 if (bounds->top > nPenY - height) {
156 bounds->top = nPenY - height;
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700157 }
158}
159
160void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
161 uint32_t start, int32_t numGlyphs,
162 RenderMode mode, Rect *bounds,
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800163 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
164 if (!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700165 return;
166 }
167
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800168 if (mode == Font::MEASURE) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700169 if (bounds == NULL) {
170 LOGE("No return rectangle provided to measure text");
171 return;
172 }
173 // Reset min and max of the bounding box to something large
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800174 bounds->set(1e6, -1e6, 1e6, -1e6);
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700175 }
176
177 int32_t penX = x, penY = y;
178 int32_t glyphsLeft = 1;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800179 if (numGlyphs > 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700180 glyphsLeft = numGlyphs;
181 }
182
183 size_t index = start;
184 size_t nextIndex = 0;
185
186 while (glyphsLeft > 0) {
187
Kenny Root300ba682010-11-09 14:37:23 -0800188 int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700189
190 // Reached the end of the string or encountered
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800191 if (utfChar < 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700192 break;
193 }
194
195 // Move to the next character in the array
196 index = nextIndex;
197
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700198 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700199
200 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800201 if (cachedGlyph->mIsValid) {
202 switch (mode) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700203 case FRAMEBUFFER:
204 drawCachedGlyph(cachedGlyph, penX, penY);
205 break;
206 case BITMAP:
207 drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
208 break;
209 case MEASURE:
210 measureCachedGlyph(cachedGlyph, penX, penY, bounds);
211 break;
212 }
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700213 }
214
215 penX += (cachedGlyph->mAdvance.x >> 6);
216
217 // If we were given a specific number of glyphs, decrement
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800218 if (numGlyphs > 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700219 glyphsLeft --;
220 }
221 }
222}
223
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700224Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
225
226 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800227 if (cachedGlyph == NULL) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700228 cachedGlyph = cacheGlyph((uint32_t)utfChar);
229 }
230 // Is the glyph still in texture cache?
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800231 if (!cachedGlyph->mIsValid) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700232 updateGlyphCache(cachedGlyph);
233 }
234
235 return cachedGlyph;
236}
237
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800238void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700239 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800240 if (error) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700241 LOGE("Couldn't load glyph.");
242 return;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700243 }
244
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700245 glyph->mAdvance = mFace->glyph->advance;
246 glyph->mBitmapLeft = mFace->glyph->bitmap_left;
247 glyph->mBitmapTop = mFace->glyph->bitmap_top;
248
249 FT_Bitmap *bitmap = &mFace->glyph->bitmap;
250
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk071508d2010-06-30 12:49:27 -0700257 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700258
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800259 if (!glyph->mIsValid) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700260 return;
261 }
262
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700263 uint32_t endX = startX + bitmap->width;
264 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700265
266 glyph->mBitmapMinX = startX;
267 glyph->mBitmapMinY = startY;
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700268 glyph->mBitmapWidth = bitmap->width;
269 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800280Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700286
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700287 updateGlyphCache(newGlyph);
288
289 return newGlyph;
290}
291
Alex Sakhartchoukb0253ea2011-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 Sakhartchouk27f50522010-08-18 15:46:43 -0700294 rsc->mStateFont.checkInit();
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700295 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
296
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800297 for (uint32_t i = 0; i < activeFonts.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700298 Font *ithFont = activeFonts[i];
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800299 if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700300 return ithFont;
301 }
302 }
303
304 Font *newFont = new Font(rsc);
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800305 bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800306 if (isInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700307 activeFonts.push(newFont);
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700308 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700309 return newFont;
310 }
311
Jason Samsb38d5342010-10-21 14:06:55 -0700312 ObjectBase::checkDelete(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700313 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700314}
315
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800316Font::~Font() {
317 if (mFace) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700318 FT_Done_Face(mFace);
319 }
320
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800321 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700322 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700323 delete glyph;
324 }
325}
326
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800327FontState::FontState() {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700328 mInitialized = false;
329 mMaxNumberOfQuads = 1024;
330 mCurrentQuadIndex = 0;
331 mRSC = NULL;
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700332 mLibrary = NULL;
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700340 gamma = atof(property);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700341 }
342
343 // Get the black gamma threshold
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700344 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700345 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700346 blackThreshold = atoi(property);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700347 }
348 mBlackThreshold = (float)(blackThreshold) / 255.0f;
349
350 // Get the white gamma threshold
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700351 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700352 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700353 whiteThreshold = atoi(property);
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk960ae152010-10-12 14:15:17 -0700360
361 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700362}
363
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800364FontState::~FontState() {
365 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700366 delete mCacheLines[i];
367 }
368
369 rsAssert(!mActiveFonts.size());
370}
371
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800372FT_Library FontState::getLib() {
373 if (!mLibrary) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700374 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800375 if (error) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700376 LOGE("Unable to initialize freetype");
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700377 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700378 }
379 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700380
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700381 return mLibrary;
382}
383
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800384void FontState::init(Context *rsc) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700385 mRSC = rsc;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700386}
387
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800388void FontState::flushAllAndInvalidate() {
389 if (mCurrentQuadIndex != 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700390 issueDrawCommand();
391 mCurrentQuadIndex = 0;
392 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800393 for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700394 mActiveFonts[i]->invalidateTextureCache();
395 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800396 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700397 mCacheLines[i]->mCurrentCol = 0;
398 }
399}
400
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800401bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700402 // If the glyph is too tall, don't cache it
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800403 if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800413 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700414 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800415 if (bitmapFit) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800421 if (!bitmapFit) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700422 flushAllAndInvalidate();
423
424 // Try to fit it again
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800425 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700426 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800427 if (bitmapFit) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800433 if (!bitmapFit) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700445 uint32_t cacheWidth = getCacheTextureType()->getDimX();
446
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700447 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
448 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700449
450 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
Alex Sakhartchouked9f2102010-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 Sakhartchouk10825a02010-10-05 11:33:27 -0700453 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchouk9b949fc2010-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 Sams6d8eb262010-12-15 01:41:00 -0800460 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700461 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700462
463 // Some debug code
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800464 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800474void FontState::initRenderState() {
Alex Sakhartchoukd2091632010-10-06 11:15:01 -0700475 String8 shaderString("varying vec2 varTex0;\n");
Alex Sakhartchoukc984dd72010-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 Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700479 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchoukc984dd72010-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 Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700484 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700485 mRSC->mStateElement.elementBuilderBegin();
486 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700487 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700488 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
489
Jason Sams31a7e422010-10-26 13:09:17 -0700490 Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
Alex Sakhartchoukc984dd72010-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 Sakhartchouk67f2e442010-11-18 15:22:43 -0800495 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
496 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700497
Jason Sams5476b452010-12-08 16:14:36 -0800498 mFontShaderFConstant.set(new Allocation(mRSC, inputType,
499 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700500 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
501 shaderString.length(), tmp, 4);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700502 mFontShaderF.set(pf);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700503 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchouk9b949fc2010-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 Sakhartchoukb89aaac2010-09-23 16:16:33 -0700508 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700509
510 ProgramStore *fontStore = new ProgramStore(mRSC);
511 mFontProgramStore.set(fontStore);
512 mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
513 mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
514 mFontProgramStore->setDitherEnable(false);
515 mFontProgramStore->setDepthMask(false);
516}
517
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800518void FontState::initTextTexture() {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700519 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
520
521 // We will allocate a texture to initially hold 32 character bitmaps
Jason Sams31a7e422010-10-26 13:09:17 -0700522 Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700523
Jason Sams5476b452010-12-08 16:14:36 -0800524 Allocation *cacheAlloc = new Allocation(mRSC, texType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700525 mTextTexture.set(cacheAlloc);
Jason Sams6d8eb262010-12-15 01:41:00 -0800526 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700527
528 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700529 int32_t nextLine = 0;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700530 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
531 nextLine += mCacheLines.top()->mMaxHeight;
532 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
533 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700534 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
535 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700536 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
537 nextLine += mCacheLines.top()->mMaxHeight;
538 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
539 nextLine += mCacheLines.top()->mMaxHeight;
540 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
541 nextLine += mCacheLines.top()->mMaxHeight;
542 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
543}
544
545// Avoid having to reallocate memory and render quad by quad
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800546void FontState::initVertexArrayBuffers() {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700547 // Now lets write index data
548 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700549 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Jason Sams31a7e422010-10-26 13:09:17 -0700550 Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700551
Jason Sams5476b452010-12-08 16:14:36 -0800552 Allocation *indexAlloc = new Allocation(mRSC, indexType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700553 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
554
555 // Four verts, two triangles , six indices per quad
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800556 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700557 int32_t i6 = i * 6;
558 int32_t i4 = i * 4;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700559
560 indexPtr[i6 + 0] = i4 + 0;
561 indexPtr[i6 + 1] = i4 + 1;
562 indexPtr[i6 + 2] = i4 + 2;
563
564 indexPtr[i6 + 3] = i4 + 0;
565 indexPtr[i6 + 4] = i4 + 2;
566 indexPtr[i6 + 5] = i4 + 3;
567 }
568
569 indexAlloc->deferedUploadToBufferObject(mRSC);
570 mIndexBuffer.set(indexAlloc);
571
572 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
573 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
574
Alex Sakhartchouk98bfe5d2010-10-18 17:18:50 -0700575 mRSC->mStateElement.elementBuilderBegin();
576 mRSC->mStateElement.elementBuilderAdd(posElem, "position", 1);
577 mRSC->mStateElement.elementBuilderAdd(texElem, "texture0", 1);
578 const Element *vertexDataElem = mRSC->mStateElement.elementBuilderCreate(mRSC);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700579
Jason Sams31a7e422010-10-26 13:09:17 -0700580 Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
581 mMaxNumberOfQuads * 4,
582 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700583
Jason Sams5476b452010-12-08 16:14:36 -0800584 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700585 mTextMeshPtr = (float*)vertexAlloc->getPtr();
586
587 mVertexArray.set(vertexAlloc);
588}
589
590// We don't want to allocate anything unless we actually draw text
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800591void FontState::checkInit() {
592 if (mInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700593 return;
594 }
595
596 initTextTexture();
597 initRenderState();
598
599 initVertexArrayBuffers();
600
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700601 // We store a string with letters in a rough frequency of occurrence
602 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
603 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
604 mLatinPrecache += String8(",.?!()-+@;:`'");
605 mLatinPrecache += String8("0123456789");
606
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700607 mInitialized = true;
608}
609
610void FontState::issueDrawCommand() {
Jason Samsa17af042010-11-17 15:29:32 -0800611 Context::PushState ps(mRSC);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700612
Jason Samsa17af042010-11-17 15:29:32 -0800613 mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
614 mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
615 mRSC->setProgramFragment(mFontShaderF.get());
616 mRSC->setProgramStore(mFontProgramStore.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700617
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800618 if (mConstantsDirty) {
Jason Sams49a05d72010-12-29 14:31:29 -0800619 mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700620 mConstantsDirty = false;
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700621 }
622
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700623 if (!mRSC->setupCheck()) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700624 return;
625 }
626
627 float *vtx = (float*)mVertexArray->getPtr();
628 float *tex = vtx + 3;
629
Alex Sakhartchouk9d71e212010-11-08 15:10:52 -0800630 VertexArray::Attrib attribs[2];
631 attribs[0].set(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
632 attribs[1].set(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
633 VertexArray va(attribs, 2);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700634 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
635
636 mIndexBuffer->uploadCheck(mRSC);
637 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
638 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700639}
640
641void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800642 float u1, float v1,
643 float x2, float y2, float z2,
644 float u2, float v2,
645 float x3, float y3, float z3,
646 float u3, float v3,
647 float x4, float y4, float z4,
648 float u4, float v4) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700649 const uint32_t vertsPerQuad = 4;
650 const uint32_t floatsPerVert = 5;
651 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
652
653 // Cull things that are off the screen
654 float width = (float)mRSC->getWidth();
655 float height = (float)mRSC->getHeight();
656
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800657 if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700658 return;
659 }
660
661 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
662 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
663 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
664 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
665
666 (*currentPos++) = x1;
667 (*currentPos++) = y1;
668 (*currentPos++) = z1;
669 (*currentPos++) = u1;
670 (*currentPos++) = v1;
671
672 (*currentPos++) = x2;
673 (*currentPos++) = y2;
674 (*currentPos++) = z2;
675 (*currentPos++) = u2;
676 (*currentPos++) = v2;
677
678 (*currentPos++) = x3;
679 (*currentPos++) = y3;
680 (*currentPos++) = z3;
681 (*currentPos++) = u3;
682 (*currentPos++) = v3;
683
684 (*currentPos++) = x4;
685 (*currentPos++) = y4;
686 (*currentPos++) = z4;
687 (*currentPos++) = u4;
688 (*currentPos++) = v4;
689
690 mCurrentQuadIndex ++;
691
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800692 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700693 issueDrawCommand();
694 mCurrentQuadIndex = 0;
695 }
696}
697
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700698uint32_t FontState::getRemainingCacheCapacity() {
699 uint32_t remainingCapacity = 0;
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700700 uint32_t totalPixels = 0;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800701 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700702 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
703 totalPixels += mCacheLines[i]->mMaxWidth;
704 }
705 remainingCapacity = (remainingCapacity * 100) / totalPixels;
706 return remainingCapacity;
707}
708
709void FontState::precacheLatin(Font *font) {
710 // Remaining capacity is measured in %
711 uint32_t remainingCapacity = getRemainingCacheCapacity();
712 uint32_t precacheIdx = 0;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800713 while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700714 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
715 remainingCapacity = getRemainingCacheCapacity();
716 precacheIdx ++;
717 }
718}
719
720
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700721void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
722 uint32_t startIndex, int32_t numGlyphs,
723 Font::RenderMode mode,
724 Font::Rect *bounds,
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800725 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700726 checkInit();
727
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700728 // Render code here
729 Font *currentFont = mRSC->getFont();
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800730 if (!currentFont) {
731 if (!mDefault.get()) {
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -0800732 String8 fontsDir("/fonts/DroidSans.ttf");
733 String8 fullPath(getenv("ANDROID_ROOT"));
734 fullPath += fontsDir;
735
736 mDefault.set(Font::create(mRSC, fullPath.string(), 16, 96));
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700737 }
738 currentFont = mDefault.get();
739 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800740 if (!currentFont) {
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700741 LOGE("Unable to initialize any fonts");
742 return;
743 }
744
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700745 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
746 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700747
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800748 if (mCurrentQuadIndex != 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700749 issueDrawCommand();
750 mCurrentQuadIndex = 0;
751 }
752}
753
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700754void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
755 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800756 bounds->bottom = - bounds->bottom;
757 bounds->top = - bounds->top;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700758}
759
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700760void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700761 mConstants.mFontColor[0] = r;
762 mConstants.mFontColor[1] = g;
763 mConstants.mFontColor[2] = b;
764 mConstants.mFontColor[3] = a;
765
766 mConstants.mGamma = 1.0f;
Alex Sakhartchouk76322af2010-10-05 13:23:55 -0700767 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700768 if (luminance <= mBlackThreshold) {
769 mConstants.mGamma = mBlackGamma;
770 } else if (luminance >= mWhiteThreshold) {
771 mConstants.mGamma = mWhiteGamma;
772 }
Alex Sakhartchouk960ae152010-10-12 14:15:17 -0700773
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700774 mConstantsDirty = true;
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700775}
776
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700777void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700778 *r = mConstants.mFontColor[0];
779 *g = mConstants.mFontColor[1];
780 *b = mConstants.mFontColor[2];
781 *a = mConstants.mFontColor[3];
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700782}
783
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800784void FontState::deinit(Context *rsc) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700785 mInitialized = false;
786
Stephen Hines01f0ad72010-09-28 15:45:45 -0700787 mFontShaderFConstant.clear();
788
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700789 mIndexBuffer.clear();
790 mVertexArray.clear();
791
792 mFontShaderF.clear();
793 mFontSampler.clear();
794 mFontProgramStore.clear();
795
796 mTextTexture.clear();
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800797 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700798 delete mCacheLines[i];
799 }
800 mCacheLines.clear();
801
802 mDefault.clear();
803
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800804 if (mLibrary) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700805 FT_Done_FreeType( mLibrary );
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700806 mLibrary = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700807 }
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700808}
809
810namespace android {
811namespace renderscript {
812
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -0800813RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, float fontSize, uint32_t dpi) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700814 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800815 if (newFont) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700816 newFont->incUserRef();
817 }
818 return newFont;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700819}
820
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800821RsFont rsi_FontCreateFromMemory(Context *rsc, char const *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
822 Font *newFont = Font::create(rsc, name, fontSize, dpi, data, dataLen);
823 if (newFont) {
824 newFont->incUserRef();
825 }
826 return newFont;
827}
828
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700829} // renderscript
830} // android