blob: 1f53c79ba5231ac701db2bec1283c6302fed50e0 [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
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070018#include "rsContext.h"
Alex Sakhartchouk137ccbb2012-03-09 09:24:39 -080019#include "rs.h"
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070020#include "rsFont.h"
21#include "rsProgramFragment.h"
Alex Sakhartchoukbedc0232012-03-09 10:47:27 -080022#include "rsMesh.h"
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -070023#include <cutils/properties.h>
Alex Sakhartchoukebd65bb2011-02-25 09:34:33 -080024
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -070025#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukebd65bb2011-02-25 09:34:33 -080026#include <ft2build.h>
27#include FT_FREETYPE_H
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070028#include FT_BITMAP_H
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -070029#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070030
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070031using namespace android;
32using namespace android::renderscript;
33
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080034Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070035 mInitialized = false;
36 mHasKerning = false;
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -070037 mFace = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070038}
39
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -080040bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -070041#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080042 if (mInitialized) {
Steve Block3762c312012-01-06 19:20:56 +000043 ALOGE("Reinitialization of fonts not supported");
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070044 return false;
45 }
46
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -080047 FT_Error error = 0;
48 if (data != NULL && dataLen > 0) {
49 error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
50 } else {
51 error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
52 }
53
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080054 if (error) {
Steve Block3762c312012-01-06 19:20:56 +000055 ALOGE("Unable to initialize font %s", name);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070056 return false;
57 }
58
59 mFontName = name;
60 mFontSize = fontSize;
61 mDpi = dpi;
62
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -080063 error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080064 if (error) {
Steve Block3762c312012-01-06 19:20:56 +000065 ALOGE("Unable to set font size on %s", name);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070066 return false;
67 }
68
69 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070070
71 mInitialized = true;
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -070072#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070073 return true;
74}
75
Jason Sams38f8d9d2011-01-27 00:14:13 -080076void Font::preDestroy() const {
77 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
78 if (mRSC->mStateFont.mActiveFonts[ct] == this) {
79 mRSC->mStateFont.mActiveFonts.removeAt(ct);
80 break;
81 }
82 }
83}
84
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080085void Font::invalidateTextureCache() {
86 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070087 mCachedGlyphs.valueAt(i)->mIsValid = false;
88 }
89}
90
Alex Sakhartchouked9f2102010-11-09 17:00:54 -080091void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070092 FontState *state = &mRSC->mStateFont;
93
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070094 int32_t nPenX = x + glyph->mBitmapLeft;
95 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -070096
Alex Sakhartchouk10825a02010-10-05 11:33:27 -070097 float u1 = glyph->mBitmapMinU;
98 float u2 = glyph->mBitmapMaxU;
99 float v1 = glyph->mBitmapMinV;
100 float v2 = glyph->mBitmapMaxV;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700101
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700102 int32_t width = (int32_t) glyph->mBitmapWidth;
103 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700104
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700105 state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
106 nPenX + width, nPenY, 0, u2, v2,
107 nPenX + width, nPenY - height, 0, u2, v1,
108 nPenX, nPenY - height, 0, u1, v1);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700109}
110
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700111void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
112 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
113 int32_t nPenX = x + glyph->mBitmapLeft;
114 int32_t nPenY = y + glyph->mBitmapTop;
115
116 uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
117 uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
118
119 FontState *state = &mRSC->mStateFont;
120 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
121 const uint8_t* cacheBuffer = state->getTextTextureData();
122
123 uint32_t cacheX = 0, cacheY = 0;
124 int32_t bX = 0, bY = 0;
125 for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
126 for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
127 if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
Steve Block3762c312012-01-06 19:20:56 +0000128 ALOGE("Skipping invalid index");
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700129 continue;
130 }
131 uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
132 bitmap[bY * bitmapW + bX] = tempCol;
133 }
134 }
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700135}
136
137void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
138 int32_t nPenX = x + glyph->mBitmapLeft;
139 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
140
141 int32_t width = (int32_t) glyph->mBitmapWidth;
142 int32_t height = (int32_t) glyph->mBitmapHeight;
143
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800144 // 0, 0 is top left, so bottom is a positive number
145 if (bounds->bottom < nPenY) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700146 bounds->bottom = nPenY;
147 }
148 if (bounds->left > nPenX) {
149 bounds->left = nPenX;
150 }
151 if (bounds->right < nPenX + width) {
152 bounds->right = nPenX + width;
153 }
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800154 if (bounds->top > nPenY - height) {
155 bounds->top = nPenY - height;
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700156 }
157}
158
159void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
160 uint32_t start, int32_t numGlyphs,
161 RenderMode mode, Rect *bounds,
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800162 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
163 if (!mInitialized || numGlyphs == 0 || text == NULL || len == 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700164 return;
165 }
166
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800167 if (mode == Font::MEASURE) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700168 if (bounds == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000169 ALOGE("No return rectangle provided to measure text");
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700170 return;
171 }
172 // Reset min and max of the bounding box to something large
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800173 bounds->set(1e6, -1e6, 1e6, -1e6);
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700174 }
175
176 int32_t penX = x, penY = y;
177 int32_t glyphsLeft = 1;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800178 if (numGlyphs > 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700179 glyphsLeft = numGlyphs;
180 }
181
182 size_t index = start;
183 size_t nextIndex = 0;
184
185 while (glyphsLeft > 0) {
186
Kenny Root300ba682010-11-09 14:37:23 -0800187 int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700188
189 // Reached the end of the string or encountered
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800190 if (utfChar < 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700191 break;
192 }
193
194 // Move to the next character in the array
195 index = nextIndex;
196
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700197 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700198
199 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800200 if (cachedGlyph->mIsValid) {
201 switch (mode) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700202 case FRAMEBUFFER:
203 drawCachedGlyph(cachedGlyph, penX, penY);
204 break;
205 case BITMAP:
206 drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
207 break;
208 case MEASURE:
209 measureCachedGlyph(cachedGlyph, penX, penY, bounds);
210 break;
211 }
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700212 }
213
Alex Sakhartchoukebd65bb2011-02-25 09:34:33 -0800214 penX += (cachedGlyph->mAdvanceX >> 6);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700215
216 // If we were given a specific number of glyphs, decrement
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800217 if (numGlyphs > 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700218 glyphsLeft --;
219 }
220 }
221}
222
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700223Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
224
225 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800226 if (cachedGlyph == NULL) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700227 cachedGlyph = cacheGlyph((uint32_t)utfChar);
228 }
229 // Is the glyph still in texture cache?
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800230 if (!cachedGlyph->mIsValid) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700231 updateGlyphCache(cachedGlyph);
232 }
233
234 return cachedGlyph;
235}
236
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800237void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700238#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700239 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800240 if (error) {
Steve Block3762c312012-01-06 19:20:56 +0000241 ALOGE("Couldn't load glyph.");
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700242 return;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700243 }
244
Alex Sakhartchoukebd65bb2011-02-25 09:34:33 -0800245 glyph->mAdvanceX = mFace->glyph->advance.x;
246 glyph->mAdvanceY = mFace->glyph->advance.y;
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700247 glyph->mBitmapLeft = mFace->glyph->bitmap_left;
248 glyph->mBitmapTop = mFace->glyph->bitmap_top;
249
250 FT_Bitmap *bitmap = &mFace->glyph->bitmap;
251
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700252 // Now copy the bitmap into the cache texture
253 uint32_t startX = 0;
254 uint32_t startY = 0;
255
256 // Let the font state figure out where to put the bitmap
257 FontState *state = &mRSC->mStateFont;
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700258 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700259
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800260 if (!glyph->mIsValid) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700261 return;
262 }
263
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700264 uint32_t endX = startX + bitmap->width;
265 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700266
267 glyph->mBitmapMinX = startX;
268 glyph->mBitmapMinY = startY;
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700269 glyph->mBitmapWidth = bitmap->width;
270 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700271
272 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
273 uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
274
275 glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
276 glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
277 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
278 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700279#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700280}
281
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800282Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700283 CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
284 mCachedGlyphs.add(glyph, newGlyph);
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700285#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700286 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
287 newGlyph->mIsValid = false;
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700288#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700289 updateGlyphCache(newGlyph);
290
291 return newGlyph;
292}
293
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800294Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
295 const void *data, uint32_t dataLen) {
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700296 rsc->mStateFont.checkInit();
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700297 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
298
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800299 for (uint32_t i = 0; i < activeFonts.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700300 Font *ithFont = activeFonts[i];
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800301 if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700302 return ithFont;
303 }
304 }
305
306 Font *newFont = new Font(rsc);
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800307 bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800308 if (isInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700309 activeFonts.push(newFont);
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700310 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700311 return newFont;
312 }
313
Jason Samsb38d5342010-10-21 14:06:55 -0700314 ObjectBase::checkDelete(newFont);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700315 return NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700316}
317
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800318Font::~Font() {
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700319#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800320 if (mFace) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700321 FT_Done_Face(mFace);
322 }
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700323#endif
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700324
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800325 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700326 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700327 delete glyph;
328 }
329}
330
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800331FontState::FontState() {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700332 mInitialized = false;
333 mMaxNumberOfQuads = 1024;
334 mCurrentQuadIndex = 0;
335 mRSC = NULL;
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700336#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700337 mLibrary = NULL;
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700338#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700339
340 // Get the renderer properties
341 char property[PROPERTY_VALUE_MAX];
342
343 // Get the gamma
344 float gamma = DEFAULT_TEXT_GAMMA;
345 if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700346 gamma = atof(property);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700347 }
348
349 // Get the black gamma threshold
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700350 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700351 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700352 blackThreshold = atoi(property);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700353 }
354 mBlackThreshold = (float)(blackThreshold) / 255.0f;
355
356 // Get the white gamma threshold
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700357 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700358 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700359 whiteThreshold = atoi(property);
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700360 }
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}
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700377#ifndef ANDROID_RS_SERIALIZE
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) {
Steve Block3762c312012-01-06 19:20:56 +0000382 ALOGE("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}
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700389#endif //ANDROID_RS_SERIALIZE
390
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700391
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800392void FontState::init(Context *rsc) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700393 mRSC = rsc;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700394}
395
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800396void FontState::flushAllAndInvalidate() {
397 if (mCurrentQuadIndex != 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700398 issueDrawCommand();
399 mCurrentQuadIndex = 0;
400 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800401 for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700402 mActiveFonts[i]->invalidateTextureCache();
403 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800404 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700405 mCacheLines[i]->mCurrentCol = 0;
406 }
407}
408
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700409#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800410bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700411 // If the glyph is too tall, don't cache it
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800412 if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
Steve Block3762c312012-01-06 19:20:56 +0000413 ALOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700414 return false;
415 }
416
417 // Now copy the bitmap into the cache texture
418 uint32_t startX = 0;
419 uint32_t startY = 0;
420
421 bool bitmapFit = false;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800422 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700423 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800424 if (bitmapFit) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700425 break;
426 }
427 }
428
429 // If the new glyph didn't fit, flush the state so far and invalidate everything
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800430 if (!bitmapFit) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700431 flushAllAndInvalidate();
432
433 // Try to fit it again
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800434 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700435 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800436 if (bitmapFit) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700437 break;
438 }
439 }
440
441 // if we still don't fit, something is wrong and we shouldn't draw
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800442 if (!bitmapFit) {
Steve Block3762c312012-01-06 19:20:56 +0000443 ALOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700444 return false;
445 }
446 }
447
448 *retOriginX = startX;
449 *retOriginY = startY;
450
451 uint32_t endX = startX + bitmap->width;
452 uint32_t endY = startY + bitmap->rows;
453
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700454 uint32_t cacheWidth = getCacheTextureType()->getDimX();
455
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700456 uint8_t *cacheBuffer = (uint8_t*)mTextTexture->getPtr();
457 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700458
459 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800460 for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
461 for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700462 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700463 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
464 }
465 }
466
467 // This will dirty the texture and the shader so next time
468 // we draw it will upload the data
Jason Sams7e8aae72011-05-26 16:33:01 -0700469
470 mTextTexture->sendDirty(mRSC);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700471 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700472
473 // Some debug code
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800474 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Steve Block3762c312012-01-06 19:20:56 +0000475 ALOGE("Cache Line: H: %u Empty Space: %f",
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700476 mCacheLines[i]->mMaxHeight,
477 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
478
479 }*/
480
481 return true;
482}
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700483#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700484
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800485void FontState::initRenderState() {
Alex Sakhartchoukd2091632010-10-06 11:15:01 -0700486 String8 shaderString("varying vec2 varTex0;\n");
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700487 shaderString.append("void main() {\n");
488 shaderString.append(" lowp vec4 col = UNI_Color;\n");
489 shaderString.append(" col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n");
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700490 shaderString.append(" col.a = pow(col.a, UNI_Gamma);\n");
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700491 shaderString.append(" gl_FragColor = col;\n");
492 shaderString.append("}\n");
493
Alex Sakhartchouk2123b462012-02-15 16:21:46 -0800494 const char *textureNames[] = { "Tex0" };
495 const size_t textureNamesLengths[] = { 4 };
496 size_t numTextures = sizeof(textureNamesLengths)/sizeof(*textureNamesLengths);
497
498 ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
499 RS_KIND_USER, false, 4);
500 ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
501 RS_KIND_USER, false, 1);
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700502 Element::Builder builder;
503 builder.add(colorElem.get(), "Color", 1);
504 builder.add(gammaElem.get(), "Gamma", 1);
505 ObjectBaseRef<const Element> constInput = builder.create(mRSC);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700506
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700507 ObjectBaseRef<Type> inputType = Type::getTypeRef(mRSC, constInput.get(), 1, 0, 0, false, false);
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700508
509 uint32_t tmp[4];
510 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700511 tmp[1] = (uint32_t)inputType.get();
Alex Sakhartchouk67f2e442010-11-18 15:22:43 -0800512 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
513 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchoukc984dd72010-09-14 09:50:43 -0700514
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700515 mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
Alex Sakhartchouk2123b462012-02-15 16:21:46 -0800516 RS_ALLOCATION_USAGE_SCRIPT |
517 RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
518 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(), shaderString.length(),
519 textureNames, numTextures, textureNamesLengths,
520 tmp, 4);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700521 mFontShaderF.set(pf);
Alex Sakhartchoukb89aaac2010-09-23 16:16:33 -0700522 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700523
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700524 mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
Alex Sakhartchouk2123b462012-02-15 16:21:46 -0800525 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP,
526 RS_SAMPLER_CLAMP).get());
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700527 mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700528
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700529 mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
530 false, false,
531 RS_BLEND_SRC_SRC_ALPHA,
532 RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
533 RS_DEPTH_FUNC_ALWAYS).get());
Jason Sams48f50562011-03-18 15:03:25 -0700534 mFontProgramStore->init();
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700535}
536
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800537void FontState::initTextTexture() {
Alex Sakhartchouk2123b462012-02-15 16:21:46 -0800538 ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8,
539 RS_KIND_PIXEL_A, true, 1);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700540
541 // We will allocate a texture to initially hold 32 character bitmaps
Alex Sakhartchouk2123b462012-02-15 16:21:46 -0800542 ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(),
543 1024, 256, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700544
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700545 Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(),
Jason Sams7e8aae72011-05-26 16:33:01 -0700546 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700547 mTextTexture.set(cacheAlloc);
Jason Sams6d8eb262010-12-15 01:41:00 -0800548 mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700549
550 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700551 int32_t nextLine = 0;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700552 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
553 nextLine += mCacheLines.top()->mMaxHeight;
554 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
555 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700556 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
557 nextLine += mCacheLines.top()->mMaxHeight;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700558 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
559 nextLine += mCacheLines.top()->mMaxHeight;
560 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
561 nextLine += mCacheLines.top()->mMaxHeight;
562 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
563 nextLine += mCacheLines.top()->mMaxHeight;
564 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
565}
566
567// Avoid having to reallocate memory and render quad by quad
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800568void FontState::initVertexArrayBuffers() {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700569 // Now lets write index data
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700570 ObjectBaseRef<const Element> indexElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700571 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700572 ObjectBaseRef<Type> indexType = Type::getTypeRef(mRSC, indexElem.get(), numIndicies, 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700573
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700574 Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType.get(),
Jason Sams7e8aae72011-05-26 16:33:01 -0700575 RS_ALLOCATION_USAGE_SCRIPT |
576 RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700577 uint16_t *indexPtr = (uint16_t*)indexAlloc->getPtr();
578
579 // Four verts, two triangles , six indices per quad
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800580 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700581 int32_t i6 = i * 6;
582 int32_t i4 = i * 4;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700583
584 indexPtr[i6 + 0] = i4 + 0;
585 indexPtr[i6 + 1] = i4 + 1;
586 indexPtr[i6 + 2] = i4 + 2;
587
588 indexPtr[i6 + 3] = i4 + 0;
589 indexPtr[i6 + 4] = i4 + 2;
590 indexPtr[i6 + 5] = i4 + 3;
591 }
592
Jason Sams7e8aae72011-05-26 16:33:01 -0700593 indexAlloc->sendDirty(mRSC);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700594
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700595 ObjectBaseRef<const Element> posElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
596 ObjectBaseRef<const Element> texElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700597
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700598 Element::Builder builder;
599 builder.add(posElem.get(), "position", 1);
600 builder.add(texElem.get(), "texture0", 1);
601 ObjectBaseRef<const Element> vertexDataElem = builder.create(mRSC);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700602
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700603 ObjectBaseRef<Type> vertexDataType = Type::getTypeRef(mRSC, vertexDataElem.get(),
604 mMaxNumberOfQuads * 4,
605 0, 0, false, false);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700606
Alex Sakhartchouk117abdb2011-08-16 13:09:46 -0700607 Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType.get(),
Jason Sams7e8aae72011-05-26 16:33:01 -0700608 RS_ALLOCATION_USAGE_SCRIPT);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700609 mTextMeshPtr = (float*)vertexAlloc->getPtr();
610
Alex Sakhartchouk4a36b452011-04-29 16:49:08 -0700611 mMesh.set(new Mesh(mRSC, 1, 1));
612 mMesh->setVertexBuffer(vertexAlloc, 0);
613 mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
614 mMesh->init();
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700615}
616
617// We don't want to allocate anything unless we actually draw text
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800618void FontState::checkInit() {
619 if (mInitialized) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700620 return;
621 }
622
623 initTextTexture();
624 initRenderState();
625
626 initVertexArrayBuffers();
627
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700628 // We store a string with letters in a rough frequency of occurrence
629 mLatinPrecache = String8(" eisarntolcdugpmhbyfvkwzxjq");
630 mLatinPrecache += String8("EISARNTOLCDUGPMHBYFVKWZXJQ");
631 mLatinPrecache += String8(",.?!()-+@;:`'");
632 mLatinPrecache += String8("0123456789");
633
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700634 mInitialized = true;
635}
636
637void FontState::issueDrawCommand() {
Jason Samsa17af042010-11-17 15:29:32 -0800638 Context::PushState ps(mRSC);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700639
Jason Samsa17af042010-11-17 15:29:32 -0800640 mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
641 mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
642 mRSC->setProgramFragment(mFontShaderF.get());
643 mRSC->setProgramStore(mFontProgramStore.get());
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700644
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800645 if (mConstantsDirty) {
Jason Sams49a05d72010-12-29 14:31:29 -0800646 mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700647 mConstantsDirty = false;
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700648 }
649
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700650 if (!mRSC->setupCheck()) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700651 return;
652 }
653
Alex Sakhartchouk4a36b452011-04-29 16:49:08 -0700654 mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700655}
656
657void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800658 float u1, float v1,
659 float x2, float y2, float z2,
660 float u2, float v2,
661 float x3, float y3, float z3,
662 float u3, float v3,
663 float x4, float y4, float z4,
664 float u4, float v4) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700665 const uint32_t vertsPerQuad = 4;
Alex Sakhartchouke60149d2011-11-15 15:15:21 -0800666 const uint32_t floatsPerVert = 6;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700667 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
668
Alex Sakhartchouk2d8ef492011-11-16 12:22:10 -0800669 if (x1 > mSurfaceWidth || y1 < 0.0f || x2 < 0 || y4 > mSurfaceHeight) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700670 return;
671 }
672
673 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
Steve Block3762c312012-01-06 19:20:56 +0000674 ALOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
675 ALOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
676 ALOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700677
678 (*currentPos++) = x1;
679 (*currentPos++) = y1;
680 (*currentPos++) = z1;
Alex Sakhartchouke60149d2011-11-15 15:15:21 -0800681 (*currentPos++) = 0;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700682 (*currentPos++) = u1;
683 (*currentPos++) = v1;
684
685 (*currentPos++) = x2;
686 (*currentPos++) = y2;
687 (*currentPos++) = z2;
Alex Sakhartchouke60149d2011-11-15 15:15:21 -0800688 (*currentPos++) = 0;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700689 (*currentPos++) = u2;
690 (*currentPos++) = v2;
691
692 (*currentPos++) = x3;
693 (*currentPos++) = y3;
694 (*currentPos++) = z3;
Alex Sakhartchouke60149d2011-11-15 15:15:21 -0800695 (*currentPos++) = 0;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700696 (*currentPos++) = u3;
697 (*currentPos++) = v3;
698
699 (*currentPos++) = x4;
700 (*currentPos++) = y4;
701 (*currentPos++) = z4;
Alex Sakhartchouke60149d2011-11-15 15:15:21 -0800702 (*currentPos++) = 0;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700703 (*currentPos++) = u4;
704 (*currentPos++) = v4;
705
706 mCurrentQuadIndex ++;
707
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800708 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700709 issueDrawCommand();
710 mCurrentQuadIndex = 0;
711 }
712}
713
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700714uint32_t FontState::getRemainingCacheCapacity() {
715 uint32_t remainingCapacity = 0;
Alex Sakhartchouk27f50522010-08-18 15:46:43 -0700716 uint32_t totalPixels = 0;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800717 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700718 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
719 totalPixels += mCacheLines[i]->mMaxWidth;
720 }
721 remainingCapacity = (remainingCapacity * 100) / totalPixels;
722 return remainingCapacity;
723}
724
725void FontState::precacheLatin(Font *font) {
726 // Remaining capacity is measured in %
727 uint32_t remainingCapacity = getRemainingCacheCapacity();
728 uint32_t precacheIdx = 0;
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800729 while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) {
Alex Sakhartchouk94bbccc2010-08-17 11:09:49 -0700730 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
731 remainingCapacity = getRemainingCacheCapacity();
732 precacheIdx ++;
733 }
734}
735
736
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700737void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
738 uint32_t startIndex, int32_t numGlyphs,
739 Font::RenderMode mode,
740 Font::Rect *bounds,
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800741 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700742 checkInit();
743
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700744 // Render code here
745 Font *currentFont = mRSC->getFont();
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800746 if (!currentFont) {
747 if (!mDefault.get()) {
Christian Robertsonbeb2b5c2011-08-09 15:24:25 -0700748 String8 fontsDir("/fonts/Roboto-Regular.ttf");
Alex Sakhartchouke27cdee2010-12-17 11:41:08 -0800749 String8 fullPath(getenv("ANDROID_ROOT"));
750 fullPath += fontsDir;
751
Alex Sakhartchouk2c74ad92011-03-16 19:28:25 -0700752 mDefault.set(Font::create(mRSC, fullPath.string(), 8, mRSC->getDPI()));
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700753 }
754 currentFont = mDefault.get();
755 }
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800756 if (!currentFont) {
Steve Block3762c312012-01-06 19:20:56 +0000757 ALOGE("Unable to initialize any fonts");
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700758 return;
759 }
760
Alex Sakhartchouk2d8ef492011-11-16 12:22:10 -0800761 // Cull things that are off the screen
762 mSurfaceWidth = (float)mRSC->getCurrentSurfaceWidth();
763 mSurfaceHeight = (float)mRSC->getCurrentSurfaceHeight();
764
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700765 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
766 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700767
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800768 if (mCurrentQuadIndex != 0) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700769 issueDrawCommand();
770 mCurrentQuadIndex = 0;
771 }
772}
773
Alex Sakhartchouk10825a02010-10-05 11:33:27 -0700774void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
775 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800776 bounds->bottom = - bounds->bottom;
777 bounds->top = - bounds->top;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700778}
779
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700780void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700781 mConstants.mFontColor[0] = r;
782 mConstants.mFontColor[1] = g;
783 mConstants.mFontColor[2] = b;
784 mConstants.mFontColor[3] = a;
785
786 mConstants.mGamma = 1.0f;
Alex Sakhartchouk76322af2010-10-05 13:23:55 -0700787 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700788 if (luminance <= mBlackThreshold) {
789 mConstants.mGamma = mBlackGamma;
790 } else if (luminance >= mWhiteThreshold) {
791 mConstants.mGamma = mWhiteGamma;
792 }
Alex Sakhartchouk960ae152010-10-12 14:15:17 -0700793
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700794 mConstantsDirty = true;
Alex Sakhartchoukfb10c162010-08-04 14:45:48 -0700795}
796
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700797void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchouk3bf3ea02010-10-01 15:20:41 -0700798 *r = mConstants.mFontColor[0];
799 *g = mConstants.mFontColor[1];
800 *b = mConstants.mFontColor[2];
801 *a = mConstants.mFontColor[3];
Alex Sakhartchouk55e81982010-08-05 11:24:14 -0700802}
803
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800804void FontState::deinit(Context *rsc) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700805 mInitialized = false;
806
Stephen Hines01f0ad72010-09-28 15:45:45 -0700807 mFontShaderFConstant.clear();
808
Alex Sakhartchouk4a36b452011-04-29 16:49:08 -0700809 mMesh.clear();
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700810
811 mFontShaderF.clear();
812 mFontSampler.clear();
813 mFontProgramStore.clear();
814
815 mTextTexture.clear();
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800816 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700817 delete mCacheLines[i];
818 }
819 mCacheLines.clear();
820
821 mDefault.clear();
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700822#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800823 if (mLibrary) {
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700824 FT_Done_FreeType( mLibrary );
Alex Sakhartchoukb6b34892010-06-30 16:53:43 -0700825 mLibrary = NULL;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700826 }
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700827#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700828}
829
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700830#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukebd65bb2011-02-25 09:34:33 -0800831bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
832 if ((uint32_t)bitmap->rows > mMaxHeight) {
833 return false;
834 }
835
836 if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
837 *retOriginX = mCurrentCol;
838 *retOriginY = mCurrentRow;
839 mCurrentCol += bitmap->width;
840 mDirty = true;
841 return true;
842 }
843
844 return false;
845}
Alex Sakhartchouk17a8a192011-06-03 10:18:01 -0700846#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukebd65bb2011-02-25 09:34:33 -0800847
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700848namespace android {
849namespace renderscript {
850
Alex Sakhartchouke7c4a752011-04-06 10:57:51 -0700851RsFont rsi_FontCreateFromFile(Context *rsc,
852 char const *name, size_t name_length,
853 float fontSize, uint32_t dpi) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700854 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchouked9f2102010-11-09 17:00:54 -0800855 if (newFont) {
Alex Sakhartchouk071508d2010-06-30 12:49:27 -0700856 newFont->incUserRef();
857 }
858 return newFont;
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700859}
860
Alex Sakhartchouke7c4a752011-04-06 10:57:51 -0700861RsFont rsi_FontCreateFromMemory(Context *rsc,
862 char const *name, size_t name_length,
863 float fontSize, uint32_t dpi,
864 const void *data, size_t data_length) {
865 Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
Alex Sakhartchoukb0253ea2011-01-07 11:12:08 -0800866 if (newFont) {
867 newFont->incUserRef();
868 }
869 return newFont;
870}
871
Alex Sakhartchouk9b949fc2010-06-24 17:15:34 -0700872} // renderscript
873} // android