blob: 96e350da2f6697a129e67e27e7c1e7bc5d2aabe6 [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 Sakhartchouked9f2102010-11-09 17:00:54 -080043bool Font::init(const char *name, uint32_t fontSize, uint32_t dpi) {
44 if (mInitialized) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk071508d2010-06-30 12:49:27 -070054 FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), fullPath.string(), 0, &mFace);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080055 if (error) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -070064 error = FT_Set_Char_Size(mFace, fontSize * 64, 0, dpi, 0);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080065 if (error) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -070071
72 mInitialized = true;
73 return true;
74}
75
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080076void Font::invalidateTextureCache() {
77 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070078 mCachedGlyphs.valueAt(i)->mIsValid = false;
79 }
80}
81
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080082void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070083 FontState *state = &mRSC->mStateFont;
84
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070085 int32_t nPenX = x + glyph->mBitmapLeft;
86 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070087
Alex Sakhartchouk10825a02010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -070092
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070093 int32_t width = (int32_t) glyph->mBitmapWidth;
94 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070095
Alex Sakhartchouk10825a02010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700100}
101
Alex Sakhartchouk10825a02010-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 Sakhartchouk10825a02010-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 Sakhartchouked9f2102010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700154 return;
155 }
156
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800157 if (mode == Font::MEASURE) {
Alex Sakhartchouk10825a02010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800168 if (numGlyphs > 0) {
Alex Sakhartchouk9b949fc2010-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 Root300ba682010-11-09 14:37:23 -0800177 int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700178
179 // Reached the end of the string or encountered
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800180 if (utfChar < 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700181 break;
182 }
183
184 // Move to the next character in the array
185 index = nextIndex;
186
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700187 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800190 if (cachedGlyph->mIsValid) {
191 switch (mode) {
Alex Sakhartchouk10825a02010-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 Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800207 if (numGlyphs > 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700208 glyphsLeft --;
209 }
210 }
211}
212
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700213Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
214
215 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800216 if (cachedGlyph == NULL) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700217 cachedGlyph = cacheGlyph((uint32_t)utfChar);
218 }
219 // Is the glyph still in texture cache?
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800220 if (!cachedGlyph->mIsValid) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700221 updateGlyphCache(cachedGlyph);
222 }
223
224 return cachedGlyph;
225}
226
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800227void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700228 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800229 if (error) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700230 LOGE("Couldn't load glyph.");
231 return;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700232 }
233
Alex Sakhartchouk071508d2010-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 Sakhartchouk9b949fc2010-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 Sakhartchouk071508d2010-06-30 12:49:27 -0700246 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700247
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800248 if (!glyph->mIsValid) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700249 return;
250 }
251
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700252 uint32_t endX = startX + bitmap->width;
253 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700254
255 glyph->mBitmapMinX = startX;
256 glyph->mBitmapMinY = startY;
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700257 glyph->mBitmapWidth = bitmap->width;
258 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800269Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700275
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700276 updateGlyphCache(newGlyph);
277
278 return newGlyph;
279}
280
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800281Font * Font::create(Context *rsc, const char *name, uint32_t fontSize, uint32_t dpi) {
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700282 rsc->mStateFont.checkInit();
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700283 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
284
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800285 for (uint32_t i = 0; i < activeFonts.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700286 Font *ithFont = activeFonts[i];
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800287 if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800294 if (isInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700295 activeFonts.push(newFont);
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700296 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700297 return newFont;
298 }
299
Jason Samsb38d5342010-10-21 14:06:55 -0700300 ObjectBase::checkDelete(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700301 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700302}
303
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800304Font::~Font() {
305 if (mFace) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800316 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700317 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700318 delete glyph;
319 }
320}
321
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800322FontState::FontState() {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700323 mInitialized = false;
324 mMaxNumberOfQuads = 1024;
325 mCurrentQuadIndex = 0;
326 mRSC = NULL;
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700327 mLibrary = NULL;
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk10825a02010-10-05 11:33:27 -0700342 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk10825a02010-10-05 11:33:27 -0700353 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk960ae152010-10-12 14:15:17 -0700366
367 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700368}
369
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800370FontState::~FontState() {
371 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700372 delete mCacheLines[i];
373 }
374
375 rsAssert(!mActiveFonts.size());
376}
377
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800378FT_Library FontState::getLib() {
379 if (!mLibrary) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700380 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800381 if (error) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700382 LOGE("Unable to initialize freetype");
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700383 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700384 }
385 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700386
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700387 return mLibrary;
388}
389
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800390void FontState::init(Context *rsc) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700391 mRSC = rsc;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700392}
393
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800394void FontState::flushAllAndInvalidate() {
395 if (mCurrentQuadIndex != 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700396 issueDrawCommand();
397 mCurrentQuadIndex = 0;
398 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800399 for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700400 mActiveFonts[i]->invalidateTextureCache();
401 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800402 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700403 mCacheLines[i]->mCurrentCol = 0;
404 }
405}
406
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800407bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700408 // If the glyph is too tall, don't cache it
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800409 if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800419 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700420 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800421 if (bitmapFit) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800427 if (!bitmapFit) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700428 flushAllAndInvalidate();
429
430 // Try to fit it again
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800431 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700432 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800433 if (bitmapFit) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800439 if (!bitmapFit) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700451 uint32_t cacheWidth = getCacheTextureType()->getDimX();
452
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700453 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
454 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700455
456 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
Alex Sakhartchouked9f2102010-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 Sakhartchouk10825a02010-10-05 11:33:27 -0700459 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchouk9b949fc2010-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
466 mTextTexture->deferedUploadToTexture(mRSC, false, 0);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700467 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700468
469 // Some debug code
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800470 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800480void FontState::initRenderState() {
Alex Sakhartchoukd2091632010-10-06 11:15:01 -0700481 String8 shaderString("varying vec2 varTex0;\n");
Alex Sakhartchoukc984dd72010-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 Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700485 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchoukc984dd72010-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 Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700490 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700491 mRSC->mStateElement.elementBuilderBegin();
492 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700493 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700494 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
495
Jason Sams31a7e422010-10-26 13:09:17 -0700496 Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700497
498 uint32_t tmp[4];
499 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
500 tmp[1] = (uint32_t)inputType;
501 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_COUNT;
502 tmp[3] = 1;
503
504 mFontShaderFConstant.set(new Allocation(mRSC, inputType));
505 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
506 shaderString.length(), tmp, 4);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700507 mFontShaderF.set(pf);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700508 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700509
510 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
511 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
512 mFontSampler.set(sampler);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700513 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700514
515 ProgramStore *fontStore = new ProgramStore(mRSC);
516 mFontProgramStore.set(fontStore);
517 mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
518 mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
519 mFontProgramStore->setDitherEnable(false);
520 mFontProgramStore->setDepthMask(false);
521}
522
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800523void FontState::initTextTexture() {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700524 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
525
526 // We will allocate a texture to initially hold 32 character bitmaps
Jason Sams31a7e422010-10-26 13:09:17 -0700527 Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700528
529 Allocation *cacheAlloc = new Allocation(mRSC, texType);
530 mTextTexture.set(cacheAlloc);
531 mTextTexture->deferedUploadToTexture(mRSC, false, 0);
532
533 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700534 int32_t nextLine = 0;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700535 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
536 nextLine += mCacheLines.top()->mMaxHeight;
537 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
538 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700539 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
540 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700541 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
542 nextLine += mCacheLines.top()->mMaxHeight;
543 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
544 nextLine += mCacheLines.top()->mMaxHeight;
545 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
546 nextLine += mCacheLines.top()->mMaxHeight;
547 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
548}
549
550// Avoid having to reallocate memory and render quad by quad
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800551void FontState::initVertexArrayBuffers() {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700552 // Now lets write index data
553 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700554 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Jason Sams31a7e422010-10-26 13:09:17 -0700555 Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700556
557 Allocation *indexAlloc = new Allocation(mRSC, indexType);
558 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
559
560 // Four verts, two triangles , six indices per quad
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800561 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700562 int32_t i6 = i * 6;
563 int32_t i4 = i * 4;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700564
565 indexPtr[i6 + 0] = i4 + 0;
566 indexPtr[i6 + 1] = i4 + 1;
567 indexPtr[i6 + 2] = i4 + 2;
568
569 indexPtr[i6 + 3] = i4 + 0;
570 indexPtr[i6 + 4] = i4 + 2;
571 indexPtr[i6 + 5] = i4 + 3;
572 }
573
574 indexAlloc->deferedUploadToBufferObject(mRSC);
575 mIndexBuffer.set(indexAlloc);
576
577 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
578 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
579
Alex Sakhartchouk98bfe5d2010-10-18 17:18:50 -0700580 mRSC->mStateElement.elementBuilderBegin();
581 mRSC->mStateElement.elementBuilderAdd(posElem, "position", 1);
582 mRSC->mStateElement.elementBuilderAdd(texElem, "texture0", 1);
583 const Element *vertexDataElem = mRSC->mStateElement.elementBuilderCreate(mRSC);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700584
Jason Sams31a7e422010-10-26 13:09:17 -0700585 Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
586 mMaxNumberOfQuads * 4,
587 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700588
589 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType);
590 mTextMeshPtr = (float*)vertexAlloc->getPtr();
591
592 mVertexArray.set(vertexAlloc);
593}
594
595// We don't want to allocate anything unless we actually draw text
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800596void FontState::checkInit() {
597 if (mInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700598 return;
599 }
600
601 initTextTexture();
602 initRenderState();
603
604 initVertexArrayBuffers();
605
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700606 // We store a string with letters in a rough frequency of occurrence
607 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
608 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
609 mLatinPrecache += String8(",.?!()-+@;:`'");
610 mLatinPrecache += String8("0123456789");
611
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700612 mInitialized = true;
613}
614
615void FontState::issueDrawCommand() {
616
617 ObjectBaseRef<const ProgramVertex> tmpV(mRSC->getVertex());
618 mRSC->setVertex(mRSC->getDefaultProgramVertex());
619
Alex Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700620 ObjectBaseRef<const ProgramRaster> tmpR(mRSC->getRaster());
621 mRSC->setRaster(mRSC->getDefaultProgramRaster());
622
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700623 ObjectBaseRef<const ProgramFragment> tmpF(mRSC->getFragment());
624 mRSC->setFragment(mFontShaderF.get());
625
626 ObjectBaseRef<const ProgramStore> tmpPS(mRSC->getFragmentStore());
627 mRSC->setFragmentStore(mFontProgramStore.get());
628
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800629 if (mConstantsDirty) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700630 mFontShaderFConstant->data(mRSC, &mConstants, sizeof(mConstants));
631 mConstantsDirty = false;
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700632 }
633
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700634 if (!mRSC->setupCheck()) {
635 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700636 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700637 mRSC->setFragment((ProgramFragment *)tmpF.get());
638 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
639 return;
640 }
641
642 float *vtx = (float*)mVertexArray->getPtr();
643 float *tex = vtx + 3;
644
Alex Sakhartchouk9d71e212010-11-08 15:10:52 -0800645 VertexArray::Attrib attribs[2];
646 attribs[0].set(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
647 attribs[1].set(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
648 VertexArray va(attribs, 2);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700649 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
650
651 mIndexBuffer->uploadCheck(mRSC);
652 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
653 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
654
655 // Reset the state
656 mRSC->setVertex((ProgramVertex *)tmpV.get());
Alex Sakhartchouk80a4c2c2010-07-12 15:50:32 -0700657 mRSC->setRaster((ProgramRaster *)tmpR.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700658 mRSC->setFragment((ProgramFragment *)tmpF.get());
659 mRSC->setFragmentStore((ProgramStore *)tmpPS.get());
660}
661
662void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800663 float u1, float v1,
664 float x2, float y2, float z2,
665 float u2, float v2,
666 float x3, float y3, float z3,
667 float u3, float v3,
668 float x4, float y4, float z4,
669 float u4, float v4) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700670 const uint32_t vertsPerQuad = 4;
671 const uint32_t floatsPerVert = 5;
672 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
673
674 // Cull things that are off the screen
675 float width = (float)mRSC->getWidth();
676 float height = (float)mRSC->getHeight();
677
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800678 if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700679 return;
680 }
681
682 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
683 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
684 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
685 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
686
687 (*currentPos++) = x1;
688 (*currentPos++) = y1;
689 (*currentPos++) = z1;
690 (*currentPos++) = u1;
691 (*currentPos++) = v1;
692
693 (*currentPos++) = x2;
694 (*currentPos++) = y2;
695 (*currentPos++) = z2;
696 (*currentPos++) = u2;
697 (*currentPos++) = v2;
698
699 (*currentPos++) = x3;
700 (*currentPos++) = y3;
701 (*currentPos++) = z3;
702 (*currentPos++) = u3;
703 (*currentPos++) = v3;
704
705 (*currentPos++) = x4;
706 (*currentPos++) = y4;
707 (*currentPos++) = z4;
708 (*currentPos++) = u4;
709 (*currentPos++) = v4;
710
711 mCurrentQuadIndex ++;
712
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800713 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700714 issueDrawCommand();
715 mCurrentQuadIndex = 0;
716 }
717}
718
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700719uint32_t FontState::getRemainingCacheCapacity() {
720 uint32_t remainingCapacity = 0;
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700721 uint32_t totalPixels = 0;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800722 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700723 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
724 totalPixels += mCacheLines[i]->mMaxWidth;
725 }
726 remainingCapacity = (remainingCapacity * 100) / totalPixels;
727 return remainingCapacity;
728}
729
730void FontState::precacheLatin(Font *font) {
731 // Remaining capacity is measured in %
732 uint32_t remainingCapacity = getRemainingCacheCapacity();
733 uint32_t precacheIdx = 0;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800734 while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700735 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
736 remainingCapacity = getRemainingCacheCapacity();
737 precacheIdx ++;
738 }
739}
740
741
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700742void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
743 uint32_t startIndex, int32_t numGlyphs,
744 Font::RenderMode mode,
745 Font::Rect *bounds,
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800746 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700747 checkInit();
748
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700749 // Render code here
750 Font *currentFont = mRSC->getFont();
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800751 if (!currentFont) {
752 if (!mDefault.get()) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700753 mDefault.set(Font::create(mRSC, "DroidSans.ttf", 16, 96));
754 }
755 currentFont = mDefault.get();
756 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800757 if (!currentFont) {
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700758 LOGE("Unable to initialize any fonts");
759 return;
760 }
761
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700762 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
763 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700764
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800765 if (mCurrentQuadIndex != 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700766 issueDrawCommand();
767 mCurrentQuadIndex = 0;
768 }
769}
770
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700771void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
772 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700773}
774
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700775void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700776 mConstants.mFontColor[0] = r;
777 mConstants.mFontColor[1] = g;
778 mConstants.mFontColor[2] = b;
779 mConstants.mFontColor[3] = a;
780
781 mConstants.mGamma = 1.0f;
Alex Sakhartchouk76322af2010-10-05 13:23:55 -0700782 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700783 if (luminance <= mBlackThreshold) {
784 mConstants.mGamma = mBlackGamma;
785 } else if (luminance >= mWhiteThreshold) {
786 mConstants.mGamma = mWhiteGamma;
787 }
Alex Sakhartchouk960ae152010-10-12 14:15:17 -0700788
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700789 mConstantsDirty = true;
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700790}
791
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700792void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700793 *r = mConstants.mFontColor[0];
794 *g = mConstants.mFontColor[1];
795 *b = mConstants.mFontColor[2];
796 *a = mConstants.mFontColor[3];
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700797}
798
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800799void FontState::deinit(Context *rsc) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700800 mInitialized = false;
801
Stephen Hines01f0ad72010-09-28 15:45:45 -0700802 mFontShaderFConstant.clear();
803
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700804 mIndexBuffer.clear();
805 mVertexArray.clear();
806
807 mFontShaderF.clear();
808 mFontSampler.clear();
809 mFontProgramStore.clear();
810
811 mTextTexture.clear();
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800812 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700813 delete mCacheLines[i];
814 }
815 mCacheLines.clear();
816
817 mDefault.clear();
818
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700819 Vector<Font*> fontsToDereference = mActiveFonts;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800820 for (uint32_t i = 0; i < fontsToDereference.size(); i ++) {
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700821 fontsToDereference[i]->zeroUserRef();
822 }
823
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800824 if (mLibrary) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700825 FT_Done_FreeType( mLibrary );
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700826 mLibrary = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700827 }
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700828}
829
830namespace android {
831namespace renderscript {
832
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800833RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, uint32_t fontSize, uint32_t dpi) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700834 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800835 if (newFont) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700836 newFont->incUserRef();
837 }
838 return newFont;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700839}
840
841} // renderscript
842} // android