blob: 2fa1f0aabf9f8ed99e3d5f6e67f053f90ec519a8 [file] [log] [blame]
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -07001
2/*
3 * Copyright (C) 2009 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
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 Sakhartchoukc9fa3052010-10-01 15:20:41 -070026#include <cutils/properties.h>
Alex Sakhartchoukd3e0ad42010-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 Sakhartchoukafb743a2010-11-09 17:00:54 -080037Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070038 mInitialized = false;
39 mHasKerning = false;
Alex Sakhartchouk3659d942010-06-30 16:53:43 -070040 mFace = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070041}
42
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080043bool Font::init(const char *name, uint32_t fontSize, uint32_t dpi) {
44 if (mInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070045 LOGE("Reinitialization of fonts not supported");
46 return false;
47 }
48
49 String8 fontsDir("/fonts/");
50 String8 fullPath(getenv("ANDROID_ROOT"));
51 fullPath += fontsDir;
52 fullPath += name;
53
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -070054 FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080055 if (error) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070056 LOGE("Unable to initialize font %s", fullPath.string());
57 return false;
58 }
59
60 mFontName = name;
61 mFontSize = fontSize;
62 mDpi = dpi;
63
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070064 error = FT_Set_Char_Size(mFace, fontSize * 64, 0, dpi, 0);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080065 if (error) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070066 LOGE("Unable to set font size on %s", fullPath.string());
67 return false;
68 }
69
70 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070071
72 mInitialized = true;
73 return true;
74}
75
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080076void Font::invalidateTextureCache() {
77 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070078 mCachedGlyphs.valueAt(i)->mIsValid = false;
79 }
80}
81
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080082void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070083 FontState *state = &mRSC->mStateFont;
84
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070085 int32_t nPenX = x + glyph->mBitmapLeft;
86 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070087
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070088 float u1 = glyph->mBitmapMinU;
89 float u2 = glyph->mBitmapMaxU;
90 float v1 = glyph->mBitmapMinV;
91 float v2 = glyph->mBitmapMaxV;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070092
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070093 int32_t width = (int32_t) glyph->mBitmapWidth;
94 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070095
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070096 state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
97 nPenX + width, nPenY, 0, u2, v2,
98 nPenX + width, nPenY - height, 0, u2, v1,
99 nPenX, nPenY - height, 0, u1, v1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700100}
101
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700102void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
103 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
104 int32_t nPenX = x + glyph->mBitmapLeft;
105 int32_t nPenY = y + glyph->mBitmapTop;
106
107 uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
108 uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
109
110 FontState *state = &mRSC->mStateFont;
111 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
112 const uint8_t* cacheBuffer = state->getTextTextureData();
113
114 uint32_t cacheX = 0, cacheY = 0;
115 int32_t bX = 0, bY = 0;
116 for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
117 for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
118 if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
119 LOGE("Skipping invalid index");
120 continue;
121 }
122 uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
123 bitmap[bY * bitmapW + bX] = tempCol;
124 }
125 }
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700126}
127
128void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
129 int32_t nPenX = x + glyph->mBitmapLeft;
130 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
131
132 int32_t width = (int32_t) glyph->mBitmapWidth;
133 int32_t height = (int32_t) glyph->mBitmapHeight;
134
135 if (bounds->bottom > nPenY) {
136 bounds->bottom = nPenY;
137 }
138 if (bounds->left > nPenX) {
139 bounds->left = nPenX;
140 }
141 if (bounds->right < nPenX + width) {
142 bounds->right = nPenX + width;
143 }
144 if (bounds->top < nPenY + height) {
145 bounds->top = nPenY + height;
146 }
147}
148
149void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
150 uint32_t start, int32_t numGlyphs,
151 RenderMode mode, Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800152 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
153 if (!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700154 return;
155 }
156
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800157 if (mode == Font::MEASURE) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700158 if (bounds == NULL) {
159 LOGE("No return rectangle provided to measure text");
160 return;
161 }
162 // Reset min and max of the bounding box to something large
163 bounds->set(1e6, -1e6, -1e6, 1e6);
164 }
165
166 int32_t penX = x, penY = y;
167 int32_t glyphsLeft = 1;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800168 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700169 glyphsLeft = numGlyphs;
170 }
171
172 size_t index = start;
173 size_t nextIndex = 0;
174
175 while (glyphsLeft > 0) {
176
Kenny Rootc9c38dd2010-11-09 14:37:23 -0800177 int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700178
179 // Reached the end of the string or encountered
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800180 if (utfChar < 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700181 break;
182 }
183
184 // Move to the next character in the array
185 index = nextIndex;
186
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700187 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700188
189 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800190 if (cachedGlyph->mIsValid) {
191 switch (mode) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700192 case FRAMEBUFFER:
193 drawCachedGlyph(cachedGlyph, penX, penY);
194 break;
195 case BITMAP:
196 drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
197 break;
198 case MEASURE:
199 measureCachedGlyph(cachedGlyph, penX, penY, bounds);
200 break;
201 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700202 }
203
204 penX += (cachedGlyph->mAdvance.x >> 6);
205
206 // If we were given a specific number of glyphs, decrement
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800207 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700208 glyphsLeft --;
209 }
210 }
211}
212
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700213Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
214
215 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800216 if (cachedGlyph == NULL) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700217 cachedGlyph = cacheGlyph((uint32_t)utfChar);
218 }
219 // Is the glyph still in texture cache?
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800220 if (!cachedGlyph->mIsValid) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700221 updateGlyphCache(cachedGlyph);
222 }
223
224 return cachedGlyph;
225}
226
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800227void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700228 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800229 if (error) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700230 LOGE("Couldn't load glyph.");
231 return;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700232 }
233
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700234 glyph->mAdvance = mFace->glyph->advance;
235 glyph->mBitmapLeft = mFace->glyph->bitmap_left;
236 glyph->mBitmapTop = mFace->glyph->bitmap_top;
237
238 FT_Bitmap *bitmap = &mFace->glyph->bitmap;
239
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700240 // Now copy the bitmap into the cache texture
241 uint32_t startX = 0;
242 uint32_t startY = 0;
243
244 // Let the font state figure out where to put the bitmap
245 FontState *state = &mRSC->mStateFont;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700246 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700247
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800248 if (!glyph->mIsValid) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700249 return;
250 }
251
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700252 uint32_t endX = startX + bitmap->width;
253 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700254
255 glyph->mBitmapMinX = startX;
256 glyph->mBitmapMinY = startY;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700257 glyph->mBitmapWidth = bitmap->width;
258 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700259
260 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
261 uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
262
263 glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
264 glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
265 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
266 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
267}
268
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800269Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700270 CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
271 mCachedGlyphs.add(glyph, newGlyph);
272
273 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
274 newGlyph->mIsValid = false;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700275
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700276 updateGlyphCache(newGlyph);
277
278 return newGlyph;
279}
280
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800281Font * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi) {
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700282 rsc->mStateFont.checkInit();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700283 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
284
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800285 for (uint32_t i = 0; i < activeFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700286 Font *ithFont = activeFonts[i];
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800287 if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700288 return ithFont;
289 }
290 }
291
292 Font *newFont = new Font(rsc);
293 bool isInitialized = newFont->init(name, fontSize, dpi);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800294 if (isInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700295 activeFonts.push(newFont);
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700296 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700297 return newFont;
298 }
299
Jason Sams225afd32010-10-21 14:06:55 -0700300 ObjectBase::checkDelete(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700301 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700302}
303
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800304Font::~Font() {
305 if (mFace) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700306 FT_Done_Face(mFace);
307 }
308
309 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
310 if (mRSC->mStateFont.mActiveFonts[ct] == this) {
311 mRSC->mStateFont.mActiveFonts.removeAt(ct);
312 break;
313 }
314 }
315
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800316 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700317 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700318 delete glyph;
319 }
320}
321
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800322FontState::FontState() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700323 mInitialized = false;
324 mMaxNumberOfQuads = 1024;
325 mCurrentQuadIndex = 0;
326 mRSC = NULL;
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700327 mLibrary = NULL;
Alex Sakhartchoukc9fa3052010-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) {
335 LOGD(" Setting text gamma to %s", property);
336 gamma = atof(property);
337 } else {
338 LOGD(" Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA);
339 }
340
341 // Get the black gamma threshold
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700342 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700343 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
344 LOGD(" Setting text black gamma threshold to %s", property);
345 blackThreshold = atoi(property);
346 } else {
347 LOGD(" Using default text black gamma threshold of %d",
348 DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD);
349 }
350 mBlackThreshold = (float)(blackThreshold) / 255.0f;
351
352 // Get the white gamma threshold
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700353 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700354 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
355 LOGD(" Setting text white gamma threshold to %s", property);
356 whiteThreshold = atoi(property);
357 } else {
358 LOGD(" Using default white black gamma threshold of %d",
359 DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD);
360 }
361 mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
362
363 // Compute the gamma tables
364 mBlackGamma = gamma;
365 mWhiteGamma = 1.0f / gamma;
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700366
367 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700368}
369
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800370FontState::~FontState() {
371 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700372 delete mCacheLines[i];
373 }
374
375 rsAssert(!mActiveFonts.size());
376}
377
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800378FT_Library FontState::getLib() {
379 if (!mLibrary) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700380 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800381 if (error) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700382 LOGE("Unable to initialize freetype");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700383 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700384 }
385 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700386
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700387 return mLibrary;
388}
389
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800390void FontState::init(Context *rsc) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700391 mRSC = rsc;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700392}
393
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800394void FontState::flushAllAndInvalidate() {
395 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700396 issueDrawCommand();
397 mCurrentQuadIndex = 0;
398 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800399 for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700400 mActiveFonts[i]->invalidateTextureCache();
401 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800402 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700403 mCacheLines[i]->mCurrentCol = 0;
404 }
405}
406
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800407bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700408 // If the glyph is too tall, don't cache it
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800409 if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700410 LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
411 return false;
412 }
413
414 // Now copy the bitmap into the cache texture
415 uint32_t startX = 0;
416 uint32_t startY = 0;
417
418 bool bitmapFit = false;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800419 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700420 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800421 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700422 break;
423 }
424 }
425
426 // If the new glyph didn't fit, flush the state so far and invalidate everything
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800427 if (!bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700428 flushAllAndInvalidate();
429
430 // Try to fit it again
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800431 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700432 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800433 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700434 break;
435 }
436 }
437
438 // if we still don't fit, something is wrong and we shouldn't draw
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800439 if (!bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700440 LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
441 return false;
442 }
443 }
444
445 *retOriginX = startX;
446 *retOriginY = startY;
447
448 uint32_t endX = startX + bitmap->width;
449 uint32_t endY = startY + bitmap->rows;
450
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700451 uint32_t cacheWidth = getCacheTextureType()->getDimX();
452
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700453 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
454 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700455
456 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800457 for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
458 for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700459 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700460 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
461 }
462 }
463
464 // This will dirty the texture and the shader so next time
465 // we draw it will upload the data
Jason Samsb7e83bd2010-12-15 01:41:00 -0800466 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700467 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700468
469 // Some debug code
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800470 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700471 LOGE("Cache Line: H: %u Empty Space: %f",
472 mCacheLines[i]->mMaxHeight,
473 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
474
475 }*/
476
477 return true;
478}
479
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800480void FontState::initRenderState() {
Alex Sakhartchouk7ffcaf22010-10-06 11:15:01 -0700481 String8 shaderString("varying vec2 varTex0;\n");
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700482 shaderString.append("void main() {\n");
483 shaderString.append(" lowp vec4 col = UNI_Color;\n");
484 shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700485 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700486 shaderString.append(" gl_FragColor = col;\n");
487 shaderString.append("}\n");
488
489 const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700490 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700491 mRSC->mStateElement.elementBuilderBegin();
492 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700493 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700494 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
495
Jason Samsf0c1df42010-10-26 13:09:17 -0700496 Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700497
498 uint32_t tmp[4];
499 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
500 tmp[1] = (uint32_t)inputType;
Alex Sakhartchouk84e40272010-11-18 15:22:43 -0800501 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
502 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700503
Jason Sams366c9c82010-12-08 16:14:36 -0800504 mFontShaderFConstant.set(new Allocation(mRSC, inputType,
505 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700506 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
507 shaderString.length(), tmp, 4);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700508 mFontShaderF.set(pf);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700509 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700510
511 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
512 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
513 mFontSampler.set(sampler);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700514 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700515
516 ProgramStore *fontStore = new ProgramStore(mRSC);
517 mFontProgramStore.set(fontStore);
518 mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
519 mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
520 mFontProgramStore->setDitherEnable(false);
521 mFontProgramStore->setDepthMask(false);
522}
523
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800524void FontState::initTextTexture() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700525 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
526
527 // We will allocate a texture to initially hold 32 character bitmaps
Jason Samsf0c1df42010-10-26 13:09:17 -0700528 Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700529
Jason Sams366c9c82010-12-08 16:14:36 -0800530 Allocation *cacheAlloc = new Allocation(mRSC, texType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700531 mTextTexture.set(cacheAlloc);
Jason Samsb7e83bd2010-12-15 01:41:00 -0800532 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700533
534 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700535 int32_t nextLine = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700536 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
537 nextLine += mCacheLines.top()->mMaxHeight;
538 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
539 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700540 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
541 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700542 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
543 nextLine += mCacheLines.top()->mMaxHeight;
544 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
545 nextLine += mCacheLines.top()->mMaxHeight;
546 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
547 nextLine += mCacheLines.top()->mMaxHeight;
548 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
549}
550
551// Avoid having to reallocate memory and render quad by quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800552void FontState::initVertexArrayBuffers() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700553 // Now lets write index data
554 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700555 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Jason Samsf0c1df42010-10-26 13:09:17 -0700556 Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700557
Jason Sams366c9c82010-12-08 16:14:36 -0800558 Allocation *indexAlloc = new Allocation(mRSC, indexType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700559 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
560
561 // Four verts, two triangles , six indices per quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800562 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700563 int32_t i6 = i * 6;
564 int32_t i4 = i * 4;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700565
566 indexPtr[i6 + 0] = i4 + 0;
567 indexPtr[i6 + 1] = i4 + 1;
568 indexPtr[i6 + 2] = i4 + 2;
569
570 indexPtr[i6 + 3] = i4 + 0;
571 indexPtr[i6 + 4] = i4 + 2;
572 indexPtr[i6 + 5] = i4 + 3;
573 }
574
575 indexAlloc->deferedUploadToBufferObject(mRSC);
576 mIndexBuffer.set(indexAlloc);
577
578 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
579 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
580
Alex Sakhartchouk64cd98e2010-10-18 17:18:50 -0700581 mRSC->mStateElement.elementBuilderBegin();
582 mRSC->mStateElement.elementBuilderAdd(posElem, "position", 1);
583 mRSC->mStateElement.elementBuilderAdd(texElem, "texture0", 1);
584 const Element *vertexDataElem = mRSC->mStateElement.elementBuilderCreate(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700585
Jason Samsf0c1df42010-10-26 13:09:17 -0700586 Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
587 mMaxNumberOfQuads * 4,
588 0, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700589
Jason Sams366c9c82010-12-08 16:14:36 -0800590 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700591 mTextMeshPtr = (float*)vertexAlloc->getPtr();
592
593 mVertexArray.set(vertexAlloc);
594}
595
596// We don't want to allocate anything unless we actually draw text
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800597void FontState::checkInit() {
598 if (mInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700599 return;
600 }
601
602 initTextTexture();
603 initRenderState();
604
605 initVertexArrayBuffers();
606
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700607 // We store a string with letters in a rough frequency of occurrence
608 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
609 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
610 mLatinPrecache += String8(",.?!()-+@;:`'");
611 mLatinPrecache += String8("0123456789");
612
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700613 mInitialized = true;
614}
615
616void FontState::issueDrawCommand() {
Jason Sams60709252010-11-17 15:29:32 -0800617 Context::PushState ps(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700618
Jason Sams60709252010-11-17 15:29:32 -0800619 mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
620 mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
621 mRSC->setProgramFragment(mFontShaderF.get());
622 mRSC->setProgramStore(mFontProgramStore.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700623
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800624 if (mConstantsDirty) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700625 mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants));
626 mConstantsDirty = false;
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700627 }
628
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700629 if (!mRSC->setupCheck()) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700630 return;
631 }
632
633 float *vtx = (float*)mVertexArray->getPtr();
634 float *tex = vtx + 3;
635
Alex Sakhartchouk54929cc2010-11-08 15:10:52 -0800636 VertexArray::Attrib attribs[2];
637 attribs[0].set(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
638 attribs[1].set(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
639 VertexArray va(attribs, 2);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700640 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
641
642 mIndexBuffer->uploadCheck(mRSC);
643 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
644 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700645}
646
647void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800648 float u1, float v1,
649 float x2, float y2, float z2,
650 float u2, float v2,
651 float x3, float y3, float z3,
652 float u3, float v3,
653 float x4, float y4, float z4,
654 float u4, float v4) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700655 const uint32_t vertsPerQuad = 4;
656 const uint32_t floatsPerVert = 5;
657 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
658
659 // Cull things that are off the screen
660 float width = (float)mRSC->getWidth();
661 float height = (float)mRSC->getHeight();
662
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800663 if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700664 return;
665 }
666
667 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
668 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
669 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
670 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
671
672 (*currentPos++) = x1;
673 (*currentPos++) = y1;
674 (*currentPos++) = z1;
675 (*currentPos++) = u1;
676 (*currentPos++) = v1;
677
678 (*currentPos++) = x2;
679 (*currentPos++) = y2;
680 (*currentPos++) = z2;
681 (*currentPos++) = u2;
682 (*currentPos++) = v2;
683
684 (*currentPos++) = x3;
685 (*currentPos++) = y3;
686 (*currentPos++) = z3;
687 (*currentPos++) = u3;
688 (*currentPos++) = v3;
689
690 (*currentPos++) = x4;
691 (*currentPos++) = y4;
692 (*currentPos++) = z4;
693 (*currentPos++) = u4;
694 (*currentPos++) = v4;
695
696 mCurrentQuadIndex ++;
697
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800698 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700699 issueDrawCommand();
700 mCurrentQuadIndex = 0;
701 }
702}
703
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700704uint32_t FontState::getRemainingCacheCapacity() {
705 uint32_t remainingCapacity = 0;
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700706 uint32_t totalPixels = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800707 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700708 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
709 totalPixels += mCacheLines[i]->mMaxWidth;
710 }
711 remainingCapacity = (remainingCapacity * 100) / totalPixels;
712 return remainingCapacity;
713}
714
715void FontState::precacheLatin(Font *font) {
716 // Remaining capacity is measured in %
717 uint32_t remainingCapacity = getRemainingCacheCapacity();
718 uint32_t precacheIdx = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800719 while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700720 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
721 remainingCapacity = getRemainingCacheCapacity();
722 precacheIdx ++;
723 }
724}
725
726
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700727void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
728 uint32_t startIndex, int32_t numGlyphs,
729 Font::RenderMode mode,
730 Font::Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800731 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700732 checkInit();
733
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700734 // Render code here
735 Font *currentFont = mRSC->getFont();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800736 if (!currentFont) {
737 if (!mDefault.get()) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700738 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
739 }
740 currentFont = mDefault.get();
741 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800742 if (!currentFont) {
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700743 LOGE("Unable to initialize any fonts");
744 return;
745 }
746
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700747 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
748 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700749
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800750 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700751 issueDrawCommand();
752 mCurrentQuadIndex = 0;
753 }
754}
755
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700756void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
757 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700758}
759
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700760void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchoukc9fa3052010-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 Sakhartchoukc8fb69e2010-10-05 13:23:55 -0700767 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700768 if (luminance <= mBlackThreshold) {
769 mConstants.mGamma = mBlackGamma;
770 } else if (luminance >= mWhiteThreshold) {
771 mConstants.mGamma = mWhiteGamma;
772 }
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700773
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700774 mConstantsDirty = true;
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700775}
776
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700777void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchoukc9fa3052010-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 Sakhartchoukca5a4542010-08-05 11:24:14 -0700782}
783
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800784void FontState::deinit(Context *rsc) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700785 mInitialized = false;
786
Stephen Hines01b7d292010-09-28 15:45:45 -0700787 mFontShaderFConstant.clear();
788
Alex Sakhartchouka1ccecd2010-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 Sakhartchoukafb743a2010-11-09 17:00:54 -0800797 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700798 delete mCacheLines[i];
799 }
800 mCacheLines.clear();
801
802 mDefault.clear();
803
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700804 Vector<Font*> fontsToDereference = mActiveFonts;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800805 for (uint32_t i = 0; i < fontsToDereference.size(); i ++) {
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700806 fontsToDereference[i]->zeroUserRef();
807 }
808
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800809 if (mLibrary) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700810 FT_Done_FreeType( mLibrary );
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700811 mLibrary = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700812 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700813}
814
815namespace android {
816namespace renderscript {
817
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800818RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700819 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800820 if (newFont) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700821 newFont->incUserRef();
822 }
823 return newFont;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700824}
825
826} // renderscript
827} // android