blob: 2f093849d69d5127aca4efb60144248f8704df01 [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
Chris Wailes93d6bc82014-07-28 16:54:38 -070036Font::Font(Context *rsc) : ObjectBase(rsc) {
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 {
Chris Wailes93d6bc82014-07-28 16:54:38 -070079 auto &activeFonts = mRSC->mStateFont.mActiveFonts;
80
81 for (auto font = activeFonts.begin(), end = activeFonts.end(); font != end;
82 font++) {
83
84 if (this == *font) {
85 activeFonts.erase(font);
86 return;
Jason Sams2e8665d2011-01-27 00:14:13 -080087 }
88 }
89}
90
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080091void Font::invalidateTextureCache() {
92 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Chris Wailes93d6bc82014-07-28 16:54:38 -070093 mCachedGlyphs[i]->mIsValid = false;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070094 }
95}
96
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080097void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070098 FontState *state = &mRSC->mStateFont;
99
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700100 int32_t nPenX = x + glyph->mBitmapLeft;
101 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700102
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700103 float u1 = glyph->mBitmapMinU;
104 float u2 = glyph->mBitmapMaxU;
105 float v1 = glyph->mBitmapMinV;
106 float v2 = glyph->mBitmapMaxV;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700107
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700108 int32_t width = (int32_t) glyph->mBitmapWidth;
109 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700110
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700111 state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
112 nPenX + width, nPenY, 0, u2, v2,
113 nPenX + width, nPenY - height, 0, u2, v1,
114 nPenX, nPenY - height, 0, u1, v1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700115}
116
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700117void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
118 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
119 int32_t nPenX = x + glyph->mBitmapLeft;
120 int32_t nPenY = y + glyph->mBitmapTop;
121
122 uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
123 uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
124
125 FontState *state = &mRSC->mStateFont;
126 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
Jason Samsa6dd8232012-07-25 19:33:43 -0700127 const uint8_t* cacheBuffer = state->mCacheBuffer;
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700128
129 uint32_t cacheX = 0, cacheY = 0;
130 int32_t bX = 0, bY = 0;
131 for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
132 for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
133 if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000134 ALOGE("Skipping invalid index");
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700135 continue;
136 }
137 uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
138 bitmap[bY * bitmapW + bX] = tempCol;
139 }
140 }
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700141}
142
143void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
144 int32_t nPenX = x + glyph->mBitmapLeft;
145 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
146
147 int32_t width = (int32_t) glyph->mBitmapWidth;
148 int32_t height = (int32_t) glyph->mBitmapHeight;
149
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800150 // 0, 0 is top left, so bottom is a positive number
151 if (bounds->bottom < nPenY) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700152 bounds->bottom = nPenY;
153 }
154 if (bounds->left > nPenX) {
155 bounds->left = nPenX;
156 }
157 if (bounds->right < nPenX + width) {
158 bounds->right = nPenX + width;
159 }
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800160 if (bounds->top > nPenY - height) {
161 bounds->top = nPenY - height;
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700162 }
163}
164
165void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
166 uint32_t start, int32_t numGlyphs,
167 RenderMode mode, Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800168 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Chris Wailes44bef6f2014-08-12 13:51:10 -0700169 if (!mInitialized || numGlyphs == 0 || text == nullptr || len == 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700170 return;
171 }
172
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800173 if (mode == Font::MEASURE) {
Chris Wailes44bef6f2014-08-12 13:51:10 -0700174 if (bounds == nullptr) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000175 ALOGE("No return rectangle provided to measure text");
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700176 return;
177 }
178 // Reset min and max of the bounding box to something large
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800179 bounds->set(1e6, -1e6, 1e6, -1e6);
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700180 }
181
182 int32_t penX = x, penY = y;
183 int32_t glyphsLeft = 1;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800184 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700185 glyphsLeft = numGlyphs;
186 }
187
188 size_t index = start;
189 size_t nextIndex = 0;
190
191 while (glyphsLeft > 0) {
192
Kenny Rootc9c38dd2010-11-09 14:37:23 -0800193 int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700194
195 // Reached the end of the string or encountered
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800196 if (utfChar < 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700197 break;
198 }
199
200 // Move to the next character in the array
201 index = nextIndex;
202
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700203 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700204
205 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800206 if (cachedGlyph->mIsValid) {
207 switch (mode) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700208 case FRAMEBUFFER:
209 drawCachedGlyph(cachedGlyph, penX, penY);
210 break;
211 case BITMAP:
212 drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
213 break;
214 case MEASURE:
215 measureCachedGlyph(cachedGlyph, penX, penY, bounds);
216 break;
217 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700218 }
219
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800220 penX += (cachedGlyph->mAdvanceX >> 6);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700221
222 // If we were given a specific number of glyphs, decrement
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800223 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700224 glyphsLeft --;
225 }
226 }
227}
228
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700229Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
230
Chris Wailes93d6bc82014-07-28 16:54:38 -0700231 CachedGlyphInfo *cachedGlyph = mCachedGlyphs[(uint32_t)utfChar];
Chris Wailes44bef6f2014-08-12 13:51:10 -0700232 if (cachedGlyph == nullptr) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700233 cachedGlyph = cacheGlyph((uint32_t)utfChar);
234 }
235 // Is the glyph still in texture cache?
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800236 if (!cachedGlyph->mIsValid) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700237 updateGlyphCache(cachedGlyph);
238 }
239
240 return cachedGlyph;
241}
242
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800243void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700244#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700245 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800246 if (error) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000247 ALOGE("Couldn't load glyph.");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700248 return;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700249 }
250
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800251 glyph->mAdvanceX = mFace->glyph->advance.x;
252 glyph->mAdvanceY = mFace->glyph->advance.y;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700253 glyph->mBitmapLeft = mFace->glyph->bitmap_left;
254 glyph->mBitmapTop = mFace->glyph->bitmap_top;
255
256 FT_Bitmap *bitmap = &mFace->glyph->bitmap;
257
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700258 // Now copy the bitmap into the cache texture
259 uint32_t startX = 0;
260 uint32_t startY = 0;
261
262 // Let the font state figure out where to put the bitmap
263 FontState *state = &mRSC->mStateFont;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700264 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700265
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800266 if (!glyph->mIsValid) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700267 return;
268 }
269
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700270 uint32_t endX = startX + bitmap->width;
271 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700272
273 glyph->mBitmapMinX = startX;
274 glyph->mBitmapMinY = startY;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700275 glyph->mBitmapWidth = bitmap->width;
276 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700277
278 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
279 uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
280
281 glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
282 glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
283 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
284 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700285#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700286}
287
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800288Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700289 CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
Chris Wailes93d6bc82014-07-28 16:54:38 -0700290 mCachedGlyphs[glyph] = newGlyph;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700291#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700292 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
293 newGlyph->mIsValid = false;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700294#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700295 updateGlyphCache(newGlyph);
296
297 return newGlyph;
298}
299
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800300Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
301 const void *data, uint32_t dataLen) {
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700302 rsc->mStateFont.checkInit();
Chris Wailes93d6bc82014-07-28 16:54:38 -0700303 std::vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700304
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800305 for (uint32_t i = 0; i < activeFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700306 Font *ithFont = activeFonts[i];
Chris Wailes93d6bc82014-07-28 16:54:38 -0700307 if (ithFont->mFontName == name &&
308 ithFont->mFontSize == fontSize &&
309 ithFont->mDpi == dpi) {
310
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700311 return ithFont;
312 }
313 }
314
315 Font *newFont = new Font(rsc);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800316 bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800317 if (isInitialized) {
Chris Wailes93d6bc82014-07-28 16:54:38 -0700318 activeFonts.push_back(newFont);
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700319 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700320 return newFont;
321 }
322
Jason Sams225afd32010-10-21 14:06:55 -0700323 ObjectBase::checkDelete(newFont);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700324 return nullptr;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700325}
326
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800327Font::~Font() {
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700328#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800329 if (mFace) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700330 FT_Done_Face(mFace);
331 }
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700332#endif
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700333
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800334 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Chris Wailes93d6bc82014-07-28 16:54:38 -0700335 CachedGlyphInfo *glyph = mCachedGlyphs[i];
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700336 delete glyph;
337 }
338}
339
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800340FontState::FontState() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700341 mInitialized = false;
342 mMaxNumberOfQuads = 1024;
343 mCurrentQuadIndex = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700344 mRSC = nullptr;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700345#ifndef ANDROID_RS_SERIALIZE
Chris Wailes44bef6f2014-08-12 13:51:10 -0700346 mLibrary = nullptr;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700347#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700348
Nick Kralevich7e85ca22013-05-22 15:04:39 -0700349 float gamma = DEFAULT_TEXT_GAMMA;
350 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
351 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
352
353#ifdef HAVE_ANDROID_OS
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700354 // Get the renderer properties
355 char property[PROPERTY_VALUE_MAX];
356
357 // Get the gamma
Chris Wailes44bef6f2014-08-12 13:51:10 -0700358 if (property_get(PROPERTY_TEXT_GAMMA, property, nullptr) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700359 gamma = atof(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700360 }
361
362 // Get the black gamma threshold
Chris Wailes44bef6f2014-08-12 13:51:10 -0700363 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, nullptr) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700364 blackThreshold = atoi(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700365 }
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700366
367 // Get the white gamma threshold
Chris Wailes44bef6f2014-08-12 13:51:10 -0700368 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, nullptr) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700369 whiteThreshold = atoi(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700370 }
Nick Kralevich7e85ca22013-05-22 15:04:39 -0700371#endif
372
373 mBlackThreshold = (float)(blackThreshold) / 255.0f;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700374 mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
375
376 // Compute the gamma tables
377 mBlackGamma = gamma;
378 mWhiteGamma = 1.0f / gamma;
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700379
380 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700381}
382
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800383FontState::~FontState() {
384 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700385 delete mCacheLines[i];
386 }
387
388 rsAssert(!mActiveFonts.size());
389}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700390#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800391FT_Library FontState::getLib() {
392 if (!mLibrary) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700393 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800394 if (error) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000395 ALOGE("Unable to initialize freetype");
Chris Wailes44bef6f2014-08-12 13:51:10 -0700396 return nullptr;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700397 }
398 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700399
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700400 return mLibrary;
401}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700402#endif //ANDROID_RS_SERIALIZE
403
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700404
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800405void FontState::init(Context *rsc) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700406 mRSC = rsc;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700407}
408
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800409void FontState::flushAllAndInvalidate() {
410 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700411 issueDrawCommand();
412 mCurrentQuadIndex = 0;
413 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800414 for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700415 mActiveFonts[i]->invalidateTextureCache();
416 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800417 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700418 mCacheLines[i]->mCurrentCol = 0;
419 }
420}
421
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700422#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800423bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700424 // If the glyph is too tall, don't cache it
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800425 if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000426 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 -0700427 return false;
428 }
429
430 // Now copy the bitmap into the cache texture
431 uint32_t startX = 0;
432 uint32_t startY = 0;
433
434 bool bitmapFit = false;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800435 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700436 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800437 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700438 break;
439 }
440 }
441
442 // If the new glyph didn't fit, flush the state so far and invalidate everything
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800443 if (!bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700444 flushAllAndInvalidate();
445
446 // Try to fit it again
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800447 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700448 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800449 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700450 break;
451 }
452 }
453
454 // if we still don't fit, something is wrong and we shouldn't draw
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800455 if (!bitmapFit) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000456 ALOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700457 return false;
458 }
459 }
460
461 *retOriginX = startX;
462 *retOriginY = startY;
463
464 uint32_t endX = startX + bitmap->width;
465 uint32_t endY = startY + bitmap->rows;
466
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700467 uint32_t cacheWidth = getCacheTextureType()->getDimX();
468
Jason Samsa6dd8232012-07-25 19:33:43 -0700469 uint8_t *cacheBuffer = mCacheBuffer;
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700470 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700471
472 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800473 for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
474 for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700475 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700476 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
477 }
478 }
479
480 // This will dirty the texture and the shader so next time
481 // we draw it will upload the data
Jason Samseb4fe182011-05-26 16:33:01 -0700482
Jason Samsa6dd8232012-07-25 19:33:43 -0700483 mRSC->mHal.funcs.allocation.data2D(mRSC, mTextTexture.get(), 0, 0, 0,
484 RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, mCacheWidth, mCacheHeight,
Tim Murray358747a2012-11-26 13:52:04 -0800485 mCacheBuffer, mCacheWidth*mCacheHeight, mCacheWidth);
Jason Samsa6dd8232012-07-25 19:33:43 -0700486
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700487 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700488
489 // Some debug code
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800490 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000491 ALOGE("Cache Line: H: %u Empty Space: %f",
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700492 mCacheLines[i]->mMaxHeight,
493 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
494
495 }*/
496
497 return true;
498}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700499#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700500
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800501void FontState::initRenderState() {
Jason Sams48ecf6a2013-07-09 15:35:29 -0700502 const char *shaderString = "varying vec2 varTex0;\n"
503 "void main() {\n"
504 " lowp vec4 col = UNI_Color;\n"
505 " col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n"
506 " col.a = pow(col.a, UNI_Gamma);\n"
507 " gl_FragColor = col;\n"
508 "}\n";
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700509
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800510 const char *textureNames[] = { "Tex0" };
511 const size_t textureNamesLengths[] = { 4 };
512 size_t numTextures = sizeof(textureNamesLengths)/sizeof(*textureNamesLengths);
513
514 ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
515 RS_KIND_USER, false, 4);
516 ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
517 RS_KIND_USER, false, 1);
Jason Samsf313dc32013-07-09 14:29:39 -0700518
519 const char *ebn1[] = { "Color", "Gamma" };
520 const Element *ebe1[] = {colorElem.get(), gammaElem.get()};
521 ObjectBaseRef<const Element> constInput = Element::create(mRSC, 2, ebe1, ebn1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700522
Jason Samsa572aca2013-01-09 11:52:26 -0800523 ObjectBaseRef<Type> inputType = Type::getTypeRef(mRSC, constInput.get(), 1, 0, 0, false, false, 0);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700524
Ian Rogersf8852d02014-01-29 15:35:17 -0800525 uintptr_t tmp[4];
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700526 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
Ian Rogersf8852d02014-01-29 15:35:17 -0800527 tmp[1] = (uintptr_t)inputType.get();
Alex Sakhartchouk84e40272010-11-18 15:22:43 -0800528 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
529 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700530
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700531 mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800532 RS_ALLOCATION_USAGE_SCRIPT |
533 RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
Jason Sams48ecf6a2013-07-09 15:35:29 -0700534 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString, strlen(shaderString),
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800535 textureNames, numTextures, textureNamesLengths,
536 tmp, 4);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700537 mFontShaderF.set(pf);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700538 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700539
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700540 mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800541 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP,
542 RS_SAMPLER_CLAMP).get());
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700543 mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700544
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700545 mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
546 false, false,
547 RS_BLEND_SRC_SRC_ALPHA,
548 RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
549 RS_DEPTH_FUNC_ALWAYS).get());
Jason Sams8feea4e2011-03-18 15:03:25 -0700550 mFontProgramStore->init();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700551}
552
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800553void FontState::initTextTexture() {
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800554 ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8,
555 RS_KIND_PIXEL_A, true, 1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700556
557 // We will allocate a texture to initially hold 32 character bitmaps
Jason Samsa6dd8232012-07-25 19:33:43 -0700558 mCacheHeight = 256;
559 mCacheWidth = 1024;
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800560 ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(),
Chris Wailes93d6bc82014-07-28 16:54:38 -0700561 mCacheWidth, mCacheHeight,
562 0, false, false, 0);
563
Jason Samsa6dd8232012-07-25 19:33:43 -0700564 mCacheBuffer = new uint8_t[mCacheWidth * mCacheHeight];
565
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700566
Chris Wailes93d6bc82014-07-28 16:54:38 -0700567 Allocation *cacheAlloc =
568 Allocation::createAllocation(mRSC, texType.get(),
569 RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700570 mTextTexture.set(cacheAlloc);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700571
572 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700573 int32_t nextLine = 0;
Chris Wailes93d6bc82014-07-28 16:54:38 -0700574 mCacheLines.push_back(new CacheTextureLine(16, texType->getDimX(),
575 nextLine, 0));
576 nextLine += mCacheLines.back()->mMaxHeight;
577 mCacheLines.push_back(new CacheTextureLine(24, texType->getDimX(),
578 nextLine, 0));
579 nextLine += mCacheLines.back()->mMaxHeight;
580 mCacheLines.push_back(new CacheTextureLine(24, texType->getDimX(),
581 nextLine, 0));
582 nextLine += mCacheLines.back()->mMaxHeight;
583 mCacheLines.push_back(new CacheTextureLine(32, texType->getDimX(),
584 nextLine, 0));
585 nextLine += mCacheLines.back()->mMaxHeight;
586 mCacheLines.push_back(new CacheTextureLine(32, texType->getDimX(),
587 nextLine, 0));
588 nextLine += mCacheLines.back()->mMaxHeight;
589 mCacheLines.push_back(new CacheTextureLine(40, texType->getDimX(),
590 nextLine, 0));
591 nextLine += mCacheLines.back()->mMaxHeight;
592 mCacheLines.push_back(new CacheTextureLine(texType->getDimY() - nextLine,
593 texType->getDimX(), nextLine, 0));
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700594}
595
596// Avoid having to reallocate memory and render quad by quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800597void FontState::initVertexArrayBuffers() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700598 // Now lets write index data
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700599 ObjectBaseRef<const Element> indexElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700600 uint32_t numIndicies = mMaxNumberOfQuads * 6;
Jason Samsa572aca2013-01-09 11:52:26 -0800601 ObjectBaseRef<Type> indexType = Type::getTypeRef(mRSC, indexElem.get(), numIndicies, 0, 0, false, false, 0);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700602
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700603 Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType.get(),
Jason Samseb4fe182011-05-26 16:33:01 -0700604 RS_ALLOCATION_USAGE_SCRIPT |
605 RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Jason Samsa6dd8232012-07-25 19:33:43 -0700606 uint16_t *indexPtr = (uint16_t*)mRSC->mHal.funcs.allocation.lock1D(mRSC, indexAlloc);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700607
608 // Four verts, two triangles , six indices per quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800609 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700610 int32_t i6 = i * 6;
611 int32_t i4 = i * 4;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700612
613 indexPtr[i6 + 0] = i4 + 0;
614 indexPtr[i6 + 1] = i4 + 1;
615 indexPtr[i6 + 2] = i4 + 2;
616
617 indexPtr[i6 + 3] = i4 + 0;
618 indexPtr[i6 + 4] = i4 + 2;
619 indexPtr[i6 + 5] = i4 + 3;
620 }
621
Jason Samseb4fe182011-05-26 16:33:01 -0700622 indexAlloc->sendDirty(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700623
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700624 ObjectBaseRef<const Element> posElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
625 ObjectBaseRef<const Element> texElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700626
Jason Samsf313dc32013-07-09 14:29:39 -0700627 const char *ebn1[] = { "position", "texture0" };
628 const Element *ebe1[] = {posElem.get(), texElem.get()};
629 ObjectBaseRef<const Element> vertexDataElem = Element::create(mRSC, 2, ebe1, ebn1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700630
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700631 ObjectBaseRef<Type> vertexDataType = Type::getTypeRef(mRSC, vertexDataElem.get(),
632 mMaxNumberOfQuads * 4,
Jason Samsa572aca2013-01-09 11:52:26 -0800633 0, 0, false, false, 0);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700634
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700635 Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType.get(),
Jason Samseb4fe182011-05-26 16:33:01 -0700636 RS_ALLOCATION_USAGE_SCRIPT);
Jason Samsa6dd8232012-07-25 19:33:43 -0700637 mTextMeshPtr = (float*)mRSC->mHal.funcs.allocation.lock1D(mRSC, vertexAlloc);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700638
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700639 mMesh.set(new Mesh(mRSC, 1, 1));
640 mMesh->setVertexBuffer(vertexAlloc, 0);
641 mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
642 mMesh->init();
Jason Samsa6dd8232012-07-25 19:33:43 -0700643 mRSC->mHal.funcs.allocation.unlock1D(mRSC, indexAlloc);
644 mRSC->mHal.funcs.allocation.unlock1D(mRSC, vertexAlloc);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700645}
646
647// We don't want to allocate anything unless we actually draw text
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800648void FontState::checkInit() {
649 if (mInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700650 return;
651 }
652
653 initTextTexture();
654 initRenderState();
655
656 initVertexArrayBuffers();
657
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700658 // We store a string with letters in a rough frequency of occurrence
Jason Samsa7f5e042013-07-08 16:46:18 -0700659 mLatinPrecache = " eisarntolcdugpmhbyfvkwzxjq"
660 "EISARNTOLCDUGPMHBYFVKWZXJQ"
661 ",.?!()-+@;:`'0123456789";
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700662 mInitialized = true;
663}
664
665void FontState::issueDrawCommand() {
Jason Sams60709252010-11-17 15:29:32 -0800666 Context::PushState ps(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700667
Jason Sams60709252010-11-17 15:29:32 -0800668 mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
669 mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
670 mRSC->setProgramFragment(mFontShaderF.get());
671 mRSC->setProgramStore(mFontProgramStore.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700672
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800673 if (mConstantsDirty) {
Jason Sams4b45b892010-12-29 14:31:29 -0800674 mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700675 mConstantsDirty = false;
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700676 }
677
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700678 if (!mRSC->setupCheck()) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700679 return;
680 }
681
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700682 mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700683}
684
685void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800686 float u1, float v1,
687 float x2, float y2, float z2,
688 float u2, float v2,
689 float x3, float y3, float z3,
690 float u3, float v3,
691 float x4, float y4, float z4,
692 float u4, float v4) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700693 const uint32_t vertsPerQuad = 4;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800694 const uint32_t floatsPerVert = 6;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700695 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
696
Alex Sakhartchouka74a8f62011-11-16 12:22:10 -0800697 if (x1 > mSurfaceWidth || y1 < 0.0f || x2 < 0 || y4 > mSurfaceHeight) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700698 return;
699 }
700
701 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
Steve Blockaf12ac62012-01-06 19:20:56 +0000702 ALOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
703 ALOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
704 ALOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700705
706 (*currentPos++) = x1;
707 (*currentPos++) = y1;
708 (*currentPos++) = z1;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800709 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700710 (*currentPos++) = u1;
711 (*currentPos++) = v1;
712
713 (*currentPos++) = x2;
714 (*currentPos++) = y2;
715 (*currentPos++) = z2;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800716 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700717 (*currentPos++) = u2;
718 (*currentPos++) = v2;
719
720 (*currentPos++) = x3;
721 (*currentPos++) = y3;
722 (*currentPos++) = z3;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800723 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700724 (*currentPos++) = u3;
725 (*currentPos++) = v3;
726
727 (*currentPos++) = x4;
728 (*currentPos++) = y4;
729 (*currentPos++) = z4;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800730 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700731 (*currentPos++) = u4;
732 (*currentPos++) = v4;
733
734 mCurrentQuadIndex ++;
735
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800736 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700737 issueDrawCommand();
738 mCurrentQuadIndex = 0;
739 }
740}
741
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700742uint32_t FontState::getRemainingCacheCapacity() {
743 uint32_t remainingCapacity = 0;
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700744 uint32_t totalPixels = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800745 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700746 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
747 totalPixels += mCacheLines[i]->mMaxWidth;
748 }
749 remainingCapacity = (remainingCapacity * 100) / totalPixels;
750 return remainingCapacity;
751}
752
753void FontState::precacheLatin(Font *font) {
754 // Remaining capacity is measured in %
755 uint32_t remainingCapacity = getRemainingCacheCapacity();
756 uint32_t precacheIdx = 0;
Jason Samsa7f5e042013-07-08 16:46:18 -0700757 const size_t l = strlen(mLatinPrecache);
758 while ((remainingCapacity > 25) && (precacheIdx < l)) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700759 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
760 remainingCapacity = getRemainingCacheCapacity();
761 precacheIdx ++;
762 }
763}
764
765
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700766void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
767 uint32_t startIndex, int32_t numGlyphs,
768 Font::RenderMode mode,
769 Font::Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800770 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700771 checkInit();
772
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700773 // Render code here
774 Font *currentFont = mRSC->getFont();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800775 if (!currentFont) {
776 if (!mDefault.get()) {
Jason Sams48ecf6a2013-07-09 15:35:29 -0700777 char fullPath[1024];
778 const char * root = getenv("ANDROID_ROOT");
779 rsAssert(strlen(root) < 256);
780 strcpy(fullPath, root);
781 strcat(fullPath, "/fonts/Roboto-Regular.ttf");
782 mDefault.set(Font::create(mRSC, fullPath, 8, mRSC->getDPI()));
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700783 }
784 currentFont = mDefault.get();
785 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800786 if (!currentFont) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000787 ALOGE("Unable to initialize any fonts");
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700788 return;
789 }
790
Alex Sakhartchouka74a8f62011-11-16 12:22:10 -0800791 // Cull things that are off the screen
792 mSurfaceWidth = (float)mRSC->getCurrentSurfaceWidth();
793 mSurfaceHeight = (float)mRSC->getCurrentSurfaceHeight();
794
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700795 currentFont->renderUTF(text, len, x, y, startIndex, numGlyphs,
796 mode, bounds, bitmap, bitmapW, bitmapH);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700797
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800798 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700799 issueDrawCommand();
800 mCurrentQuadIndex = 0;
801 }
802}
803
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700804void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
805 renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800806 bounds->bottom = - bounds->bottom;
807 bounds->top = - bounds->top;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700808}
809
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700810void FontState::setFontColor(float r, float g, float b, float a) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700811 mConstants.mFontColor[0] = r;
812 mConstants.mFontColor[1] = g;
813 mConstants.mFontColor[2] = b;
814 mConstants.mFontColor[3] = a;
815
816 mConstants.mGamma = 1.0f;
Alex Sakhartchoukc8fb69e2010-10-05 13:23:55 -0700817 const float luminance = (r * 2.0f + g * 5.0f + b) / 8.0f;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700818 if (luminance <= mBlackThreshold) {
819 mConstants.mGamma = mBlackGamma;
820 } else if (luminance >= mWhiteThreshold) {
821 mConstants.mGamma = mWhiteGamma;
822 }
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700823
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700824 mConstantsDirty = true;
Alex Sakhartchouk9fc9f032010-08-04 14:45:48 -0700825}
826
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700827void FontState::getFontColor(float *r, float *g, float *b, float *a) const {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700828 *r = mConstants.mFontColor[0];
829 *g = mConstants.mFontColor[1];
830 *b = mConstants.mFontColor[2];
831 *a = mConstants.mFontColor[3];
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700832}
833
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800834void FontState::deinit(Context *rsc) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700835 mInitialized = false;
836
Stephen Hines01b7d292010-09-28 15:45:45 -0700837 mFontShaderFConstant.clear();
838
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700839 mMesh.clear();
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700840
841 mFontShaderF.clear();
842 mFontSampler.clear();
843 mFontProgramStore.clear();
844
845 mTextTexture.clear();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800846 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700847 delete mCacheLines[i];
848 }
849 mCacheLines.clear();
850
851 mDefault.clear();
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700852#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800853 if (mLibrary) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700854 FT_Done_FreeType( mLibrary );
Chris Wailes44bef6f2014-08-12 13:51:10 -0700855 mLibrary = nullptr;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700856 }
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700857#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700858}
859
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700860#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800861bool FontState::CacheTextureLine::fitBitmap(FT_Bitmap_ *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
862 if ((uint32_t)bitmap->rows > mMaxHeight) {
863 return false;
864 }
865
866 if (mCurrentCol + (uint32_t)bitmap->width < mMaxWidth) {
867 *retOriginX = mCurrentCol;
868 *retOriginY = mCurrentRow;
869 mCurrentCol += bitmap->width;
870 mDirty = true;
871 return true;
872 }
873
874 return false;
875}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700876#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800877
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700878namespace android {
879namespace renderscript {
880
Alex Sakhartchouk70b83c12011-04-06 10:57:51 -0700881RsFont rsi_FontCreateFromFile(Context *rsc,
882 char const *name, size_t name_length,
883 float fontSize, uint32_t dpi) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700884 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800885 if (newFont) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700886 newFont->incUserRef();
887 }
888 return newFont;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700889}
890
Alex Sakhartchouk70b83c12011-04-06 10:57:51 -0700891RsFont rsi_FontCreateFromMemory(Context *rsc,
892 char const *name, size_t name_length,
893 float fontSize, uint32_t dpi,
894 const void *data, size_t data_length) {
895 Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800896 if (newFont) {
897 newFont->incUserRef();
898 }
899 return newFont;
900}
901
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700902} // renderscript
903} // android