blob: 80bca4391f443f712592d3a518a50f68541040e5 [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 Sakhartchouke27cdee2010-12-17 11:41:08 -080043bool Font::init(const char *name, float fontSize, uint32_t dpi) {
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 Sakhartchouke27cdee2010-12-17 11:41:08 -080049 FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080050 if (error) {
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080051 LOGE("Unable to initialize font %s", name);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070052 return false;
53 }
54
55 mFontName = name;
56 mFontSize = fontSize;
57 mDpi = dpi;
58
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080059 error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080060 if (error) {
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080061 LOGE("Unable to set font size on %s", name);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070062 return false;
63 }
64
65 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070066
67 mInitialized = true;
68 return true;
69}
70
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080071void Font::invalidateTextureCache() {
72 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070073 mCachedGlyphs.valueAt(i)->mIsValid = false;
74 }
75}
76
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080077void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070078 FontState *state = &mRSC->mStateFont;
79
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070080 int32_t nPenX = x + glyph->mBitmapLeft;
81 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070082
Alex Sakhartchouk10825a02010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -070087
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070088 int32_t width = (int32_t) glyph->mBitmapWidth;
89 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070090
Alex Sakhartchouk10825a02010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -070095}
96
Alex Sakhartchouk10825a02010-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 Sakhartchouk10825a02010-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 Sakhartchouked9f2102010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700149 return;
150 }
151
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800152 if (mode == Font::MEASURE) {
Alex Sakhartchouk10825a02010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800163 if (numGlyphs > 0) {
Alex Sakhartchouk9b949fc2010-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 Root300ba682010-11-09 14:37:23 -0800172 int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700173
174 // Reached the end of the string or encountered
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800175 if (utfChar < 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700176 break;
177 }
178
179 // Move to the next character in the array
180 index = nextIndex;
181
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700182 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800185 if (cachedGlyph->mIsValid) {
186 switch (mode) {
Alex Sakhartchouk10825a02010-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 Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800202 if (numGlyphs > 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700203 glyphsLeft --;
204 }
205 }
206}
207
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700208Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
209
210 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800211 if (cachedGlyph == NULL) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700212 cachedGlyph = cacheGlyph((uint32_t)utfChar);
213 }
214 // Is the glyph still in texture cache?
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800215 if (!cachedGlyph->mIsValid) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700216 updateGlyphCache(cachedGlyph);
217 }
218
219 return cachedGlyph;
220}
221
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800222void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700223 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800224 if (error) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700225 LOGE("Couldn't load glyph.");
226 return;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700227 }
228
Alex Sakhartchouk071508d2010-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 Sakhartchouk9b949fc2010-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 Sakhartchouk071508d2010-06-30 12:49:27 -0700241 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700242
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800243 if (!glyph->mIsValid) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700244 return;
245 }
246
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700247 uint32_t endX = startX + bitmap->width;
248 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700249
250 glyph->mBitmapMinX = startX;
251 glyph->mBitmapMinY = startY;
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700252 glyph->mBitmapWidth = bitmap->width;
253 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800264Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700270
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700271 updateGlyphCache(newGlyph);
272
273 return newGlyph;
274}
275
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -0800276Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi) {
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700277 rsc->mStateFont.checkInit();
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700278 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
279
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800280 for (uint32_t i = 0; i < activeFonts.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700281 Font *ithFont = activeFonts[i];
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800282 if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800289 if (isInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700290 activeFonts.push(newFont);
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700291 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700292 return newFont;
293 }
294
Jason Samsb38d5342010-10-21 14:06:55 -0700295 ObjectBase::checkDelete(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700296 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700297}
298
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800299Font::~Font() {
300 if (mFace) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800311 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700312 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700313 delete glyph;
314 }
315}
316
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800317FontState::FontState() {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700318 mInitialized = false;
319 mMaxNumberOfQuads = 1024;
320 mCurrentQuadIndex = 0;
321 mRSC = NULL;
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700322 mLibrary = NULL;
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700330 gamma = atof(property);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700331 }
332
333 // Get the black gamma threshold
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700334 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700335 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700336 blackThreshold = atoi(property);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700337 }
338 mBlackThreshold = (float)(blackThreshold) / 255.0f;
339
340 // Get the white gamma threshold
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700341 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700342 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700343 whiteThreshold = atoi(property);
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk960ae152010-10-12 14:15:17 -0700350
351 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700352}
353
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800354FontState::~FontState() {
355 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700356 delete mCacheLines[i];
357 }
358
359 rsAssert(!mActiveFonts.size());
360}
361
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800362FT_Library FontState::getLib() {
363 if (!mLibrary) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700364 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800365 if (error) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700366 LOGE("Unable to initialize freetype");
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700367 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700368 }
369 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700370
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700371 return mLibrary;
372}
373
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800374void FontState::init(Context *rsc) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700375 mRSC = rsc;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700376}
377
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800378void FontState::flushAllAndInvalidate() {
379 if (mCurrentQuadIndex != 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700380 issueDrawCommand();
381 mCurrentQuadIndex = 0;
382 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800383 for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700384 mActiveFonts[i]->invalidateTextureCache();
385 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800386 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700387 mCacheLines[i]->mCurrentCol = 0;
388 }
389}
390
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800391bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700392 // If the glyph is too tall, don't cache it
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800393 if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800403 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700404 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800405 if (bitmapFit) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800411 if (!bitmapFit) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700412 flushAllAndInvalidate();
413
414 // Try to fit it again
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800415 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700416 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800417 if (bitmapFit) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800423 if (!bitmapFit) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700435 uint32_t cacheWidth = getCacheTextureType()->getDimX();
436
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700437 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
438 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700439
440 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
Alex Sakhartchouked9f2102010-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 Sakhartchouk10825a02010-10-05 11:33:27 -0700443 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchouk9b949fc2010-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 Sams6d8eb262010-12-15 01:41:00 -0800450 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700451 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700452
453 // Some debug code
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800454 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800464void FontState::initRenderState() {
Alex Sakhartchoukd2091632010-10-06 11:15:01 -0700465 String8 shaderString("varying vec2 varTex0;\n");
Alex Sakhartchoukc984dd72010-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 Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700469 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchoukc984dd72010-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 Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700474 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700475 mRSC->mStateElement.elementBuilderBegin();
476 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700477 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700478 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
479
Jason Sams31a7e422010-10-26 13:09:17 -0700480 Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
Alex Sakhartchoukc984dd72010-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 Sakhartchouk67f2e442010-11-18 15:22:43 -0800485 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
486 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700487
Jason Sams5476b452010-12-08 16:14:36 -0800488 mFontShaderFConstant.set(new Allocation(mRSC, inputType,
489 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700490 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
491 shaderString.length(), tmp, 4);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700492 mFontShaderF.set(pf);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700493 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchouk9b949fc2010-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 Sakhartchoukb89aaac2010-09-23 16:16:33 -0700498 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800508void FontState::initTextTexture() {
Alex Sakhartchouk9b949fc2010-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 Sams31a7e422010-10-26 13:09:17 -0700512 Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700513
Jason Sams5476b452010-12-08 16:14:36 -0800514 Allocation *cacheAlloc = new Allocation(mRSC, texType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700515 mTextTexture.set(cacheAlloc);
Jason Sams6d8eb262010-12-15 01:41:00 -0800516 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700517
518 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700519 int32_t nextLine = 0;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk94bbccc2010-08-17 11:09:49 -0700524 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
525 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800536void FontState::initVertexArrayBuffers() {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700539 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Jason Sams31a7e422010-10-26 13:09:17 -0700540 Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700541
Jason Sams5476b452010-12-08 16:14:36 -0800542 Allocation *indexAlloc = new Allocation(mRSC, indexType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700543 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
544
545 // Four verts, two triangles , six indices per quad
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800546 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700547 int32_t i6 = i * 6;
548 int32_t i4 = i * 4;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk98bfe5d2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700569
Jason Sams31a7e422010-10-26 13:09:17 -0700570 Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
571 mMaxNumberOfQuads * 4,
572 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700573
Jason Sams5476b452010-12-08 16:14:36 -0800574 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800581void FontState::checkInit() {
582 if (mInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700583 return;
584 }
585
586 initTextTexture();
587 initRenderState();
588
589 initVertexArrayBuffers();
590
Alex Sakhartchouk27f50522010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700597 mInitialized = true;
598}
599
600void FontState::issueDrawCommand() {
Jason Samsa17af042010-11-17 15:29:32 -0800601 Context::PushState ps(mRSC);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700602
Jason Samsa17af042010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700607
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800608 if (mConstantsDirty) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700609 mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants));
610 mConstantsDirty = false;
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700611 }
612
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700613 if (!mRSC->setupCheck()) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700614 return;
615 }
616
617 float *vtx = (float*)mVertexArray->getPtr();
618 float *tex = vtx + 3;
619
Alex Sakhartchouk9d71e212010-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 Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700629}
630
631void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchouked9f2102010-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 Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800647 if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800682 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700683 issueDrawCommand();
684 mCurrentQuadIndex = 0;
685 }
686}
687
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700688uint32_t FontState::getRemainingCacheCapacity() {
689 uint32_t remainingCapacity = 0;
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700690 uint32_t totalPixels = 0;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800691 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk94bbccc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800703 while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700704 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
705 remainingCapacity = getRemainingCacheCapacity();
706 precacheIdx ++;
707 }
708}
709
710
Alex Sakhartchouk10825a02010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800715 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700716 checkInit();
717
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700718 // Render code here
719 Font *currentFont = mRSC->getFont();
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800720 if (!currentFont) {
721 if (!mDefault.get()) {
Alex Sakhartchouke27cdee2010-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 Sakhartchouk071508d2010-06-30 12:49:27 -0700727 }
728 currentFont = mDefault.get();
729 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800730 if (!currentFont) {
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700731 LOGE("Unable to initialize any fonts");
732 return;
733 }
734
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700735 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
736 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700737
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800738 if (mCurrentQuadIndex != 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700739 issueDrawCommand();
740 mCurrentQuadIndex = 0;
741 }
742}
743
Alex Sakhartchouk10825a02010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700746}
747
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700748void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk76322af2010-10-05 13:23:55 -0700755 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700756 if (luminance <= mBlackThreshold) {
757 mConstants.mGamma = mBlackGamma;
758 } else if (luminance >= mWhiteThreshold) {
759 mConstants.mGamma = mWhiteGamma;
760 }
Alex Sakhartchouk960ae152010-10-12 14:15:17 -0700761
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700762 mConstantsDirty = true;
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700763}
764
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700765void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk55e81982010-08-05 11:24:14 -0700770}
771
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800772void FontState::deinit(Context *rsc) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700773 mInitialized = false;
774
Stephen Hines01f0ad72010-09-28 15:45:45 -0700775 mFontShaderFConstant.clear();
776
Alex Sakhartchouk071508d2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800785 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700786 delete mCacheLines[i];
787 }
788 mCacheLines.clear();
789
790 mDefault.clear();
791
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700792 Vector<Font*> fontsToDereference = mActiveFonts;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800793 for (uint32_t i = 0; i < fontsToDereference.size(); i ++) {
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700794 fontsToDereference[i]->zeroUserRef();
795 }
796
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800797 if (mLibrary) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700798 FT_Done_FreeType( mLibrary );
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700799 mLibrary = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700800 }
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700801}
802
803namespace android {
804namespace renderscript {
805
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -0800806RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, float fontSize, uint32_t dpi) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700807 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800808 if (newFont) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700809 newFont->incUserRef();
810 }
811 return newFont;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700812}
813
814} // renderscript
815} // android