blob: 80bca4391f443f712592d3a518a50f68541040e5 [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 Sakhartchoukc17ace22010-12-17 11:41:08 -080043bool Font::init(const char *name, float fontSize, uint32_t dpi) {
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080044 if (mInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070045 LOGE("Reinitialization of fonts not supported");
46 return false;
47 }
48
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -080049 FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080050 if (error) {
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -080051 LOGE("Unable to initialize font %s", name);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070052 return false;
53 }
54
55 mFontName = name;
56 mFontSize = fontSize;
57 mDpi = dpi;
58
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -080059 error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080060 if (error) {
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -080061 LOGE("Unable to set font size on %s", name);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070062 return false;
63 }
64
65 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070066
67 mInitialized = true;
68 return true;
69}
70
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080071void Font::invalidateTextureCache() {
72 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070073 mCachedGlyphs.valueAt(i)->mIsValid = false;
74 }
75}
76
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080077void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070078 FontState *state = &mRSC->mStateFont;
79
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070080 int32_t nPenX = x + glyph->mBitmapLeft;
81 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070082
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070083 float u1 = glyph->mBitmapMinU;
84 float u2 = glyph->mBitmapMaxU;
85 float v1 = glyph->mBitmapMinV;
86 float v2 = glyph->mBitmapMaxV;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070087
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070088 int32_t width = (int32_t) glyph->mBitmapWidth;
89 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070090
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070091 state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
92 nPenX + width, nPenY, 0, u2, v2,
93 nPenX + width, nPenY - height, 0, u2, v1,
94 nPenX, nPenY - height, 0, u1, v1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070095}
96
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070097void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
98 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
99 int32_t nPenX = x + glyph->mBitmapLeft;
100 int32_t nPenY = y + glyph->mBitmapTop;
101
102 uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
103 uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
104
105 FontState *state = &mRSC->mStateFont;
106 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
107 const uint8_t* cacheBuffer = state->getTextTextureData();
108
109 uint32_t cacheX = 0, cacheY = 0;
110 int32_t bX = 0, bY = 0;
111 for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
112 for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
113 if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
114 LOGE("Skipping invalid index");
115 continue;
116 }
117 uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
118 bitmap[bY * bitmapW + bX] = tempCol;
119 }
120 }
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700121}
122
123void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
124 int32_t nPenX = x + glyph->mBitmapLeft;
125 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
126
127 int32_t width = (int32_t) glyph->mBitmapWidth;
128 int32_t height = (int32_t) glyph->mBitmapHeight;
129
130 if (bounds->bottom > nPenY) {
131 bounds->bottom = nPenY;
132 }
133 if (bounds->left > nPenX) {
134 bounds->left = nPenX;
135 }
136 if (bounds->right < nPenX + width) {
137 bounds->right = nPenX + width;
138 }
139 if (bounds->top < nPenY + height) {
140 bounds->top = nPenY + height;
141 }
142}
143
144void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
145 uint32_t start, int32_t numGlyphs,
146 RenderMode mode, Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800147 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
148 if (!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700149 return;
150 }
151
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800152 if (mode == Font::MEASURE) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700153 if (bounds == NULL) {
154 LOGE("No return rectangle provided to measure text");
155 return;
156 }
157 // Reset min and max of the bounding box to something large
158 bounds->set(1e6, -1e6, -1e6, 1e6);
159 }
160
161 int32_t penX = x, penY = y;
162 int32_t glyphsLeft = 1;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800163 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700164 glyphsLeft = numGlyphs;
165 }
166
167 size_t index = start;
168 size_t nextIndex = 0;
169
170 while (glyphsLeft > 0) {
171
Kenny Rootc9c38dd2010-11-09 14:37:23 -0800172 int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700173
174 // Reached the end of the string or encountered
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800175 if (utfChar < 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700176 break;
177 }
178
179 // Move to the next character in the array
180 index = nextIndex;
181
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700182 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700183
184 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800185 if (cachedGlyph->mIsValid) {
186 switch (mode) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700187 case FRAMEBUFFER:
188 drawCachedGlyph(cachedGlyph, penX, penY);
189 break;
190 case BITMAP:
191 drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
192 break;
193 case MEASURE:
194 measureCachedGlyph(cachedGlyph, penX, penY, bounds);
195 break;
196 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700197 }
198
199 penX += (cachedGlyph->mAdvance.x >> 6);
200
201 // If we were given a specific number of glyphs, decrement
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800202 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700203 glyphsLeft --;
204 }
205 }
206}
207
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700208Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
209
210 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800211 if (cachedGlyph == NULL) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700212 cachedGlyph = cacheGlyph((uint32_t)utfChar);
213 }
214 // Is the glyph still in texture cache?
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800215 if (!cachedGlyph->mIsValid) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700216 updateGlyphCache(cachedGlyph);
217 }
218
219 return cachedGlyph;
220}
221
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800222void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700223 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800224 if (error) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700225 LOGE("Couldn't load glyph.");
226 return;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700227 }
228
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700229 glyph->mAdvance = mFace->glyph->advance;
230 glyph->mBitmapLeft = mFace->glyph->bitmap_left;
231 glyph->mBitmapTop = mFace->glyph->bitmap_top;
232
233 FT_Bitmap *bitmap = &mFace->glyph->bitmap;
234
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700235 // Now copy the bitmap into the cache texture
236 uint32_t startX = 0;
237 uint32_t startY = 0;
238
239 // Let the font state figure out where to put the bitmap
240 FontState *state = &mRSC->mStateFont;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700241 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700242
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800243 if (!glyph->mIsValid) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700244 return;
245 }
246
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700247 uint32_t endX = startX + bitmap->width;
248 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700249
250 glyph->mBitmapMinX = startX;
251 glyph->mBitmapMinY = startY;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700252 glyph->mBitmapWidth = bitmap->width;
253 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700254
255 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
256 uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
257
258 glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
259 glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
260 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
261 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
262}
263
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800264Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700265 CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
266 mCachedGlyphs.add(glyph, newGlyph);
267
268 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
269 newGlyph->mIsValid = false;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700270
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700271 updateGlyphCache(newGlyph);
272
273 return newGlyph;
274}
275
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -0800276Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi) {
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700277 rsc->mStateFont.checkInit();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700278 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
279
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800280 for (uint32_t i = 0; i < activeFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700281 Font *ithFont = activeFonts[i];
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800282 if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700283 return ithFont;
284 }
285 }
286
287 Font *newFont = new Font(rsc);
288 bool isInitialized = newFont->init(name, fontSize, dpi);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800289 if (isInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700290 activeFonts.push(newFont);
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700291 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700292 return newFont;
293 }
294
Jason Sams225afd32010-10-21 14:06:55 -0700295 ObjectBase::checkDelete(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700296 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700297}
298
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800299Font::~Font() {
300 if (mFace) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700301 FT_Done_Face(mFace);
302 }
303
304 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
305 if (mRSC->mStateFont.mActiveFonts[ct] == this) {
306 mRSC->mStateFont.mActiveFonts.removeAt(ct);
307 break;
308 }
309 }
310
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800311 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700312 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700313 delete glyph;
314 }
315}
316
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800317FontState::FontState() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700318 mInitialized = false;
319 mMaxNumberOfQuads = 1024;
320 mCurrentQuadIndex = 0;
321 mRSC = NULL;
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700322 mLibrary = NULL;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700323
324 // Get the renderer properties
325 char property[PROPERTY_VALUE_MAX];
326
327 // Get the gamma
328 float gamma = DEFAULT_TEXT_GAMMA;
329 if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700330 gamma = atof(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700331 }
332
333 // Get the black gamma threshold
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700334 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700335 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700336 blackThreshold = atoi(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700337 }
338 mBlackThreshold = (float)(blackThreshold) / 255.0f;
339
340 // Get the white gamma threshold
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700341 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700342 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700343 whiteThreshold = atoi(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700344 }
345 mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
346
347 // Compute the gamma tables
348 mBlackGamma = gamma;
349 mWhiteGamma = 1.0f / gamma;
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700350
351 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700352}
353
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800354FontState::~FontState() {
355 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700356 delete mCacheLines[i];
357 }
358
359 rsAssert(!mActiveFonts.size());
360}
361
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800362FT_Library FontState::getLib() {
363 if (!mLibrary) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700364 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800365 if (error) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700366 LOGE("Unable to initialize freetype");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700367 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700368 }
369 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700370
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700371 return mLibrary;
372}
373
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800374void FontState::init(Context *rsc) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700375 mRSC = rsc;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700376}
377
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800378void FontState::flushAllAndInvalidate() {
379 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700380 issueDrawCommand();
381 mCurrentQuadIndex = 0;
382 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800383 for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700384 mActiveFonts[i]->invalidateTextureCache();
385 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800386 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700387 mCacheLines[i]->mCurrentCol = 0;
388 }
389}
390
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800391bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700392 // If the glyph is too tall, don't cache it
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800393 if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700394 LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
395 return false;
396 }
397
398 // Now copy the bitmap into the cache texture
399 uint32_t startX = 0;
400 uint32_t startY = 0;
401
402 bool bitmapFit = false;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800403 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700404 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800405 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700406 break;
407 }
408 }
409
410 // If the new glyph didn't fit, flush the state so far and invalidate everything
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800411 if (!bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700412 flushAllAndInvalidate();
413
414 // Try to fit it again
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800415 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700416 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800417 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700418 break;
419 }
420 }
421
422 // if we still don't fit, something is wrong and we shouldn't draw
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800423 if (!bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700424 LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
425 return false;
426 }
427 }
428
429 *retOriginX = startX;
430 *retOriginY = startY;
431
432 uint32_t endX = startX + bitmap->width;
433 uint32_t endY = startY + bitmap->rows;
434
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700435 uint32_t cacheWidth = getCacheTextureType()->getDimX();
436
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700437 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
438 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700439
440 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800441 for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
442 for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700443 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700444 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
445 }
446 }
447
448 // This will dirty the texture and the shader so next time
449 // we draw it will upload the data
Jason Samsb7e83bd2010-12-15 01:41:00 -0800450 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700451 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700452
453 // Some debug code
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800454 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700455 LOGE("Cache Line: H: %u Empty Space: %f",
456 mCacheLines[i]->mMaxHeight,
457 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
458
459 }*/
460
461 return true;
462}
463
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800464void FontState::initRenderState() {
Alex Sakhartchouk7ffcaf22010-10-06 11:15:01 -0700465 String8 shaderString("varying vec2 varTex0;\n");
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700466 shaderString.append("void main() {\n");
467 shaderString.append(" lowp vec4 col = UNI_Color;\n");
468 shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700469 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700470 shaderString.append(" gl_FragColor = col;\n");
471 shaderString.append("}\n");
472
473 const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700474 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700475 mRSC->mStateElement.elementBuilderBegin();
476 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700477 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700478 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
479
Jason Samsf0c1df42010-10-26 13:09:17 -0700480 Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700481
482 uint32_t tmp[4];
483 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
484 tmp[1] = (uint32_t)inputType;
Alex Sakhartchouk84e40272010-11-18 15:22:43 -0800485 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
486 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700487
Jason Sams366c9c82010-12-08 16:14:36 -0800488 mFontShaderFConstant.set(new Allocation(mRSC, inputType,
489 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700490 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
491 shaderString.length(), tmp, 4);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700492 mFontShaderF.set(pf);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700493 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700494
495 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
496 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
497 mFontSampler.set(sampler);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700498 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700499
500 ProgramStore *fontStore = new ProgramStore(mRSC);
501 mFontProgramStore.set(fontStore);
502 mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
503 mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
504 mFontProgramStore->setDitherEnable(false);
505 mFontProgramStore->setDepthMask(false);
506}
507
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800508void FontState::initTextTexture() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700509 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
510
511 // We will allocate a texture to initially hold 32 character bitmaps
Jason Samsf0c1df42010-10-26 13:09:17 -0700512 Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700513
Jason Sams366c9c82010-12-08 16:14:36 -0800514 Allocation *cacheAlloc = new Allocation(mRSC, texType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700515 mTextTexture.set(cacheAlloc);
Jason Samsb7e83bd2010-12-15 01:41:00 -0800516 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700517
518 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700519 int32_t nextLine = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700520 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
521 nextLine += mCacheLines.top()->mMaxHeight;
522 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
523 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700524 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
525 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700526 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
527 nextLine += mCacheLines.top()->mMaxHeight;
528 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
529 nextLine += mCacheLines.top()->mMaxHeight;
530 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
531 nextLine += mCacheLines.top()->mMaxHeight;
532 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
533}
534
535// Avoid having to reallocate memory and render quad by quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800536void FontState::initVertexArrayBuffers() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700537 // Now lets write index data
538 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700539 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Jason Samsf0c1df42010-10-26 13:09:17 -0700540 Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700541
Jason Sams366c9c82010-12-08 16:14:36 -0800542 Allocation *indexAlloc = new Allocation(mRSC, indexType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700543 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
544
545 // Four verts, two triangles , six indices per quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800546 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700547 int32_t i6 = i * 6;
548 int32_t i4 = i * 4;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700549
550 indexPtr[i6 + 0] = i4 + 0;
551 indexPtr[i6 + 1] = i4 + 1;
552 indexPtr[i6 + 2] = i4 + 2;
553
554 indexPtr[i6 + 3] = i4 + 0;
555 indexPtr[i6 + 4] = i4 + 2;
556 indexPtr[i6 + 5] = i4 + 3;
557 }
558
559 indexAlloc->deferedUploadToBufferObject(mRSC);
560 mIndexBuffer.set(indexAlloc);
561
562 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
563 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
564
Alex Sakhartchouk64cd98e2010-10-18 17:18:50 -0700565 mRSC->mStateElement.elementBuilderBegin();
566 mRSC->mStateElement.elementBuilderAdd(posElem, "position", 1);
567 mRSC->mStateElement.elementBuilderAdd(texElem, "texture0", 1);
568 const Element *vertexDataElem = mRSC->mStateElement.elementBuilderCreate(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700569
Jason Samsf0c1df42010-10-26 13:09:17 -0700570 Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
571 mMaxNumberOfQuads * 4,
572 0, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700573
Jason Sams366c9c82010-12-08 16:14:36 -0800574 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700575 mTextMeshPtr = (float*)vertexAlloc->getPtr();
576
577 mVertexArray.set(vertexAlloc);
578}
579
580// We don't want to allocate anything unless we actually draw text
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800581void FontState::checkInit() {
582 if (mInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700583 return;
584 }
585
586 initTextTexture();
587 initRenderState();
588
589 initVertexArrayBuffers();
590
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700591 // We store a string with letters in a rough frequency of occurrence
592 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
593 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
594 mLatinPrecache += String8(",.?!()-+@;:`'");
595 mLatinPrecache += String8("0123456789");
596
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700597 mInitialized = true;
598}
599
600void FontState::issueDrawCommand() {
Jason Sams60709252010-11-17 15:29:32 -0800601 Context::PushState ps(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700602
Jason Sams60709252010-11-17 15:29:32 -0800603 mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
604 mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
605 mRSC->setProgramFragment(mFontShaderF.get());
606 mRSC->setProgramStore(mFontProgramStore.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700607
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800608 if (mConstantsDirty) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700609 mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants));
610 mConstantsDirty = false;
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700611 }
612
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700613 if (!mRSC->setupCheck()) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700614 return;
615 }
616
617 float *vtx = (float*)mVertexArray->getPtr();
618 float *tex = vtx + 3;
619
Alex Sakhartchouk54929cc2010-11-08 15:10:52 -0800620 VertexArray::Attrib attribs[2];
621 attribs[0].set(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
622 attribs[1].set(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
623 VertexArray va(attribs, 2);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700624 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
625
626 mIndexBuffer->uploadCheck(mRSC);
627 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
628 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700629}
630
631void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800632 float u1, float v1,
633 float x2, float y2, float z2,
634 float u2, float v2,
635 float x3, float y3, float z3,
636 float u3, float v3,
637 float x4, float y4, float z4,
638 float u4, float v4) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700639 const uint32_t vertsPerQuad = 4;
640 const uint32_t floatsPerVert = 5;
641 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
642
643 // Cull things that are off the screen
644 float width = (float)mRSC->getWidth();
645 float height = (float)mRSC->getHeight();
646
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800647 if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700648 return;
649 }
650
651 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
652 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
653 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
654 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
655
656 (*currentPos++) = x1;
657 (*currentPos++) = y1;
658 (*currentPos++) = z1;
659 (*currentPos++) = u1;
660 (*currentPos++) = v1;
661
662 (*currentPos++) = x2;
663 (*currentPos++) = y2;
664 (*currentPos++) = z2;
665 (*currentPos++) = u2;
666 (*currentPos++) = v2;
667
668 (*currentPos++) = x3;
669 (*currentPos++) = y3;
670 (*currentPos++) = z3;
671 (*currentPos++) = u3;
672 (*currentPos++) = v3;
673
674 (*currentPos++) = x4;
675 (*currentPos++) = y4;
676 (*currentPos++) = z4;
677 (*currentPos++) = u4;
678 (*currentPos++) = v4;
679
680 mCurrentQuadIndex ++;
681
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800682 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700683 issueDrawCommand();
684 mCurrentQuadIndex = 0;
685 }
686}
687
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700688uint32_t FontState::getRemainingCacheCapacity() {
689 uint32_t remainingCapacity = 0;
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700690 uint32_t totalPixels = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800691 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700692 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
693 totalPixels += mCacheLines[i]->mMaxWidth;
694 }
695 remainingCapacity = (remainingCapacity * 100) / totalPixels;
696 return remainingCapacity;
697}
698
699void FontState::precacheLatin(Font *font) {
700 // Remaining capacity is measured in %
701 uint32_t remainingCapacity = getRemainingCacheCapacity();
702 uint32_t precacheIdx = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800703 while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700704 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
705 remainingCapacity = getRemainingCacheCapacity();
706 precacheIdx ++;
707 }
708}
709
710
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700711void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
712 uint32_t startIndex, int32_t numGlyphs,
713 Font::RenderMode mode,
714 Font::Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800715 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700716 checkInit();
717
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700718 // Render code here
719 Font *currentFont = mRSC->getFont();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800720 if (!currentFont) {
721 if (!mDefault.get()) {
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -0800722 String8 fontsDir("/fonts/DroidSans.ttf");
723 String8 fullPath(getenv("ANDROID_ROOT"));
724 fullPath += fontsDir;
725
726 mDefault.set(Font::create(mRSC, fullPath.string(), 16, 96));
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700727 }
728 currentFont = mDefault.get();
729 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800730 if (!currentFont) {
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700731 LOGE("Unable to initialize any fonts");
732 return;
733 }
734
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700735 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
736 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700737
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800738 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700739 issueDrawCommand();
740 mCurrentQuadIndex = 0;
741 }
742}
743
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700744void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
745 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700746}
747
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700748void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700749 mConstants.mFontColor[0] = r;
750 mConstants.mFontColor[1] = g;
751 mConstants.mFontColor[2] = b;
752 mConstants.mFontColor[3] = a;
753
754 mConstants.mGamma = 1.0f;
Alex Sakhartchoukc8fb69e2010-10-05 13:23:55 -0700755 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700756 if (luminance <= mBlackThreshold) {
757 mConstants.mGamma = mBlackGamma;
758 } else if (luminance >= mWhiteThreshold) {
759 mConstants.mGamma = mWhiteGamma;
760 }
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700761
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700762 mConstantsDirty = true;
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700763}
764
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700765void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700766 *r = mConstants.mFontColor[0];
767 *g = mConstants.mFontColor[1];
768 *b = mConstants.mFontColor[2];
769 *a = mConstants.mFontColor[3];
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700770}
771
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800772void FontState::deinit(Context *rsc) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700773 mInitialized = false;
774
Stephen Hines01b7d292010-09-28 15:45:45 -0700775 mFontShaderFConstant.clear();
776
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700777 mIndexBuffer.clear();
778 mVertexArray.clear();
779
780 mFontShaderF.clear();
781 mFontSampler.clear();
782 mFontProgramStore.clear();
783
784 mTextTexture.clear();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800785 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700786 delete mCacheLines[i];
787 }
788 mCacheLines.clear();
789
790 mDefault.clear();
791
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700792 Vector<Font*> fontsToDereference = mActiveFonts;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800793 for (uint32_t i = 0; i < fontsToDereference.size(); i ++) {
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700794 fontsToDereference[i]->zeroUserRef();
795 }
796
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800797 if (mLibrary) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700798 FT_Done_FreeType( mLibrary );
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700799 mLibrary = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700800 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700801}
802
803namespace android {
804namespace renderscript {
805
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -0800806RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, float fontSize, uint32_t dpi) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700807 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800808 if (newFont) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700809 newFont->incUserRef();
810 }
811 return newFont;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700812}
813
814} // renderscript
815} // android