blob: 8b38fdee85572288920d357f8b7b5a688e558e24 [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
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070018#include "rsContext.h"
Alex Sakhartchouke23d2392012-03-09 09:24:39 -080019#include "rs.h"
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070020#include "rsFont.h"
21#include "rsProgramFragment.h"
Alex Sakhartchouk4edf0302012-03-09 10:47:27 -080022#include "rsMesh.h"
Nick Kralevich7e85ca22013-05-22 15:04:39 -070023#ifdef HAVE_ANDROID_OS
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -070024#include <cutils/properties.h>
Nick Kralevich7e85ca22013-05-22 15:04:39 -070025#endif
Alex Sakhartchouk02000b32011-02-25 09:34:33 -080026
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -070027#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouk02000b32011-02-25 09:34:33 -080028#include <ft2build.h>
29#include FT_FREETYPE_H
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070030#include FT_BITMAP_H
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -070031#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070032
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070033using namespace android;
34using namespace android::renderscript;
35
Yang Nib8353c52015-02-14 18:00:59 -080036Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070037 mInitialized = false;
38 mHasKerning = false;
Chris Wailes44bef6f2014-08-12 13:51:10 -070039 mFace = nullptr;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070040}
41
Alex Sakhartchouk5224a272011-01-07 11:12:08 -080042bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -070043#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080044 if (mInitialized) {
Steve Blockaf12ac62012-01-06 19:20:56 +000045 ALOGE("Reinitialization of fonts not supported");
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070046 return false;
47 }
48
Alex Sakhartchouk5224a272011-01-07 11:12:08 -080049 FT_Error error = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -070050 if (data != nullptr && dataLen > 0) {
Alex Sakhartchouk5224a272011-01-07 11:12:08 -080051 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) {
Steve Blockaf12ac62012-01-06 19:20:56 +000057 ALOGE("Unable to initialize font %s", name);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070058 return false;
59 }
60
Jason Sams48ecf6a2013-07-09 15:35:29 -070061 mFontName = rsuCopyString(name);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070062 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) {
Steve Blockaf12ac62012-01-06 19:20:56 +000067 ALOGE("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;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -070074#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070075 return true;
76}
77
Jason Sams2e8665d2011-01-27 00:14:13 -080078void Font::preDestroy() const {
Yang Nib8353c52015-02-14 18:00:59 -080079 for (uint32_t ct = 0; ct < mRSC->mStateFont.mActiveFonts.size(); ct++) {
80 if (mRSC->mStateFont.mActiveFonts[ct] == this) {
81 mRSC->mStateFont.mActiveFonts.removeAt(ct);
82 break;
Jason Sams2e8665d2011-01-27 00:14:13 -080083 }
84 }
85}
86
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080087void Font::invalidateTextureCache() {
88 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Yang Nib8353c52015-02-14 18:00:59 -080089 mCachedGlyphs.valueAt(i)->mIsValid = false;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070090 }
91}
92
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080093void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070094 FontState *state = &mRSC->mStateFont;
95
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070096 int32_t nPenX = x + glyph->mBitmapLeft;
97 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070098
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070099 float u1 = glyph->mBitmapMinU;
100 float u2 = glyph->mBitmapMaxU;
101 float v1 = glyph->mBitmapMinV;
102 float v2 = glyph->mBitmapMaxV;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700103
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700104 int32_t width = (int32_t) glyph->mBitmapWidth;
105 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700106
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700107 state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
108 nPenX + width, nPenY, 0, u2, v2,
109 nPenX + width, nPenY - height, 0, u2, v1,
110 nPenX, nPenY - height, 0, u1, v1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700111}
112
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700113void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
114 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
115 int32_t nPenX = x + glyph->mBitmapLeft;
116 int32_t nPenY = y + glyph->mBitmapTop;
117
118 uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
119 uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
120
121 FontState *state = &mRSC->mStateFont;
122 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
Jason Samsa6dd8232012-07-25 19:33:43 -0700123 const uint8_t* cacheBuffer = state->mCacheBuffer;
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700124
125 uint32_t cacheX = 0, cacheY = 0;
126 int32_t bX = 0, bY = 0;
127 for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
128 for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
129 if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000130 ALOGE("Skipping invalid index");
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700131 continue;
132 }
133 uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
134 bitmap[bY * bitmapW + bX] = tempCol;
135 }
136 }
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700137}
138
139void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
140 int32_t nPenX = x + glyph->mBitmapLeft;
141 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
142
143 int32_t width = (int32_t) glyph->mBitmapWidth;
144 int32_t height = (int32_t) glyph->mBitmapHeight;
145
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800146 // 0, 0 is top left, so bottom is a positive number
147 if (bounds->bottom < nPenY) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700148 bounds->bottom = nPenY;
149 }
150 if (bounds->left > nPenX) {
151 bounds->left = nPenX;
152 }
153 if (bounds->right < nPenX + width) {
154 bounds->right = nPenX + width;
155 }
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800156 if (bounds->top > nPenY - height) {
157 bounds->top = nPenY - height;
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700158 }
159}
160
161void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
162 uint32_t start, int32_t numGlyphs,
163 RenderMode mode, Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800164 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Chris Wailes44bef6f2014-08-12 13:51:10 -0700165 if (!mInitialized || numGlyphs == 0 || text == nullptr || len == 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700166 return;
167 }
168
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800169 if (mode == Font::MEASURE) {
Chris Wailes44bef6f2014-08-12 13:51:10 -0700170 if (bounds == nullptr) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000171 ALOGE("No return rectangle provided to measure text");
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700172 return;
173 }
174 // Reset min and max of the bounding box to something large
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800175 bounds->set(1e6, -1e6, 1e6, -1e6);
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700176 }
177
178 int32_t penX = x, penY = y;
179 int32_t glyphsLeft = 1;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800180 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700181 glyphsLeft = numGlyphs;
182 }
183
184 size_t index = start;
185 size_t nextIndex = 0;
186
187 while (glyphsLeft > 0) {
188
Kenny Rootc9c38dd2010-11-09 14:37:23 -0800189 int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700190
191 // Reached the end of the string or encountered
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800192 if (utfChar < 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700193 break;
194 }
195
196 // Move to the next character in the array
197 index = nextIndex;
198
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700199 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700200
201 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800202 if (cachedGlyph->mIsValid) {
203 switch (mode) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700204 case FRAMEBUFFER:
205 drawCachedGlyph(cachedGlyph, penX, penY);
206 break;
207 case BITMAP:
208 drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
209 break;
210 case MEASURE:
211 measureCachedGlyph(cachedGlyph, penX, penY, bounds);
212 break;
213 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700214 }
215
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800216 penX += (cachedGlyph->mAdvanceX >> 6);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700217
218 // If we were given a specific number of glyphs, decrement
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800219 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700220 glyphsLeft --;
221 }
222 }
223}
224
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700225Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
226
Yang Nib8353c52015-02-14 18:00:59 -0800227 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700228 if (cachedGlyph == nullptr) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700229 cachedGlyph = cacheGlyph((uint32_t)utfChar);
230 }
231 // Is the glyph still in texture cache?
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800232 if (!cachedGlyph->mIsValid) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700233 updateGlyphCache(cachedGlyph);
234 }
235
236 return cachedGlyph;
237}
238
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800239void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700240#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700241 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800242 if (error) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000243 ALOGE("Couldn't load glyph.");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700244 return;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700245 }
246
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800247 glyph->mAdvanceX = mFace->glyph->advance.x;
248 glyph->mAdvanceY = mFace->glyph->advance.y;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700249 glyph->mBitmapLeft = mFace->glyph->bitmap_left;
250 glyph->mBitmapTop = mFace->glyph->bitmap_top;
251
252 FT_Bitmap *bitmap = &mFace->glyph->bitmap;
253
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700254 // Now copy the bitmap into the cache texture
255 uint32_t startX = 0;
256 uint32_t startY = 0;
257
258 // Let the font state figure out where to put the bitmap
259 FontState *state = &mRSC->mStateFont;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700260 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700261
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800262 if (!glyph->mIsValid) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700263 return;
264 }
265
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700266 uint32_t endX = startX + bitmap->width;
267 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700268
269 glyph->mBitmapMinX = startX;
270 glyph->mBitmapMinY = startY;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700271 glyph->mBitmapWidth = bitmap->width;
272 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700273
274 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
275 uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
276
277 glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
278 glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
279 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
280 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700281#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700282}
283
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800284Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700285 CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
Yang Nib8353c52015-02-14 18:00:59 -0800286 mCachedGlyphs.add(glyph, newGlyph);
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700287#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700288 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
289 newGlyph->mIsValid = false;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700290#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700291 updateGlyphCache(newGlyph);
292
293 return newGlyph;
294}
295
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800296Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
297 const void *data, uint32_t dataLen) {
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700298 rsc->mStateFont.checkInit();
Yang Nib8353c52015-02-14 18:00:59 -0800299 Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700300
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800301 for (uint32_t i = 0; i < activeFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700302 Font *ithFont = activeFonts[i];
Yang Nib8353c52015-02-14 18:00:59 -0800303 if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700304 return ithFont;
305 }
306 }
307
308 Font *newFont = new Font(rsc);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800309 bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800310 if (isInitialized) {
Yang Nib8353c52015-02-14 18:00:59 -0800311 activeFonts.push(newFont);
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700312 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700313 return newFont;
314 }
315
Jason Sams225afd32010-10-21 14:06:55 -0700316 ObjectBase::checkDelete(newFont);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700317 return nullptr;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700318}
319
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800320Font::~Font() {
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700321#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800322 if (mFace) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700323 FT_Done_Face(mFace);
324 }
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700325#endif
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700326
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800327 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Yang Nib8353c52015-02-14 18:00:59 -0800328 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700329 delete glyph;
330 }
331}
332
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800333FontState::FontState() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700334 mInitialized = false;
335 mMaxNumberOfQuads = 1024;
336 mCurrentQuadIndex = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700337 mRSC = nullptr;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700338#ifndef ANDROID_RS_SERIALIZE
Chris Wailes44bef6f2014-08-12 13:51:10 -0700339 mLibrary = nullptr;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700340#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700341
Nick Kralevich7e85ca22013-05-22 15:04:39 -0700342 float gamma = DEFAULT_TEXT_GAMMA;
343 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
344 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
345
346#ifdef HAVE_ANDROID_OS
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700347 // Get the renderer properties
348 char property[PROPERTY_VALUE_MAX];
349
350 // Get the gamma
Chris Wailes44bef6f2014-08-12 13:51:10 -0700351 if (property_get(PROPERTY_TEXT_GAMMA, property, nullptr) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700352 gamma = atof(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700353 }
354
355 // Get the black gamma threshold
Chris Wailes44bef6f2014-08-12 13:51:10 -0700356 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, nullptr) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700357 blackThreshold = atoi(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700358 }
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700359
360 // Get the white gamma threshold
Chris Wailes44bef6f2014-08-12 13:51:10 -0700361 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, nullptr) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700362 whiteThreshold = atoi(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700363 }
Nick Kralevich7e85ca22013-05-22 15:04:39 -0700364#endif
365
366 mBlackThreshold = (float)(blackThreshold) / 255.0f;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700367 mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
368
369 // Compute the gamma tables
370 mBlackGamma = gamma;
371 mWhiteGamma = 1.0f / gamma;
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700372
373 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700374}
375
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800376FontState::~FontState() {
377 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700378 delete mCacheLines[i];
379 }
380
381 rsAssert(!mActiveFonts.size());
382}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700383#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800384FT_Library FontState::getLib() {
385 if (!mLibrary) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700386 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800387 if (error) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000388 ALOGE("Unable to initialize freetype");
Chris Wailes44bef6f2014-08-12 13:51:10 -0700389 return nullptr;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700390 }
391 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700392
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700393 return mLibrary;
394}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700395#endif //ANDROID_RS_SERIALIZE
396
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700397
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800398void FontState::init(Context *rsc) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700399 mRSC = rsc;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700400}
401
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800402void FontState::flushAllAndInvalidate() {
403 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700404 issueDrawCommand();
405 mCurrentQuadIndex = 0;
406 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800407 for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700408 mActiveFonts[i]->invalidateTextureCache();
409 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800410 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700411 mCacheLines[i]->mCurrentCol = 0;
412 }
413}
414
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700415#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800416bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700417 // If the glyph is too tall, don't cache it
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800418 if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000419 ALOGE("Font size to large to fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700420 return false;
421 }
422
423 // Now copy the bitmap into the cache texture
424 uint32_t startX = 0;
425 uint32_t startY = 0;
426
427 bool bitmapFit = false;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800428 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700429 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800430 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700431 break;
432 }
433 }
434
435 // If the new glyph didn't fit, flush the state so far and invalidate everything
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800436 if (!bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700437 flushAllAndInvalidate();
438
439 // Try to fit it again
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800440 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700441 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800442 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700443 break;
444 }
445 }
446
447 // if we still don't fit, something is wrong and we shouldn't draw
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800448 if (!bitmapFit) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000449 ALOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700450 return false;
451 }
452 }
453
454 *retOriginX = startX;
455 *retOriginY = startY;
456
457 uint32_t endX = startX + bitmap->width;
458 uint32_t endY = startY + bitmap->rows;
459
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700460 uint32_t cacheWidth = getCacheTextureType()->getDimX();
461
Jason Samsa6dd8232012-07-25 19:33:43 -0700462 uint8_t *cacheBuffer = mCacheBuffer;
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700463 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700464
465 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800466 for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
467 for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700468 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700469 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
470 }
471 }
472
473 // This will dirty the texture and the shader so next time
474 // we draw it will upload the data
Jason Samseb4fe182011-05-26 16:33:01 -0700475
Jason Samsa6dd8232012-07-25 19:33:43 -0700476 mRSC->mHal.funcs.allocation.data2D(mRSC, mTextTexture.get(), 0, 0, 0,
477 RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, mCacheWidth, mCacheHeight,
Tim Murray358747a2012-11-26 13:52:04 -0800478 mCacheBuffer, mCacheWidth*mCacheHeight, mCacheWidth);
Jason Samsa6dd8232012-07-25 19:33:43 -0700479
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700480 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700481
482 // Some debug code
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800483 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000484 ALOGE("Cache Line: H: %u Empty Space: %f",
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700485 mCacheLines[i]->mMaxHeight,
486 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
487
488 }*/
489
490 return true;
491}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700492#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700493
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800494void FontState::initRenderState() {
Jason Sams48ecf6a2013-07-09 15:35:29 -0700495 const char *shaderString = "varying vec2 varTex0;\n"
496 "void main() {\n"
497 " lowp vec4 col = UNI_Color;\n"
498 " col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n"
499 " col.a = pow(col.a, UNI_Gamma);\n"
500 " gl_FragColor = col;\n"
501 "}\n";
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700502
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800503 const char *textureNames[] = { "Tex0" };
504 const size_t textureNamesLengths[] = { 4 };
505 size_t numTextures = sizeof(textureNamesLengths)/sizeof(*textureNamesLengths);
506
507 ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
508 RS_KIND_USER, false, 4);
509 ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
510 RS_KIND_USER, false, 1);
Jason Samsf313dc32013-07-09 14:29:39 -0700511
512 const char *ebn1[] = { "Color", "Gamma" };
513 const Element *ebe1[] = {colorElem.get(), gammaElem.get()};
514 ObjectBaseRef<const Element> constInput = Element::create(mRSC, 2, ebe1, ebn1);
Jason Samsc7968a02014-11-11 16:24:36 -0800515 ObjectBaseRef<Type> inputType = Type::getTypeRef(mRSC, constInput.get(), 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700516
Ian Rogersf8852d02014-01-29 15:35:17 -0800517 uintptr_t tmp[4];
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700518 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
Ian Rogersf8852d02014-01-29 15:35:17 -0800519 tmp[1] = (uintptr_t)inputType.get();
Alex Sakhartchouk84e40272010-11-18 15:22:43 -0800520 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
521 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700522
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700523 mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800524 RS_ALLOCATION_USAGE_SCRIPT |
525 RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
Jason Sams48ecf6a2013-07-09 15:35:29 -0700526 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString, strlen(shaderString),
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800527 textureNames, numTextures, textureNamesLengths,
528 tmp, 4);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700529 mFontShaderF.set(pf);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700530 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700531
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700532 mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800533 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP,
534 RS_SAMPLER_CLAMP).get());
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700535 mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700536
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700537 mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
538 false, false,
539 RS_BLEND_SRC_SRC_ALPHA,
540 RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
541 RS_DEPTH_FUNC_ALWAYS).get());
Jason Sams8feea4e2011-03-18 15:03:25 -0700542 mFontProgramStore->init();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700543}
544
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800545void FontState::initTextTexture() {
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800546 ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8,
547 RS_KIND_PIXEL_A, true, 1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700548
549 // We will allocate a texture to initially hold 32 character bitmaps
Jason Samsa6dd8232012-07-25 19:33:43 -0700550 mCacheHeight = 256;
551 mCacheWidth = 1024;
Jason Samsc7968a02014-11-11 16:24:36 -0800552 ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(), mCacheWidth, mCacheHeight);
Chris Wailes93d6bc82014-07-28 16:54:38 -0700553
Jason Samsa6dd8232012-07-25 19:33:43 -0700554 mCacheBuffer = new uint8_t[mCacheWidth * mCacheHeight];
555
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700556
Yang Nib8353c52015-02-14 18:00:59 -0800557 Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(),
558 RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700559 mTextTexture.set(cacheAlloc);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700560
561 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700562 int32_t nextLine = 0;
Yang Nib8353c52015-02-14 18:00:59 -0800563 mCacheLines.push(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
564 nextLine += mCacheLines.top()->mMaxHeight;
565 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
566 nextLine += mCacheLines.top()->mMaxHeight;
567 mCacheLines.push(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
568 nextLine += mCacheLines.top()->mMaxHeight;
569 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
570 nextLine += mCacheLines.top()->mMaxHeight;
571 mCacheLines.push(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
572 nextLine += mCacheLines.top()->mMaxHeight;
573 mCacheLines.push(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
574 nextLine += mCacheLines.top()->mMaxHeight;
575 mCacheLines.push(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700576}
577
578// Avoid having to reallocate memory and render quad by quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800579void FontState::initVertexArrayBuffers() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700580 // Now lets write index data
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700581 ObjectBaseRef<const Element> indexElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
Jason Samsc7968a02014-11-11 16:24:36 -0800582 ObjectBaseRef<Type> indexType = Type::getTypeRef(mRSC, indexElem.get(), mMaxNumberOfQuads * 6);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700583
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700584 Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType.get(),
Jason Samseb4fe182011-05-26 16:33:01 -0700585 RS_ALLOCATION_USAGE_SCRIPT |
586 RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Jason Samsa6dd8232012-07-25 19:33:43 -0700587 uint16_t *indexPtr = (uint16_t*)mRSC->mHal.funcs.allocation.lock1D(mRSC, indexAlloc);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700588
589 // Four verts, two triangles , six indices per quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800590 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700591 int32_t i6 = i * 6;
592 int32_t i4 = i * 4;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700593
594 indexPtr[i6 + 0] = i4 + 0;
595 indexPtr[i6 + 1] = i4 + 1;
596 indexPtr[i6 + 2] = i4 + 2;
597
598 indexPtr[i6 + 3] = i4 + 0;
599 indexPtr[i6 + 4] = i4 + 2;
600 indexPtr[i6 + 5] = i4 + 3;
601 }
602
Jason Samseb4fe182011-05-26 16:33:01 -0700603 indexAlloc->sendDirty(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700604
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700605 ObjectBaseRef<const Element> posElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
606 ObjectBaseRef<const Element> texElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700607
Jason Samsf313dc32013-07-09 14:29:39 -0700608 const char *ebn1[] = { "position", "texture0" };
609 const Element *ebe1[] = {posElem.get(), texElem.get()};
610 ObjectBaseRef<const Element> vertexDataElem = Element::create(mRSC, 2, ebe1, ebn1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700611
Jason Samsc7968a02014-11-11 16:24:36 -0800612 ObjectBaseRef<Type> vertexDataType = Type::getTypeRef(mRSC, vertexDataElem.get(), mMaxNumberOfQuads * 4);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700613
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700614 Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType.get(),
Jason Samseb4fe182011-05-26 16:33:01 -0700615 RS_ALLOCATION_USAGE_SCRIPT);
Jason Samsa6dd8232012-07-25 19:33:43 -0700616 mTextMeshPtr = (float*)mRSC->mHal.funcs.allocation.lock1D(mRSC, vertexAlloc);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700617
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700618 mMesh.set(new Mesh(mRSC, 1, 1));
619 mMesh->setVertexBuffer(vertexAlloc, 0);
620 mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
621 mMesh->init();
Jason Samsa6dd8232012-07-25 19:33:43 -0700622 mRSC->mHal.funcs.allocation.unlock1D(mRSC, indexAlloc);
623 mRSC->mHal.funcs.allocation.unlock1D(mRSC, vertexAlloc);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700624}
625
626// We don't want to allocate anything unless we actually draw text
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800627void FontState::checkInit() {
628 if (mInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700629 return;
630 }
631
632 initTextTexture();
633 initRenderState();
634
635 initVertexArrayBuffers();
636
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700637 // We store a string with letters in a rough frequency of occurrence
Jason Samsa7f5e042013-07-08 16:46:18 -0700638 mLatinPrecache = " eisarntolcdugpmhbyfvkwzxjq"
639 "EISARNTOLCDUGPMHBYFVKWZXJQ"
640 ",.?!()-+@;:`'0123456789";
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700641 mInitialized = true;
642}
643
644void FontState::issueDrawCommand() {
Jason Sams60709252010-11-17 15:29:32 -0800645 Context::PushState ps(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700646
Jason Sams60709252010-11-17 15:29:32 -0800647 mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
648 mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
649 mRSC->setProgramFragment(mFontShaderF.get());
650 mRSC->setProgramStore(mFontProgramStore.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700651
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800652 if (mConstantsDirty) {
Jason Sams4b45b892010-12-29 14:31:29 -0800653 mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700654 mConstantsDirty = false;
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700655 }
656
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700657 if (!mRSC->setupCheck()) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700658 return;
659 }
660
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700661 mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700662}
663
664void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800665 float u1, float v1,
666 float x2, float y2, float z2,
667 float u2, float v2,
668 float x3, float y3, float z3,
669 float u3, float v3,
670 float x4, float y4, float z4,
671 float u4, float v4) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700672 const uint32_t vertsPerQuad = 4;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800673 const uint32_t floatsPerVert = 6;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700674 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
675
Alex Sakhartchouka74a8f62011-11-16 12:22:10 -0800676 if (x1 > mSurfaceWidth || y1 < 0.0f || x2 < 0 || y4 > mSurfaceHeight) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700677 return;
678 }
679
680 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
Steve Blockaf12ac62012-01-06 19:20:56 +0000681 ALOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
682 ALOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
683 ALOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700684
685 (*currentPos++) = x1;
686 (*currentPos++) = y1;
687 (*currentPos++) = z1;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800688 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700689 (*currentPos++) = u1;
690 (*currentPos++) = v1;
691
692 (*currentPos++) = x2;
693 (*currentPos++) = y2;
694 (*currentPos++) = z2;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800695 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700696 (*currentPos++) = u2;
697 (*currentPos++) = v2;
698
699 (*currentPos++) = x3;
700 (*currentPos++) = y3;
701 (*currentPos++) = z3;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800702 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700703 (*currentPos++) = u3;
704 (*currentPos++) = v3;
705
706 (*currentPos++) = x4;
707 (*currentPos++) = y4;
708 (*currentPos++) = z4;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800709 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700710 (*currentPos++) = u4;
711 (*currentPos++) = v4;
712
713 mCurrentQuadIndex ++;
714
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800715 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700716 issueDrawCommand();
717 mCurrentQuadIndex = 0;
718 }
719}
720
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700721uint32_t FontState::getRemainingCacheCapacity() {
722 uint32_t remainingCapacity = 0;
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700723 uint32_t totalPixels = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800724 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700725 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
726 totalPixels += mCacheLines[i]->mMaxWidth;
727 }
728 remainingCapacity = (remainingCapacity * 100) / totalPixels;
729 return remainingCapacity;
730}
731
732void FontState::precacheLatin(Font *font) {
733 // Remaining capacity is measured in %
734 uint32_t remainingCapacity = getRemainingCacheCapacity();
735 uint32_t precacheIdx = 0;
Jason Samsa7f5e042013-07-08 16:46:18 -0700736 const size_t l = strlen(mLatinPrecache);
737 while ((remainingCapacity > 25) && (precacheIdx < l)) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700738 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
739 remainingCapacity = getRemainingCacheCapacity();
740 precacheIdx ++;
741 }
742}
743
744
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700745void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
746 uint32_t startIndex, int32_t numGlyphs,
747 Font::RenderMode mode,
748 Font::Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800749 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700750 checkInit();
751
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700752 // Render code here
753 Font *currentFont = mRSC->getFont();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800754 if (!currentFont) {
755 if (!mDefault.get()) {
Jason Sams48ecf6a2013-07-09 15:35:29 -0700756 char fullPath[1024];
757 const char * root = getenv("ANDROID_ROOT");
758 rsAssert(strlen(root) < 256);
759 strcpy(fullPath, root);
760 strcat(fullPath, "/fonts/Roboto-Regular.ttf");
761 mDefault.set(Font::create(mRSC, fullPath, 8, mRSC->getDPI()));
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700762 }
763 currentFont = mDefault.get();
764 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800765 if (!currentFont) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000766 ALOGE("Unable to initialize any fonts");
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700767 return;
768 }
769
Alex Sakhartchouka74a8f62011-11-16 12:22:10 -0800770 // Cull things that are off the screen
771 mSurfaceWidth = (float)mRSC->getCurrentSurfaceWidth();
772 mSurfaceHeight = (float)mRSC->getCurrentSurfaceHeight();
773
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700774 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
775 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700776
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800777 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700778 issueDrawCommand();
779 mCurrentQuadIndex = 0;
780 }
781}
782
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700783void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
784 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800785 bounds->bottom = - bounds->bottom;
786 bounds->top = - bounds->top;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700787}
788
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700789void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700790 mConstants.mFontColor[0] = r;
791 mConstants.mFontColor[1] = g;
792 mConstants.mFontColor[2] = b;
793 mConstants.mFontColor[3] = a;
794
795 mConstants.mGamma = 1.0f;
Alex Sakhartchoukc8fb69e2010-10-05 13:23:55 -0700796 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700797 if (luminance <= mBlackThreshold) {
798 mConstants.mGamma = mBlackGamma;
799 } else if (luminance >= mWhiteThreshold) {
800 mConstants.mGamma = mWhiteGamma;
801 }
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700802
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700803 mConstantsDirty = true;
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700804}
805
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700806void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700807 *r = mConstants.mFontColor[0];
808 *g = mConstants.mFontColor[1];
809 *b = mConstants.mFontColor[2];
810 *a = mConstants.mFontColor[3];
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700811}
812
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800813void FontState::deinit(Context *rsc) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700814 mInitialized = false;
815
Stephen Hines01b7d292010-09-28 15:45:45 -0700816 mFontShaderFConstant.clear();
817
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700818 mMesh.clear();
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700819
820 mFontShaderF.clear();
821 mFontSampler.clear();
822 mFontProgramStore.clear();
823
824 mTextTexture.clear();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800825 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700826 delete mCacheLines[i];
827 }
828 mCacheLines.clear();
829
830 mDefault.clear();
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700831#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800832 if (mLibrary) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700833 FT_Done_FreeType( mLibrary );
Chris Wailes44bef6f2014-08-12 13:51:10 -0700834 mLibrary = nullptr;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700835 }
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700836#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700837}
838
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700839#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800840bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
841 if ((uint32_t)bitmap->rows > mMaxHeight) {
842 return false;
843 }
844
845 if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
846 *retOriginX = mCurrentCol;
847 *retOriginY = mCurrentRow;
848 mCurrentCol += bitmap->width;
849 mDirty = true;
850 return true;
851 }
852
853 return false;
854}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700855#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800856
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700857namespace android {
858namespace renderscript {
859
Alex Sakhartchouk70b83c12011-04-06 10:57:51 -0700860RsFont rsi_FontCreateFromFile(Context *rsc,
861 char const *name, size_t name_length,
862 float fontSize, uint32_t dpi) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700863 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800864 if (newFont) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700865 newFont->incUserRef();
866 }
867 return newFont;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700868}
869
Alex Sakhartchouk70b83c12011-04-06 10:57:51 -0700870RsFont rsi_FontCreateFromMemory(Context *rsc,
871 char const *name, size_t name_length,
872 float fontSize, uint32_t dpi,
873 const void *data, size_t data_length) {
874 Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800875 if (newFont) {
876 newFont->incUserRef();
877 }
878 return newFont;
879}
880
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700881} // renderscript
882} // android