blob: 8571c32e95ec3da805ec5976f8bd9889fe31c8df [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 Sakhartchoukb0253ea2011-01-07 11:12:08 -080043bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
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 Sakhartchoukb0253ea2011-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 Sakhartchouked9f2102010-11-09 17:00:54 -080056 if (error) {
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080057 LOGE("Unable to initialize font %s", name);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070058 return false;
59 }
60
61 mFontName = name;
62 mFontSize = fontSize;
63 mDpi = dpi;
64
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080065 error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080066 if (error) {
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080067 LOGE("Unable to set font size on %s", name);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070068 return false;
69 }
70
71 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070072
73 mInitialized = true;
74 return true;
75}
76
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080077void Font::invalidateTextureCache() {
78 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070079 mCachedGlyphs.valueAt(i)->mIsValid = false;
80 }
81}
82
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080083void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070084 FontState *state = &mRSC->mStateFont;
85
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070086 int32_t nPenX = x + glyph->mBitmapLeft;
87 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070088
Alex Sakhartchouk10825a02010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -070093
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070094 int32_t width = (int32_t) glyph->mBitmapWidth;
95 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070096
Alex Sakhartchouk10825a02010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700101}
102
Alex Sakhartchouk10825a02010-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 Sakhartchouk10825a02010-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 Sakhartchoukb0253ea2011-01-07 11:12:08 -0800136 // 0, 0 is top left, so bottom is a positive number
137 if (bounds->bottom < nPenY) {
Alex Sakhartchouk10825a02010-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 Sakhartchoukb0253ea2011-01-07 11:12:08 -0800146 if (bounds->top > nPenY - height) {
147 bounds->top = nPenY - height;
Alex Sakhartchouk10825a02010-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 Sakhartchouked9f2102010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700156 return;
157 }
158
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800159 if (mode == Font::MEASURE) {
Alex Sakhartchouk10825a02010-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 Sakhartchoukb0253ea2011-01-07 11:12:08 -0800165 bounds->set(1e6, -1e6, 1e6, -1e6);
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700166 }
167
168 int32_t penX = x, penY = y;
169 int32_t glyphsLeft = 1;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800170 if (numGlyphs > 0) {
Alex Sakhartchouk9b949fc2010-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 Root300ba682010-11-09 14:37:23 -0800179 int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700180
181 // Reached the end of the string or encountered
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800182 if (utfChar < 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700183 break;
184 }
185
186 // Move to the next character in the array
187 index = nextIndex;
188
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700189 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800192 if (cachedGlyph->mIsValid) {
193 switch (mode) {
Alex Sakhartchouk10825a02010-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 Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800209 if (numGlyphs > 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700210 glyphsLeft --;
211 }
212 }
213}
214
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700215Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
216
217 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800218 if (cachedGlyph == NULL) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700219 cachedGlyph = cacheGlyph((uint32_t)utfChar);
220 }
221 // Is the glyph still in texture cache?
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800222 if (!cachedGlyph->mIsValid) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700223 updateGlyphCache(cachedGlyph);
224 }
225
226 return cachedGlyph;
227}
228
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800229void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700230 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800231 if (error) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700232 LOGE("Couldn't load glyph.");
233 return;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700234 }
235
Alex Sakhartchouk071508d2010-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 Sakhartchouk9b949fc2010-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 Sakhartchouk071508d2010-06-30 12:49:27 -0700248 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700249
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800250 if (!glyph->mIsValid) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700251 return;
252 }
253
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700254 uint32_t endX = startX + bitmap->width;
255 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700256
257 glyph->mBitmapMinX = startX;
258 glyph->mBitmapMinY = startY;
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700259 glyph->mBitmapWidth = bitmap->width;
260 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800271Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700277
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700278 updateGlyphCache(newGlyph);
279
280 return newGlyph;
281}
282
Alex Sakhartchoukb0253ea2011-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 Sakhartchouk27f50522010-08-18 15:46:43 -0700285 rsc->mStateFont.checkInit();
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700286 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
287
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800288 for (uint32_t i = 0; i < activeFonts.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700289 Font *ithFont = activeFonts[i];
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800290 if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700291 return ithFont;
292 }
293 }
294
295 Font *newFont = new Font(rsc);
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800296 bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800297 if (isInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700298 activeFonts.push(newFont);
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700299 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700300 return newFont;
301 }
302
Jason Samsb38d5342010-10-21 14:06:55 -0700303 ObjectBase::checkDelete(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700304 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700305}
306
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800307Font::~Font() {
308 if (mFace) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800319 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700320 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700321 delete glyph;
322 }
323}
324
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800325FontState::FontState() {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700326 mInitialized = false;
327 mMaxNumberOfQuads = 1024;
328 mCurrentQuadIndex = 0;
329 mRSC = NULL;
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700330 mLibrary = NULL;
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700338 gamma = atof(property);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700339 }
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) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700344 blackThreshold = atoi(property);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700345 }
346 mBlackThreshold = (float)(blackThreshold) / 255.0f;
347
348 // Get the white gamma threshold
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700349 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700350 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700351 whiteThreshold = atoi(property);
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk960ae152010-10-12 14:15:17 -0700358
359 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700360}
361
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800362FontState::~FontState() {
363 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700364 delete mCacheLines[i];
365 }
366
367 rsAssert(!mActiveFonts.size());
368}
369
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800370FT_Library FontState::getLib() {
371 if (!mLibrary) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700372 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800373 if (error) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700374 LOGE("Unable to initialize freetype");
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700375 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700376 }
377 }
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700378
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700379 return mLibrary;
380}
381
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800382void FontState::init(Context *rsc) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700383 mRSC = rsc;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700384}
385
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800386void FontState::flushAllAndInvalidate() {
387 if (mCurrentQuadIndex != 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700388 issueDrawCommand();
389 mCurrentQuadIndex = 0;
390 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800391 for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700392 mActiveFonts[i]->invalidateTextureCache();
393 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800394 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700395 mCacheLines[i]->mCurrentCol = 0;
396 }
397}
398
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800399bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700400 // If the glyph is too tall, don't cache it
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800401 if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800411 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700412 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800413 if (bitmapFit) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800419 if (!bitmapFit) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700420 flushAllAndInvalidate();
421
422 // Try to fit it again
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800423 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700424 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800425 if (bitmapFit) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800431 if (!bitmapFit) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700443 uint32_t cacheWidth = getCacheTextureType()->getDimX();
444
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700445 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
446 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700447
448 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
Alex Sakhartchouked9f2102010-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 Sakhartchouk10825a02010-10-05 11:33:27 -0700451 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchouk9b949fc2010-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 Sams6d8eb262010-12-15 01:41:00 -0800458 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700459 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700460
461 // Some debug code
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800462 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800472void FontState::initRenderState() {
Alex Sakhartchoukd2091632010-10-06 11:15:01 -0700473 String8 shaderString("varying vec2 varTex0;\n");
Alex Sakhartchoukc984dd72010-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 Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700477 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchoukc984dd72010-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 Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700482 const Element *gammaElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700483 mRSC->mStateElement.elementBuilderBegin();
484 mRSC->mStateElement.elementBuilderAdd(colorElem, "Color", 1);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700485 mRSC->mStateElement.elementBuilderAdd(gammaElem, "Gamma", 1);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700486 const Element *constInput = mRSC->mStateElement.elementBuilderCreate(mRSC);
487
Jason Sams31a7e422010-10-26 13:09:17 -0700488 Type *inputType = Type::getType(mRSC, constInput, 1, 0, 0, false, false);
Alex Sakhartchoukc984dd72010-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 Sakhartchouk67f2e442010-11-18 15:22:43 -0800493 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
494 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700495
Jason Sams5476b452010-12-08 16:14:36 -0800496 mFontShaderFConstant.set(new Allocation(mRSC, inputType,
497 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700498 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
499 shaderString.length(), tmp, 4);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700500 mFontShaderF.set(pf);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700501 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchouk9b949fc2010-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 Sakhartchoukb89aaac2010-09-23 16:16:33 -0700506 mFontShaderF->bindSampler(mRSC, 0, sampler);
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800516void FontState::initTextTexture() {
Alex Sakhartchouk9b949fc2010-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 Sams31a7e422010-10-26 13:09:17 -0700520 Type *texType = Type::getType(mRSC, alphaElem, 1024, 256, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700521
Jason Sams5476b452010-12-08 16:14:36 -0800522 Allocation *cacheAlloc = new Allocation(mRSC, texType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700523 mTextTexture.set(cacheAlloc);
Jason Sams6d8eb262010-12-15 01:41:00 -0800524 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700525
526 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700527 int32_t nextLine = 0;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk94bbccc2010-08-17 11:09:49 -0700532 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
533 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800544void FontState::initVertexArrayBuffers() {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700547 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Jason Sams31a7e422010-10-26 13:09:17 -0700548 Type *indexType = Type::getType(mRSC, indexElem, numIndicies, 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700549
Jason Sams5476b452010-12-08 16:14:36 -0800550 Allocation *indexAlloc = new Allocation(mRSC, indexType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700551 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
552
553 // Four verts, two triangles , six indices per quad
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800554 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700555 int32_t i6 = i * 6;
556 int32_t i4 = i * 4;
Alex Sakhartchouk9b949fc2010-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 Sakhartchouk98bfe5d2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700577
Jason Sams31a7e422010-10-26 13:09:17 -0700578 Type *vertexDataType = Type::getType(mRSC, vertexDataElem,
579 mMaxNumberOfQuads * 4,
580 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700581
Jason Sams5476b452010-12-08 16:14:36 -0800582 Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800589void FontState::checkInit() {
590 if (mInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700591 return;
592 }
593
594 initTextTexture();
595 initRenderState();
596
597 initVertexArrayBuffers();
598
Alex Sakhartchouk27f50522010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700605 mInitialized = true;
606}
607
608void FontState::issueDrawCommand() {
Jason Samsa17af042010-11-17 15:29:32 -0800609 Context::PushState ps(mRSC);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700610
Jason Samsa17af042010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700615
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800616 if (mConstantsDirty) {
Jason Sams49a05d72010-12-29 14:31:29 -0800617 mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700618 mConstantsDirty = false;
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700619 }
620
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700621 if (!mRSC->setupCheck()) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700622 return;
623 }
624
625 float *vtx = (float*)mVertexArray->getPtr();
626 float *tex = vtx + 3;
627
Alex Sakhartchouk9d71e212010-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 Sakhartchouk9b949fc2010-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700637}
638
639void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchouked9f2102010-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 Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800655 if (x1 > width || y1 < 0.0f || x2 < 0 || y4 > height) {
Alex Sakhartchouk9b949fc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800690 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700691 issueDrawCommand();
692 mCurrentQuadIndex = 0;
693 }
694}
695
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700696uint32_t FontState::getRemainingCacheCapacity() {
697 uint32_t remainingCapacity = 0;
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700698 uint32_t totalPixels = 0;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800699 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk94bbccc2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800711 while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700712 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
713 remainingCapacity = getRemainingCacheCapacity();
714 precacheIdx ++;
715 }
716}
717
718
Alex Sakhartchouk10825a02010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800723 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700724 checkInit();
725
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700726 // Render code here
727 Font *currentFont = mRSC->getFont();
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800728 if (!currentFont) {
729 if (!mDefault.get()) {
Alex Sakhartchouke27cdee2010-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 Sakhartchouk071508d2010-06-30 12:49:27 -0700735 }
736 currentFont = mDefault.get();
737 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800738 if (!currentFont) {
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700739 LOGE("Unable to initialize any fonts");
740 return;
741 }
742
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700743 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
744 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700745
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800746 if (mCurrentQuadIndex != 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700747 issueDrawCommand();
748 mCurrentQuadIndex = 0;
749 }
750}
751
Alex Sakhartchouk10825a02010-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 Sakhartchoukb0253ea2011-01-07 11:12:08 -0800754 bounds->bottom = - bounds->bottom;
755 bounds->top = - bounds->top;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700756}
757
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700758void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk76322af2010-10-05 13:23:55 -0700765 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700766 if (luminance <= mBlackThreshold) {
767 mConstants.mGamma = mBlackGamma;
768 } else if (luminance >= mWhiteThreshold) {
769 mConstants.mGamma = mWhiteGamma;
770 }
Alex Sakhartchouk960ae152010-10-12 14:15:17 -0700771
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700772 mConstantsDirty = true;
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700773}
774
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700775void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchouk3bf3ea02010-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 Sakhartchouk55e81982010-08-05 11:24:14 -0700780}
781
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800782void FontState::deinit(Context *rsc) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700783 mInitialized = false;
784
Stephen Hines01f0ad72010-09-28 15:45:45 -0700785 mFontShaderFConstant.clear();
786
Alex Sakhartchouk071508d2010-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 Sakhartchouked9f2102010-11-09 17:00:54 -0800795 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700796 delete mCacheLines[i];
797 }
798 mCacheLines.clear();
799
800 mDefault.clear();
801
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700802 Vector<Font*> fontsToDereference = mActiveFonts;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800803 for (uint32_t i = 0; i < fontsToDereference.size(); i ++) {
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700804 fontsToDereference[i]->zeroUserRef();
805 }
806
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800807 if (mLibrary) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700808 FT_Done_FreeType( mLibrary );
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700809 mLibrary = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700810 }
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700811}
812
813namespace android {
814namespace renderscript {
815
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -0800816RsFont rsi_FontCreateFromFile(Context *rsc, char const *name, float fontSize, uint32_t dpi) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700817 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800818 if (newFont) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700819 newFont->incUserRef();
820 }
821 return newFont;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700822}
823
Alex Sakhartchoukb0253ea2011-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 Sakhartchouk9b949fc2010-06-24 17:15:34 -0700832} // renderscript
833} // android