blob: 8571c32e95ec3da805ec5976f8bd9889fe31c8df [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 Sakhartchouk5224a272011-01-07 11:12:08 -080043bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
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 Sakhartchouk5224a272011-01-07 11:12:08 -080049 FT_Error error = 0;
50 if (data != NULL && dataLen > 0) {
51 error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
52 } else {
53 error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
54 }
55
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080056 if (error) {
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -080057 LOGE("Unable to initialize font %s", name);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070058 return false;
59 }
60
61 mFontName = name;
62 mFontSize = fontSize;
63 mDpi = dpi;
64
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -080065 error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080066 if (error) {
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -080067 LOGE("Unable to set font size on %s", name);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070068 return false;
69 }
70
71 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070072
73 mInitialized = true;
74 return true;
75}
76
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080077void Font::invalidateTextureCache() {
78 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070079 mCachedGlyphs.valueAt(i)->mIsValid = false;
80 }
81}
82
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080083void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070084 FontState *state = &mRSC->mStateFont;
85
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070086 int32_t nPenX = x + glyph->mBitmapLeft;
87 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070088
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070089 float u1 = glyph->mBitmapMinU;
90 float u2 = glyph->mBitmapMaxU;
91 float v1 = glyph->mBitmapMinV;
92 float v2 = glyph->mBitmapMaxV;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070093
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070094 int32_t width = (int32_t) glyph->mBitmapWidth;
95 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070096
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070097 state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
98 nPenX + width, nPenY, 0, u2, v2,
99 nPenX + width, nPenY - height, 0, u2, v1,
100 nPenX, nPenY - height, 0, u1, v1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700101}
102
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700103void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
104 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
105 int32_t nPenX = x + glyph->mBitmapLeft;
106 int32_t nPenY = y + glyph->mBitmapTop;
107
108 uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
109 uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
110
111 FontState *state = &mRSC->mStateFont;
112 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
113 const uint8_t* cacheBuffer = state->getTextTextureData();
114
115 uint32_t cacheX = 0, cacheY = 0;
116 int32_t bX = 0, bY = 0;
117 for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
118 for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
119 if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
120 LOGE("Skipping invalid index");
121 continue;
122 }
123 uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
124 bitmap[bY * bitmapW + bX] = tempCol;
125 }
126 }
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700127}
128
129void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
130 int32_t nPenX = x + glyph->mBitmapLeft;
131 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
132
133 int32_t width = (int32_t) glyph->mBitmapWidth;
134 int32_t height = (int32_t) glyph->mBitmapHeight;
135
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800136 // 0, 0 is top left, so bottom is a positive number
137 if (bounds->bottom < nPenY) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700138 bounds->bottom = nPenY;
139 }
140 if (bounds->left > nPenX) {
141 bounds->left = nPenX;
142 }
143 if (bounds->right < nPenX + width) {
144 bounds->right = nPenX + width;
145 }
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800146 if (bounds->top > nPenY - height) {
147 bounds->top = nPenY - height;
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700148 }
149}
150
151void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
152 uint32_t start, int32_t numGlyphs,
153 RenderMode mode, Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800154 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
155 if (!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700156 return;
157 }
158
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800159 if (mode == Font::MEASURE) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700160 if (bounds == NULL) {
161 LOGE("No return rectangle provided to measure text");
162 return;
163 }
164 // Reset min and max of the bounding box to something large
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800165 bounds->set(1e6, -1e6, 1e6, -1e6);
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700166 }
167
168 int32_t penX = x, penY = y;
169 int32_t glyphsLeft = 1;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800170 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700171 glyphsLeft = numGlyphs;
172 }
173
174 size_t index = start;
175 size_t nextIndex = 0;
176
177 while (glyphsLeft > 0) {
178
Kenny Rootc9c38dd2010-11-09 14:37:23 -0800179 int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700180
181 // Reached the end of the string or encountered
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800182 if (utfChar < 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700183 break;
184 }
185
186 // Move to the next character in the array
187 index = nextIndex;
188
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700189 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700190
191 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800192 if (cachedGlyph->mIsValid) {
193 switch (mode) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700194 case FRAMEBUFFER:
195 drawCachedGlyph(cachedGlyph, penX, penY);
196 break;
197 case BITMAP:
198 drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
199 break;
200 case MEASURE:
201 measureCachedGlyph(cachedGlyph, penX, penY, bounds);
202 break;
203 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700204 }
205
206 penX += (cachedGlyph->mAdvance.x >> 6);
207
208 // If we were given a specific number of glyphs, decrement
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800209 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700210 glyphsLeft --;
211 }
212 }
213}
214
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700215Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
216
217 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800218 if (cachedGlyph == NULL) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700219 cachedGlyph = cacheGlyph((uint32_t)utfChar);
220 }
221 // Is the glyph still in texture cache?
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800222 if (!cachedGlyph->mIsValid) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700223 updateGlyphCache(cachedGlyph);
224 }
225
226 return cachedGlyph;
227}
228
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800229void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700230 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800231 if (error) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700232 LOGE("Couldn't load glyph.");
233 return;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700234 }
235
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700236 glyph->mAdvance = mFace->glyph->advance;
237 glyph->mBitmapLeft = mFace->glyph->bitmap_left;
238 glyph->mBitmapTop = mFace->glyph->bitmap_top;
239
240 FT_Bitmap *bitmap = &mFace->glyph->bitmap;
241
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700242 // Now copy the bitmap into the cache texture
243 uint32_t startX = 0;
244 uint32_t startY = 0;
245
246 // Let the font state figure out where to put the bitmap
247 FontState *state = &mRSC->mStateFont;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700248 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700249
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800250 if (!glyph->mIsValid) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700251 return;
252 }
253
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700254 uint32_t endX = startX + bitmap->width;
255 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700256
257 glyph->mBitmapMinX = startX;
258 glyph->mBitmapMinY = startY;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700259 glyph->mBitmapWidth = bitmap->width;
260 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700261
262 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
263 uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
264
265 glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
266 glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
267 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
268 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
269}
270
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800271Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700272 CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
273 mCachedGlyphs.add(glyph, newGlyph);
274
275 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
276 newGlyph->mIsValid = false;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700277
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700278 updateGlyphCache(newGlyph);
279
280 return newGlyph;
281}
282
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800283Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
284 const void *data, uint32_t dataLen) {
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700285 rsc->mStateFont.checkInit();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700286 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
287
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800288 for (uint32_t i = 0; i < activeFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700289 Font *ithFont = activeFonts[i];
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800290 if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700291 return ithFont;
292 }
293 }
294
295 Font *newFont = new Font(rsc);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800296 bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800297 if (isInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700298 activeFonts.push(newFont);
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700299 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700300 return newFont;
301 }
302
Jason Sams225afd32010-10-21 14:06:55 -0700303 ObjectBase::checkDelete(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700304 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700305}
306
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800307Font::~Font() {
308 if (mFace) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700309 FT_Done_Face(mFace);
310 }
311
312 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
313 if (mRSC->mStateFont.mActiveFonts[ct] == this) {
314 mRSC->mStateFont.mActiveFonts.removeAt(ct);
315 break;
316 }
317 }
318
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800319 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700320 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700321 delete glyph;
322 }
323}
324
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800325FontState::FontState() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700326 mInitialized = false;
327 mMaxNumberOfQuads = 1024;
328 mCurrentQuadIndex = 0;
329 mRSC = NULL;
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700330 mLibrary = NULL;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700331
332 // Get the renderer properties
333 char property[PROPERTY_VALUE_MAX];
334
335 // Get the gamma
336 float gamma = DEFAULT_TEXT_GAMMA;
337 if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700338 gamma = atof(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700339 }
340
341 // Get the black gamma threshold
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700342 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700343 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700344 blackThreshold = atoi(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700345 }
346 mBlackThreshold = (float)(blackThreshold) / 255.0f;
347
348 // Get the white gamma threshold
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700349 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700350 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700351 whiteThreshold = atoi(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700352 }
353 mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
354
355 // Compute the gamma tables
356 mBlackGamma = gamma;
357 mWhiteGamma = 1.0f / gamma;
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700358
359 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700360}
361
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800362FontState::~FontState() {
363 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700364 delete mCacheLines[i];
365 }
366
367 rsAssert(!mActiveFonts.size());
368}
369
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800370FT_Library FontState::getLib() {
371 if (!mLibrary) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700372 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800373 if (error) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700374 LOGE("Unable to initialize freetype");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700375 return NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700376 }
377 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700378
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700379 return mLibrary;
380}
381
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800382void FontState::init(Context *rsc) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700383 mRSC = rsc;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700384}
385
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800386void FontState::flushAllAndInvalidate() {
387 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700388 issueDrawCommand();
389 mCurrentQuadIndex = 0;
390 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800391 for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700392 mActiveFonts[i]->invalidateTextureCache();
393 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800394 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700395 mCacheLines[i]->mCurrentCol = 0;
396 }
397}
398
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800399bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700400 // If the glyph is too tall, don't cache it
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800401 if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700402 LOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
403 return false;
404 }
405
406 // Now copy the bitmap into the cache texture
407 uint32_t startX = 0;
408 uint32_t startY = 0;
409
410 bool bitmapFit = false;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800411 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700412 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800413 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700414 break;
415 }
416 }
417
418 // If the new glyph didn't fit, flush the state so far and invalidate everything
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800419 if (!bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700420 flushAllAndInvalidate();
421
422 // Try to fit it again
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800423 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700424 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800425 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700426 break;
427 }
428 }
429
430 // if we still don't fit, something is wrong and we shouldn't draw
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800431 if (!bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700432 LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
433 return false;
434 }
435 }
436
437 *retOriginX = startX;
438 *retOriginY = startY;
439
440 uint32_t endX = startX + bitmap->width;
441 uint32_t endY = startY + bitmap->rows;
442
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700443 uint32_t cacheWidth = getCacheTextureType()->getDimX();
444
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700445 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
446 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700447
448 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800449 for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
450 for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700451 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700452 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
453 }
454 }
455
456 // This will dirty the texture and the shader so next time
457 // we draw it will upload the data
Jason Samsb7e83bd2010-12-15 01:41:00 -0800458 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700459 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700460
461 // Some debug code
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800462 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700463 LOGE("Cache Line: H: %u Empty Space: %f",
464 mCacheLines[i]->mMaxHeight,
465 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
466
467 }*/
468
469 return true;
470}
471
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800472void FontState::initRenderState() {
Alex Sakhartchouk7ffcaf22010-10-06 11:15:01 -0700473 String8 shaderString("varying vec2 varTex0;\n");
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700474 shaderString.append("void main() {\n");
475 shaderString.append(" lowp vec4 col = UNI_Color;\n");
476 shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700477 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700478 shaderString.append(" gl_FragColor = col;\n");
479 shaderString.append("}\n");
480
481 const Element *colorElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700482 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700483 mRSC->mStateElement.elementBuilderBegin();
484 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700485 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700486 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
487
Jason Samsf0c1df42010-10-26 13:09:17 -0700488 Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700489
490 uint32_t tmp[4];
491 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
492 tmp[1] = (uint32_t)inputType;
Alex Sakhartchouk84e40272010-11-18 15:22:43 -0800493 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
494 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700495
Jason Sams366c9c82010-12-08 16:14:36 -0800496 mFontShaderFConstant.set(new Allocation(mRSC, inputType,
497 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700498 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
499 shaderString.length(), tmp, 4);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700500 mFontShaderF.set(pf);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700501 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700502
503 Sampler *sampler = new Sampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
504 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP);
505 mFontSampler.set(sampler);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700506 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700507
508 ProgramStore *fontStore = new ProgramStore(mRSC);
509 mFontProgramStore.set(fontStore);
510 mFontProgramStore->setDepthFunc(RS_DEPTH_FUNC_ALWAYS);
511 mFontProgramStore->setBlendFunc(RS_BLEND_SRC_SRC_ALPHA, RS_BLEND_DST_ONE_MINUS_SRC_ALPHA);
512 mFontProgramStore->setDitherEnable(false);
513 mFontProgramStore->setDepthMask(false);
514}
515
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800516void FontState::initTextTexture() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700517 const Element *alphaElem = Element::create(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
518
519 // We will allocate a texture to initially hold 32 character bitmaps
Jason Samsf0c1df42010-10-26 13:09:17 -0700520 Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700521
Jason Sams366c9c82010-12-08 16:14:36 -0800522 Allocation *cacheAlloc = new Allocation(mRSC, texType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700523 mTextTexture.set(cacheAlloc);
Jason Samsb7e83bd2010-12-15 01:41:00 -0800524 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700525
526 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700527 int32_t nextLine = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700528 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
529 nextLine += mCacheLines.top()->mMaxHeight;
530 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
531 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700532 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
533 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700534 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
535 nextLine += mCacheLines.top()->mMaxHeight;
536 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
537 nextLine += mCacheLines.top()->mMaxHeight;
538 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
539 nextLine += mCacheLines.top()->mMaxHeight;
540 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
541}
542
543// Avoid having to reallocate memory and render quad by quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800544void FontState::initVertexArrayBuffers() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700545 // Now lets write index data
546 const Element *indexElem = Element::create(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700547 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Jason Samsf0c1df42010-10-26 13:09:17 -0700548 Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700549
Jason Sams366c9c82010-12-08 16:14:36 -0800550 Allocation *indexAlloc = new Allocation(mRSC, indexType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700551 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
552
553 // Four verts, two triangles , six indices per quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800554 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700555 int32_t i6 = i * 6;
556 int32_t i4 = i * 4;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700557
558 indexPtr[i6 + 0] = i4 + 0;
559 indexPtr[i6 + 1] = i4 + 1;
560 indexPtr[i6 + 2] = i4 + 2;
561
562 indexPtr[i6 + 3] = i4 + 0;
563 indexPtr[i6 + 4] = i4 + 2;
564 indexPtr[i6 + 5] = i4 + 3;
565 }
566
567 indexAlloc->deferedUploadToBufferObject(mRSC);
568 mIndexBuffer.set(indexAlloc);
569
570 const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
571 const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
572
Alex Sakhartchouk64cd98e2010-10-18 17:18:50 -0700573 mRSC->mStateElement.elementBuilderBegin();
574 mRSC->mStateElement.elementBuilderAdd(posElem, "position", 1);
575 mRSC->mStateElement.elementBuilderAdd(texElem, "texture0", 1);
576 const Element *vertexDataElem = mRSC->mStateElement.elementBuilderCreate(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700577
Jason Samsf0c1df42010-10-26 13:09:17 -0700578 Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
579 mMaxNumberOfQuads * 4,
580 0, 0, false, false);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700581
Jason Sams366c9c82010-12-08 16:14:36 -0800582 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700583 mTextMeshPtr = (float*)vertexAlloc->getPtr();
584
585 mVertexArray.set(vertexAlloc);
586}
587
588// We don't want to allocate anything unless we actually draw text
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800589void FontState::checkInit() {
590 if (mInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700591 return;
592 }
593
594 initTextTexture();
595 initRenderState();
596
597 initVertexArrayBuffers();
598
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700599 // We store a string with letters in a rough frequency of occurrence
600 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
601 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
602 mLatinPrecache += String8(",.?!()-+@;:`'");
603 mLatinPrecache += String8("0123456789");
604
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700605 mInitialized = true;
606}
607
608void FontState::issueDrawCommand() {
Jason Sams60709252010-11-17 15:29:32 -0800609 Context::PushState ps(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700610
Jason Sams60709252010-11-17 15:29:32 -0800611 mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
612 mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
613 mRSC->setProgramFragment(mFontShaderF.get());
614 mRSC->setProgramStore(mFontProgramStore.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700615
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800616 if (mConstantsDirty) {
Jason Sams4b45b892010-12-29 14:31:29 -0800617 mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700618 mConstantsDirty = false;
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700619 }
620
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700621 if (!mRSC->setupCheck()) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700622 return;
623 }
624
625 float *vtx = (float*)mVertexArray->getPtr();
626 float *tex = vtx + 3;
627
Alex Sakhartchouk54929cc2010-11-08 15:10:52 -0800628 VertexArray::Attrib attribs[2];
629 attribs[0].set(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
630 attribs[1].set(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
631 VertexArray va(attribs, 2);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700632 va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
633
634 mIndexBuffer->uploadCheck(mRSC);
635 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
636 glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700637}
638
639void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800640 float u1, float v1,
641 float x2, float y2, float z2,
642 float u2, float v2,
643 float x3, float y3, float z3,
644 float u3, float v3,
645 float x4, float y4, float z4,
646 float u4, float v4) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700647 const uint32_t vertsPerQuad = 4;
648 const uint32_t floatsPerVert = 5;
649 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
650
651 // Cull things that are off the screen
652 float width = (float)mRSC->getWidth();
653 float height = (float)mRSC->getHeight();
654
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800655 if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700656 return;
657 }
658
659 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
660 LOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
661 LOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
662 LOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
663
664 (*currentPos++) = x1;
665 (*currentPos++) = y1;
666 (*currentPos++) = z1;
667 (*currentPos++) = u1;
668 (*currentPos++) = v1;
669
670 (*currentPos++) = x2;
671 (*currentPos++) = y2;
672 (*currentPos++) = z2;
673 (*currentPos++) = u2;
674 (*currentPos++) = v2;
675
676 (*currentPos++) = x3;
677 (*currentPos++) = y3;
678 (*currentPos++) = z3;
679 (*currentPos++) = u3;
680 (*currentPos++) = v3;
681
682 (*currentPos++) = x4;
683 (*currentPos++) = y4;
684 (*currentPos++) = z4;
685 (*currentPos++) = u4;
686 (*currentPos++) = v4;
687
688 mCurrentQuadIndex ++;
689
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800690 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700691 issueDrawCommand();
692 mCurrentQuadIndex = 0;
693 }
694}
695
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700696uint32_t FontState::getRemainingCacheCapacity() {
697 uint32_t remainingCapacity = 0;
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700698 uint32_t totalPixels = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800699 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700700 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
701 totalPixels += mCacheLines[i]->mMaxWidth;
702 }
703 remainingCapacity = (remainingCapacity * 100) / totalPixels;
704 return remainingCapacity;
705}
706
707void FontState::precacheLatin(Font *font) {
708 // Remaining capacity is measured in %
709 uint32_t remainingCapacity = getRemainingCacheCapacity();
710 uint32_t precacheIdx = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800711 while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700712 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
713 remainingCapacity = getRemainingCacheCapacity();
714 precacheIdx ++;
715 }
716}
717
718
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700719void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
720 uint32_t startIndex, int32_t numGlyphs,
721 Font::RenderMode mode,
722 Font::Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800723 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700724 checkInit();
725
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700726 // Render code here
727 Font *currentFont = mRSC->getFont();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800728 if (!currentFont) {
729 if (!mDefault.get()) {
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -0800730 String8 fontsDir("/fonts/DroidSans.ttf");
731 String8 fullPath(getenv("ANDROID_ROOT"));
732 fullPath += fontsDir;
733
734 mDefault.set(Font::create(mRSC, fullPath.string(), 16, 96));
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700735 }
736 currentFont = mDefault.get();
737 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800738 if (!currentFont) {
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700739 LOGE("Unable to initialize any fonts");
740 return;
741 }
742
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700743 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
744 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700745
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800746 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700747 issueDrawCommand();
748 mCurrentQuadIndex = 0;
749 }
750}
751
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700752void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
753 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800754 bounds->bottom = - bounds->bottom;
755 bounds->top = - bounds->top;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700756}
757
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700758void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700759 mConstants.mFontColor[0] = r;
760 mConstants.mFontColor[1] = g;
761 mConstants.mFontColor[2] = b;
762 mConstants.mFontColor[3] = a;
763
764 mConstants.mGamma = 1.0f;
Alex Sakhartchoukc8fb69e2010-10-05 13:23:55 -0700765 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700766 if (luminance <= mBlackThreshold) {
767 mConstants.mGamma = mBlackGamma;
768 } else if (luminance >= mWhiteThreshold) {
769 mConstants.mGamma = mWhiteGamma;
770 }
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700771
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700772 mConstantsDirty = true;
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700773}
774
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700775void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700776 *r = mConstants.mFontColor[0];
777 *g = mConstants.mFontColor[1];
778 *b = mConstants.mFontColor[2];
779 *a = mConstants.mFontColor[3];
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700780}
781
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800782void FontState::deinit(Context *rsc) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700783 mInitialized = false;
784
Stephen Hines01b7d292010-09-28 15:45:45 -0700785 mFontShaderFConstant.clear();
786
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700787 mIndexBuffer.clear();
788 mVertexArray.clear();
789
790 mFontShaderF.clear();
791 mFontSampler.clear();
792 mFontProgramStore.clear();
793
794 mTextTexture.clear();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800795 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700796 delete mCacheLines[i];
797 }
798 mCacheLines.clear();
799
800 mDefault.clear();
801
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700802 Vector<Font*> fontsToDereference = mActiveFonts;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800803 for (uint32_t i = 0; i < fontsToDereference.size(); i ++) {
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700804 fontsToDereference[i]->zeroUserRef();
805 }
806
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800807 if (mLibrary) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700808 FT_Done_FreeType( mLibrary );
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700809 mLibrary = NULL;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700810 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700811}
812
813namespace android {
814namespace renderscript {
815
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -0800816RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, float fontSize, uint32_t dpi) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700817 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800818 if (newFont) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700819 newFont->incUserRef();
820 }
821 return newFont;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700822}
823
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800824RsFont rsi_FontCreateFromMemory(Context *rsc, char const *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
825 Font *newFont = Font::create(rsc, name, fontSize, dpi, data, dataLen);
826 if (newFont) {
827 newFont->incUserRef();
828 }
829 return newFont;
830}
831
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700832} // renderscript
833} // android