blob: 511bf62796d36577a5154a4b3f61e3a34472be12 [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"
Alex Sakhartchouk02000b32011-02-25 09:34:33 -080023
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -070024#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouk02000b32011-02-25 09:34:33 -080025#include <ft2build.h>
26#include FT_FREETYPE_H
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070027#include FT_BITMAP_H
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -070028#endif //ANDROID_RS_SERIALIZE
Michael Butler2a1576f2017-04-19 18:47:55 -070029#include <string.h>
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070030
Chih-Hung Hsieh11496ac2016-11-15 15:14:05 -080031namespace android {
32namespace renderscript {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070033
Yang Nib8353c52015-02-14 18:00:59 -080034Font::Font(Context *rsc) : ObjectBase(rsc), mCachedGlyphs(NULL) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070035 mInitialized = false;
36 mHasKerning = false;
Chris Wailes44bef6f2014-08-12 13:51:10 -070037 mFace = nullptr;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070038}
39
Alex Sakhartchouk5224a272011-01-07 11:12:08 -080040bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -070041#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080042 if (mInitialized) {
Steve Blockaf12ac62012-01-06 19:20:56 +000043 ALOGE("Reinitialization of fonts not supported");
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070044 return false;
45 }
46
Alex Sakhartchouk5224a272011-01-07 11:12:08 -080047 FT_Error error = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -070048 if (data != nullptr && dataLen > 0) {
Alex Sakhartchouk5224a272011-01-07 11:12:08 -080049 error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
50 } else {
51 error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
52 }
53
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080054 if (error) {
Steve Blockaf12ac62012-01-06 19:20:56 +000055 ALOGE("Unable to initialize font %s", name);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070056 return false;
57 }
58
Jason Sams48ecf6a2013-07-09 15:35:29 -070059 mFontName = rsuCopyString(name);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070060 mFontSize = fontSize;
61 mDpi = dpi;
62
Alex Sakhartchoukc17ace22010-12-17 11:41:08 -080063 error = FT_Set_Char_Size(mFace, (FT_F26Dot6)(fontSize * 64.0f), 0, dpi, 0);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080064 if (error) {
Steve Blockaf12ac62012-01-06 19:20:56 +000065 ALOGE("Unable to set font size on %s", name);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070066 return false;
67 }
68
69 mHasKerning = FT_HAS_KERNING(mFace);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070070
71 mInitialized = true;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -070072#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070073 return true;
74}
75
Jason Sams2e8665d2011-01-27 00:14:13 -080076void Font::preDestroy() const {
Miao Wang82e135c2017-02-27 23:35:35 -080077 auto& activeFonts = mRSC->mStateFont.mActiveFonts;
78 for (uint32_t ct = 0; ct < activeFonts.size(); ct++) {
79 if (activeFonts[ct] == this) {
80 activeFonts.erase(activeFonts.begin() + ct);
Yang Nib8353c52015-02-14 18:00:59 -080081 break;
Jason Sams2e8665d2011-01-27 00:14:13 -080082 }
83 }
84}
85
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080086void Font::invalidateTextureCache() {
87 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Yang Nib8353c52015-02-14 18:00:59 -080088 mCachedGlyphs.valueAt(i)->mIsValid = false;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070089 }
90}
91
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -080092void Font::drawCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070093 FontState *state = &mRSC->mStateFont;
94
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070095 int32_t nPenX = x + glyph->mBitmapLeft;
96 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -070097
Alex Sakhartchouk09c67352010-10-05 11:33:27 -070098 float u1 = glyph->mBitmapMinU;
99 float u2 = glyph->mBitmapMaxU;
100 float v1 = glyph->mBitmapMinV;
101 float v2 = glyph->mBitmapMaxV;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700102
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700103 int32_t width = (int32_t) glyph->mBitmapWidth;
104 int32_t height = (int32_t) glyph->mBitmapHeight;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700105
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700106 state->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
107 nPenX + width, nPenY, 0, u2, v2,
108 nPenX + width, nPenY - height, 0, u2, v1,
109 nPenX, nPenY - height, 0, u1, v1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700110}
111
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700112void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int32_t x, int32_t y,
113 uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) {
114 int32_t nPenX = x + glyph->mBitmapLeft;
115 int32_t nPenY = y + glyph->mBitmapTop;
116
117 uint32_t endX = glyph->mBitmapMinX + glyph->mBitmapWidth;
118 uint32_t endY = glyph->mBitmapMinY + glyph->mBitmapHeight;
119
120 FontState *state = &mRSC->mStateFont;
121 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
Jason Samsa6dd8232012-07-25 19:33:43 -0700122 const uint8_t* cacheBuffer = state->mCacheBuffer;
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700123
124 uint32_t cacheX = 0, cacheY = 0;
125 int32_t bX = 0, bY = 0;
126 for (cacheX = glyph->mBitmapMinX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
127 for (cacheY = glyph->mBitmapMinY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
128 if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000129 ALOGE("Skipping invalid index");
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700130 continue;
131 }
132 uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
133 bitmap[bY * bitmapW + bX] = tempCol;
134 }
135 }
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700136}
137
138void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int32_t x, int32_t y, Rect *bounds) {
139 int32_t nPenX = x + glyph->mBitmapLeft;
140 int32_t nPenY = y - glyph->mBitmapTop + glyph->mBitmapHeight;
141
142 int32_t width = (int32_t) glyph->mBitmapWidth;
143 int32_t height = (int32_t) glyph->mBitmapHeight;
144
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800145 // 0, 0 is top left, so bottom is a positive number
146 if (bounds->bottom < nPenY) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700147 bounds->bottom = nPenY;
148 }
149 if (bounds->left > nPenX) {
150 bounds->left = nPenX;
151 }
152 if (bounds->right < nPenX + width) {
153 bounds->right = nPenX + width;
154 }
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800155 if (bounds->top > nPenY - height) {
156 bounds->top = nPenY - height;
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700157 }
158}
159
160void Font::renderUTF(const char *text, uint32_t len, int32_t x, int32_t y,
161 uint32_t start, int32_t numGlyphs,
162 RenderMode mode, Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800163 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Chris Wailes44bef6f2014-08-12 13:51:10 -0700164 if (!mInitialized || numGlyphs == 0 || text == nullptr || len == 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700165 return;
166 }
167
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800168 if (mode == Font::MEASURE) {
Chris Wailes44bef6f2014-08-12 13:51:10 -0700169 if (bounds == nullptr) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000170 ALOGE("No return rectangle provided to measure text");
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700171 return;
172 }
173 // Reset min and max of the bounding box to something large
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800174 bounds->set(1e6, -1e6, 1e6, -1e6);
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700175 }
176
177 int32_t penX = x, penY = y;
178 int32_t glyphsLeft = 1;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800179 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700180 glyphsLeft = numGlyphs;
181 }
182
183 size_t index = start;
184 size_t nextIndex = 0;
185
186 while (glyphsLeft > 0) {
187
Kenny Rootc9c38dd2010-11-09 14:37:23 -0800188 int32_t utfChar = utf32_from_utf8_at(text, len, index, &nextIndex);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700189
190 // Reached the end of the string or encountered
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800191 if (utfChar < 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700192 break;
193 }
194
195 // Move to the next character in the array
196 index = nextIndex;
197
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700198 CachedGlyphInfo *cachedGlyph = getCachedUTFChar(utfChar);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700199
200 // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800201 if (cachedGlyph->mIsValid) {
202 switch (mode) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700203 case FRAMEBUFFER:
204 drawCachedGlyph(cachedGlyph, penX, penY);
205 break;
206 case BITMAP:
207 drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH);
208 break;
209 case MEASURE:
210 measureCachedGlyph(cachedGlyph, penX, penY, bounds);
211 break;
212 }
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700213 }
214
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800215 penX += (cachedGlyph->mAdvanceX >> 6);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700216
217 // If we were given a specific number of glyphs, decrement
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800218 if (numGlyphs > 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700219 glyphsLeft --;
220 }
221 }
222}
223
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700224Font::CachedGlyphInfo* Font::getCachedUTFChar(int32_t utfChar) {
225
Yang Nib8353c52015-02-14 18:00:59 -0800226 CachedGlyphInfo *cachedGlyph = mCachedGlyphs.valueFor((uint32_t)utfChar);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700227 if (cachedGlyph == nullptr) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700228 cachedGlyph = cacheGlyph((uint32_t)utfChar);
229 }
230 // Is the glyph still in texture cache?
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800231 if (!cachedGlyph->mIsValid) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700232 updateGlyphCache(cachedGlyph);
233 }
234
235 return cachedGlyph;
236}
237
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800238void Font::updateGlyphCache(CachedGlyphInfo *glyph) {
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700239#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700240 FT_Error error = FT_Load_Glyph( mFace, glyph->mGlyphIndex, FT_LOAD_RENDER );
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800241 if (error) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000242 ALOGE("Couldn't load glyph.");
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700243 return;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700244 }
245
Alex Sakhartchouk02000b32011-02-25 09:34:33 -0800246 glyph->mAdvanceX = mFace->glyph->advance.x;
247 glyph->mAdvanceY = mFace->glyph->advance.y;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700248 glyph->mBitmapLeft = mFace->glyph->bitmap_left;
249 glyph->mBitmapTop = mFace->glyph->bitmap_top;
250
251 FT_Bitmap *bitmap = &mFace->glyph->bitmap;
252
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700253 // Now copy the bitmap into the cache texture
254 uint32_t startX = 0;
255 uint32_t startY = 0;
256
257 // Let the font state figure out where to put the bitmap
258 FontState *state = &mRSC->mStateFont;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700259 glyph->mIsValid = state->cacheBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700260
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800261 if (!glyph->mIsValid) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700262 return;
263 }
264
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700265 uint32_t endX = startX + bitmap->width;
266 uint32_t endY = startY + bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700267
268 glyph->mBitmapMinX = startX;
269 glyph->mBitmapMinY = startY;
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700270 glyph->mBitmapWidth = bitmap->width;
271 glyph->mBitmapHeight = bitmap->rows;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700272
273 uint32_t cacheWidth = state->getCacheTextureType()->getDimX();
274 uint32_t cacheHeight = state->getCacheTextureType()->getDimY();
275
276 glyph->mBitmapMinU = (float)startX / (float)cacheWidth;
277 glyph->mBitmapMinV = (float)startY / (float)cacheHeight;
278 glyph->mBitmapMaxU = (float)endX / (float)cacheWidth;
279 glyph->mBitmapMaxV = (float)endY / (float)cacheHeight;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700280#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700281}
282
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800283Font::CachedGlyphInfo *Font::cacheGlyph(uint32_t glyph) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700284 CachedGlyphInfo *newGlyph = new CachedGlyphInfo();
Yang Nib8353c52015-02-14 18:00:59 -0800285 mCachedGlyphs.add(glyph, newGlyph);
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700286#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700287 newGlyph->mGlyphIndex = FT_Get_Char_Index(mFace, glyph);
288 newGlyph->mIsValid = false;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700289#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700290 updateGlyphCache(newGlyph);
291
292 return newGlyph;
293}
294
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800295Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
296 const void *data, uint32_t dataLen) {
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700297 rsc->mStateFont.checkInit();
Miao Wang82e135c2017-02-27 23:35:35 -0800298 auto& activeFonts = rsc->mStateFont.mActiveFonts;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700299
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800300 for (uint32_t i = 0; i < activeFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700301 Font *ithFont = activeFonts[i];
Yang Nib8353c52015-02-14 18:00:59 -0800302 if (ithFont->mFontName == name && ithFont->mFontSize == fontSize && ithFont->mDpi == dpi) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700303 return ithFont;
304 }
305 }
306
307 Font *newFont = new Font(rsc);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800308 bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800309 if (isInitialized) {
Miao Wang82e135c2017-02-27 23:35:35 -0800310 activeFonts.push_back(newFont);
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700311 rsc->mStateFont.precacheLatin(newFont);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700312 return newFont;
313 }
314
Jason Sams225afd32010-10-21 14:06:55 -0700315 ObjectBase::checkDelete(newFont);
Chris Wailes44bef6f2014-08-12 13:51:10 -0700316 return nullptr;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700317}
318
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800319Font::~Font() {
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700320#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800321 if (mFace) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700322 FT_Done_Face(mFace);
323 }
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700324#endif
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700325
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800326 for (uint32_t i = 0; i < mCachedGlyphs.size(); i ++) {
Yang Nib8353c52015-02-14 18:00:59 -0800327 CachedGlyphInfo *glyph = mCachedGlyphs.valueAt(i);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700328 delete glyph;
329 }
330}
331
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800332FontState::FontState() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700333 mInitialized = false;
334 mMaxNumberOfQuads = 1024;
335 mCurrentQuadIndex = 0;
Chris Wailes44bef6f2014-08-12 13:51:10 -0700336 mRSC = nullptr;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700337#ifndef ANDROID_RS_SERIALIZE
Chris Wailes44bef6f2014-08-12 13:51:10 -0700338 mLibrary = nullptr;
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700339#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700340
Nick Kralevich7e85ca22013-05-22 15:04:39 -0700341 float gamma = DEFAULT_TEXT_GAMMA;
342 int32_t blackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
343 int32_t whiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
344
Elliott Hughese5e18cc2015-08-12 16:37:22 -0700345#ifdef __ANDROID__
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700346 // Get the renderer properties
Miao Wang82e135c2017-02-27 23:35:35 -0800347 char property[PROP_VALUE_MAX];
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700348
349 // Get the gamma
Chris Wailes44bef6f2014-08-12 13:51:10 -0700350 if (property_get(PROPERTY_TEXT_GAMMA, property, nullptr) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700351 gamma = atof(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700352 }
353
354 // Get the black gamma threshold
Chris Wailes44bef6f2014-08-12 13:51:10 -0700355 if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, nullptr) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700356 blackThreshold = atoi(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700357 }
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700358
359 // Get the white gamma threshold
Chris Wailes44bef6f2014-08-12 13:51:10 -0700360 if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, nullptr) > 0) {
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700361 whiteThreshold = atoi(property);
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700362 }
Nick Kralevich7e85ca22013-05-22 15:04:39 -0700363#endif
364
365 mBlackThreshold = (float)(blackThreshold) / 255.0f;
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700366 mWhiteThreshold = (float)(whiteThreshold) / 255.0f;
367
368 // Compute the gamma tables
369 mBlackGamma = gamma;
370 mWhiteGamma = 1.0f / gamma;
Alex Sakhartchouk4f230b32010-10-12 14:15:17 -0700371
372 setFontColor(0.1f, 0.1f, 0.1f, 1.0f);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700373}
374
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800375FontState::~FontState() {
376 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700377 delete mCacheLines[i];
378 }
379
380 rsAssert(!mActiveFonts.size());
381}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700382#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800383FT_Library FontState::getLib() {
384 if (!mLibrary) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700385 FT_Error error = FT_Init_FreeType(&mLibrary);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800386 if (error) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000387 ALOGE("Unable to initialize freetype");
Chris Wailes44bef6f2014-08-12 13:51:10 -0700388 return nullptr;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700389 }
390 }
Alex Sakhartchouk3659d942010-06-30 16:53:43 -0700391
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700392 return mLibrary;
393}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700394#endif //ANDROID_RS_SERIALIZE
395
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700396
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800397void FontState::init(Context *rsc) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700398 mRSC = rsc;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700399}
400
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800401void FontState::flushAllAndInvalidate() {
402 if (mCurrentQuadIndex != 0) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700403 issueDrawCommand();
404 mCurrentQuadIndex = 0;
405 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800406 for (uint32_t i = 0; i < mActiveFonts.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700407 mActiveFonts[i]->invalidateTextureCache();
408 }
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800409 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700410 mCacheLines[i]->mCurrentCol = 0;
411 }
412}
413
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700414#ifndef ANDROID_RS_SERIALIZE
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800415bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *retOriginY) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700416 // If the glyph is too tall, don't cache it
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800417 if ((uint32_t)bitmap->rows > mCacheLines[mCacheLines.size()-1]->mMaxHeight) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000418 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 -0700419 return false;
420 }
421
422 // Now copy the bitmap into the cache texture
423 uint32_t startX = 0;
424 uint32_t startY = 0;
425
426 bool bitmapFit = false;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800427 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700428 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800429 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700430 break;
431 }
432 }
433
434 // If the new glyph didn't fit, flush the state so far and invalidate everything
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800435 if (!bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700436 flushAllAndInvalidate();
437
438 // Try to fit it again
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800439 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700440 bitmapFit = mCacheLines[i]->fitBitmap(bitmap, &startX, &startY);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800441 if (bitmapFit) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700442 break;
443 }
444 }
445
446 // if we still don't fit, something is wrong and we shouldn't draw
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800447 if (!bitmapFit) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000448 ALOGE("Bitmap doesn't fit in cache. width, height = %i, %i", (int)bitmap->width, (int)bitmap->rows);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700449 return false;
450 }
451 }
452
453 *retOriginX = startX;
454 *retOriginY = startY;
455
456 uint32_t endX = startX + bitmap->width;
457 uint32_t endY = startY + bitmap->rows;
458
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700459 uint32_t cacheWidth = getCacheTextureType()->getDimX();
460
Jason Samsa6dd8232012-07-25 19:33:43 -0700461 uint8_t *cacheBuffer = mCacheBuffer;
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700462 uint8_t *bitmapBuffer = bitmap->buffer;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700463
464 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800465 for (cacheX = startX, bX = 0; cacheX < endX; cacheX ++, bX ++) {
466 for (cacheY = startY, bY = 0; cacheY < endY; cacheY ++, bY ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700467 uint8_t tempCol = bitmapBuffer[bY * bitmap->width + bX];
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700468 cacheBuffer[cacheY*cacheWidth + cacheX] = tempCol;
469 }
470 }
471
472 // This will dirty the texture and the shader so next time
473 // we draw it will upload the data
Jason Samseb4fe182011-05-26 16:33:01 -0700474
Jason Samsa6dd8232012-07-25 19:33:43 -0700475 mRSC->mHal.funcs.allocation.data2D(mRSC, mTextTexture.get(), 0, 0, 0,
476 RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, mCacheWidth, mCacheHeight,
Tim Murray358747a2012-11-26 13:52:04 -0800477 mCacheBuffer, mCacheWidth*mCacheHeight, mCacheWidth);
Jason Samsa6dd8232012-07-25 19:33:43 -0700478
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700479 mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700480
481 // Some debug code
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800482 /*for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Steve Blockaf12ac62012-01-06 19:20:56 +0000483 ALOGE("Cache Line: H: %u Empty Space: %f",
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700484 mCacheLines[i]->mMaxHeight,
485 (1.0f - (float)mCacheLines[i]->mCurrentCol/(float)mCacheLines[i]->mMaxWidth)*100.0f);
486
487 }*/
488
489 return true;
490}
Alex Sakhartchoukb81a0eb2011-06-03 10:18:01 -0700491#endif //ANDROID_RS_SERIALIZE
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700492
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800493void FontState::initRenderState() {
Jason Sams48ecf6a2013-07-09 15:35:29 -0700494 const char *shaderString = "varying vec2 varTex0;\n"
495 "void main() {\n"
496 " lowp vec4 col = UNI_Color;\n"
497 " col.a = texture2D(UNI_Tex0, varTex0.xy).a;\n"
498 " col.a = pow(col.a, UNI_Gamma);\n"
499 " gl_FragColor = col;\n"
500 "}\n";
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700501
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800502 const char *textureNames[] = { "Tex0" };
503 const size_t textureNamesLengths[] = { 4 };
504 size_t numTextures = sizeof(textureNamesLengths)/sizeof(*textureNamesLengths);
505
506 ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
507 RS_KIND_USER, false, 4);
508 ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
509 RS_KIND_USER, false, 1);
Jason Samsf313dc32013-07-09 14:29:39 -0700510
511 const char *ebn1[] = { "Color", "Gamma" };
512 const Element *ebe1[] = {colorElem.get(), gammaElem.get()};
513 ObjectBaseRef<const Element> constInput = Element::create(mRSC, 2, ebe1, ebn1);
Jason Samsc7968a02014-11-11 16:24:36 -0800514 ObjectBaseRef<Type> inputType = Type::getTypeRef(mRSC, constInput.get(), 1);
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700515
Ian Rogersf8852d02014-01-29 15:35:17 -0800516 uintptr_t tmp[4];
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700517 tmp[0] = RS_PROGRAM_PARAM_CONSTANT;
Ian Rogersf8852d02014-01-29 15:35:17 -0800518 tmp[1] = (uintptr_t)inputType.get();
Alex Sakhartchouk84e40272010-11-18 15:22:43 -0800519 tmp[2] = RS_PROGRAM_PARAM_TEXTURE_TYPE;
520 tmp[3] = RS_TEXTURE_2D;
Alex Sakhartchouke7ae69f2010-09-14 09:50:43 -0700521
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700522 mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800523 RS_ALLOCATION_USAGE_SCRIPT |
524 RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
Jason Sams48ecf6a2013-07-09 15:35:29 -0700525 ProgramFragment *pf = new ProgramFragment(mRSC, shaderString, strlen(shaderString),
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800526 textureNames, numTextures, textureNamesLengths,
527 tmp, 4);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700528 mFontShaderF.set(pf);
Alex Sakhartchouk383e5b12010-09-23 16:16:33 -0700529 mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700530
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700531 mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800532 RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP,
533 RS_SAMPLER_CLAMP).get());
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700534 mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700535
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700536 mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
537 false, false,
538 RS_BLEND_SRC_SRC_ALPHA,
539 RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,
540 RS_DEPTH_FUNC_ALWAYS).get());
Jason Sams8feea4e2011-03-18 15:03:25 -0700541 mFontProgramStore->init();
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700542}
543
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800544void FontState::initTextTexture() {
Alex Sakhartchouk748eb072012-02-15 16:21:46 -0800545 ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8,
546 RS_KIND_PIXEL_A, true, 1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700547
548 // We will allocate a texture to initially hold 32 character bitmaps
Jason Samsa6dd8232012-07-25 19:33:43 -0700549 mCacheHeight = 256;
550 mCacheWidth = 1024;
Jason Samsc7968a02014-11-11 16:24:36 -0800551 ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(), mCacheWidth, mCacheHeight);
Chris Wailes93d6bc82014-07-28 16:54:38 -0700552
Jason Samsa6dd8232012-07-25 19:33:43 -0700553 mCacheBuffer = new uint8_t[mCacheWidth * mCacheHeight];
554
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700555
Yang Nib8353c52015-02-14 18:00:59 -0800556 Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(),
557 RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700558 mTextTexture.set(cacheAlloc);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700559
560 // Split up our cache texture into lines of certain widths
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700561 int32_t nextLine = 0;
Miao Wang82e135c2017-02-27 23:35:35 -0800562 mCacheLines.push_back(new CacheTextureLine(16, texType->getDimX(), nextLine, 0));
563 nextLine += mCacheLines.back()->mMaxHeight;
564 mCacheLines.push_back(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
565 nextLine += mCacheLines.back()->mMaxHeight;
566 mCacheLines.push_back(new CacheTextureLine(24, texType->getDimX(), nextLine, 0));
567 nextLine += mCacheLines.back()->mMaxHeight;
568 mCacheLines.push_back(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
569 nextLine += mCacheLines.back()->mMaxHeight;
570 mCacheLines.push_back(new CacheTextureLine(32, texType->getDimX(), nextLine, 0));
571 nextLine += mCacheLines.back()->mMaxHeight;
572 mCacheLines.push_back(new CacheTextureLine(40, texType->getDimX(), nextLine, 0));
573 nextLine += mCacheLines.back()->mMaxHeight;
574 mCacheLines.push_back(new CacheTextureLine(texType->getDimY() - nextLine, texType->getDimX(), nextLine, 0));
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700575}
576
577// Avoid having to reallocate memory and render quad by quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800578void FontState::initVertexArrayBuffers() {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700579 // Now lets write index data
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700580 ObjectBaseRef<const Element> indexElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_16, RS_KIND_USER, false, 1);
Jason Samsc7968a02014-11-11 16:24:36 -0800581 ObjectBaseRef<Type> indexType = Type::getTypeRef(mRSC, indexElem.get(), mMaxNumberOfQuads * 6);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700582
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700583 Allocation *indexAlloc = Allocation::createAllocation(mRSC, indexType.get(),
Jason Samseb4fe182011-05-26 16:33:01 -0700584 RS_ALLOCATION_USAGE_SCRIPT |
585 RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
Jason Samsa6dd8232012-07-25 19:33:43 -0700586 uint16_t *indexPtr = (uint16_t*)mRSC->mHal.funcs.allocation.lock1D(mRSC, indexAlloc);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700587
588 // Four verts, two triangles , six indices per quad
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800589 for (uint32_t i = 0; i < mMaxNumberOfQuads; i ++) {
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700590 int32_t i6 = i * 6;
591 int32_t i4 = i * 4;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700592
593 indexPtr[i6 + 0] = i4 + 0;
594 indexPtr[i6 + 1] = i4 + 1;
595 indexPtr[i6 + 2] = i4 + 2;
596
597 indexPtr[i6 + 3] = i4 + 0;
598 indexPtr[i6 + 4] = i4 + 2;
599 indexPtr[i6 + 5] = i4 + 3;
600 }
601
Jason Samseb4fe182011-05-26 16:33:01 -0700602 indexAlloc->sendDirty(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700603
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700604 ObjectBaseRef<const Element> posElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
605 ObjectBaseRef<const Element> texElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700606
Jason Samsf313dc32013-07-09 14:29:39 -0700607 const char *ebn1[] = { "position", "texture0" };
608 const Element *ebe1[] = {posElem.get(), texElem.get()};
609 ObjectBaseRef<const Element> vertexDataElem = Element::create(mRSC, 2, ebe1, ebn1);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700610
Jason Samsc7968a02014-11-11 16:24:36 -0800611 ObjectBaseRef<Type> vertexDataType = Type::getTypeRef(mRSC, vertexDataElem.get(), mMaxNumberOfQuads * 4);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700612
Alex Sakhartchoukc700e642011-08-16 13:09:46 -0700613 Allocation *vertexAlloc = Allocation::createAllocation(mRSC, vertexDataType.get(),
Jason Samseb4fe182011-05-26 16:33:01 -0700614 RS_ALLOCATION_USAGE_SCRIPT);
Jason Samsa6dd8232012-07-25 19:33:43 -0700615 mTextMeshPtr = (float*)mRSC->mHal.funcs.allocation.lock1D(mRSC, vertexAlloc);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700616
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700617 mMesh.set(new Mesh(mRSC, 1, 1));
618 mMesh->setVertexBuffer(vertexAlloc, 0);
619 mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
620 mMesh->init();
Jason Samsa6dd8232012-07-25 19:33:43 -0700621 mRSC->mHal.funcs.allocation.unlock1D(mRSC, indexAlloc);
622 mRSC->mHal.funcs.allocation.unlock1D(mRSC, vertexAlloc);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700623}
624
625// We don't want to allocate anything unless we actually draw text
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800626void FontState::checkInit() {
627 if (mInitialized) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700628 return;
629 }
630
631 initTextTexture();
632 initRenderState();
633
634 initVertexArrayBuffers();
635
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700636 // We store a string with letters in a rough frequency of occurrence
Jason Samsa7f5e042013-07-08 16:46:18 -0700637 mLatinPrecache = " eisarntolcdugpmhbyfvkwzxjq"
638 "EISARNTOLCDUGPMHBYFVKWZXJQ"
639 ",.?!()-+@;:`'0123456789";
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700640 mInitialized = true;
641}
642
643void FontState::issueDrawCommand() {
Jason Sams60709252010-11-17 15:29:32 -0800644 Context::PushState ps(mRSC);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700645
Jason Sams60709252010-11-17 15:29:32 -0800646 mRSC->setProgramVertex(mRSC->getDefaultProgramVertex());
647 mRSC->setProgramRaster(mRSC->getDefaultProgramRaster());
648 mRSC->setProgramFragment(mFontShaderF.get());
649 mRSC->setProgramStore(mFontProgramStore.get());
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700650
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800651 if (mConstantsDirty) {
Jason Sams4b45b892010-12-29 14:31:29 -0800652 mFontShaderFConstant->data(mRSC, 0, 0, 1, &mConstants, sizeof(mConstants));
Alex Sakhartchoukc9fa3052010-10-01 15:20:41 -0700653 mConstantsDirty = false;
Alex Sakhartchoukca5a4542010-08-05 11:24:14 -0700654 }
655
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700656 if (!mRSC->setupCheck()) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700657 return;
658 }
659
Alex Sakhartchouka04e30d2011-04-29 16:49:08 -0700660 mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700661}
662
663void FontState::appendMeshQuad(float x1, float y1, float z1,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800664 float u1, float v1,
665 float x2, float y2, float z2,
666 float u2, float v2,
667 float x3, float y3, float z3,
668 float u3, float v3,
669 float x4, float y4, float z4,
670 float u4, float v4) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700671 const uint32_t vertsPerQuad = 4;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800672 const uint32_t floatsPerVert = 6;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700673 float *currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
674
Alex Sakhartchouka74a8f62011-11-16 12:22:10 -0800675 if (x1 > mSurfaceWidth || y1 < 0.0f || x2 < 0 || y4 > mSurfaceHeight) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700676 return;
677 }
678
679 /*LOGE("V0 x: %f y: %f z: %f", x1, y1, z1);
Steve Blockaf12ac62012-01-06 19:20:56 +0000680 ALOGE("V1 x: %f y: %f z: %f", x2, y2, z2);
681 ALOGE("V2 x: %f y: %f z: %f", x3, y3, z3);
682 ALOGE("V3 x: %f y: %f z: %f", x4, y4, z4);*/
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700683
684 (*currentPos++) = x1;
685 (*currentPos++) = y1;
686 (*currentPos++) = z1;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800687 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700688 (*currentPos++) = u1;
689 (*currentPos++) = v1;
690
691 (*currentPos++) = x2;
692 (*currentPos++) = y2;
693 (*currentPos++) = z2;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800694 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700695 (*currentPos++) = u2;
696 (*currentPos++) = v2;
697
698 (*currentPos++) = x3;
699 (*currentPos++) = y3;
700 (*currentPos++) = z3;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800701 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700702 (*currentPos++) = u3;
703 (*currentPos++) = v3;
704
705 (*currentPos++) = x4;
706 (*currentPos++) = y4;
707 (*currentPos++) = z4;
Alex Sakhartchouk2d1220c2011-11-15 15:15:21 -0800708 (*currentPos++) = 0;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700709 (*currentPos++) = u4;
710 (*currentPos++) = v4;
711
712 mCurrentQuadIndex ++;
713
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800714 if (mCurrentQuadIndex == mMaxNumberOfQuads) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700715 issueDrawCommand();
716 mCurrentQuadIndex = 0;
717 }
718}
719
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700720uint32_t FontState::getRemainingCacheCapacity() {
721 uint32_t remainingCapacity = 0;
Alex Sakhartchouk35b96442010-08-18 15:46:43 -0700722 uint32_t totalPixels = 0;
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800723 for (uint32_t i = 0; i < mCacheLines.size(); i ++) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700724 remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
725 totalPixels += mCacheLines[i]->mMaxWidth;
726 }
727 remainingCapacity = (remainingCapacity * 100) / totalPixels;
728 return remainingCapacity;
729}
730
731void FontState::precacheLatin(Font *font) {
732 // Remaining capacity is measured in %
733 uint32_t remainingCapacity = getRemainingCacheCapacity();
734 uint32_t precacheIdx = 0;
Jason Samsa7f5e042013-07-08 16:46:18 -0700735 const size_t l = strlen(mLatinPrecache);
736 while ((remainingCapacity > 25) && (precacheIdx < l)) {
Alex Sakhartchouk01bcef62010-08-17 11:09:49 -0700737 font->getCachedUTFChar((int32_t)mLatinPrecache[precacheIdx]);
738 remainingCapacity = getRemainingCacheCapacity();
739 precacheIdx ++;
740 }
741}
742
743
Alex Sakhartchouk09c67352010-10-05 11:33:27 -0700744void FontState::renderText(const char *text, uint32_t len, int32_t x, int32_t y,
745 uint32_t startIndex, int32_t numGlyphs,
746 Font::RenderMode mode,
747 Font::Rect *bounds,
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800748 uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700749 checkInit();
750
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700751 // Render code here
752 Font *currentFont = mRSC->getFont();
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800753 if (!currentFont) {
754 if (!mDefault.get()) {
Jason Sams48ecf6a2013-07-09 15:35:29 -0700755 char fullPath[1024];
756 const char * root = getenv("ANDROID_ROOT");
757 rsAssert(strlen(root) < 256);
Michael Butler2a1576f2017-04-19 18:47:55 -0700758 strlcpy(fullPath, root, sizeof(fullPath));
759 strlcat(fullPath, "/fonts/Roboto-Regular.ttf", sizeof(fullPath));
Michael Butler7305bb32017-04-26 18:25:16 -0700760 fullPath[sizeof(fullPath)-1] = '\0';
Jason Sams48ecf6a2013-07-09 15:35:29 -0700761 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 Sakhartchouk70b83c12011-04-06 10:57:51 -0700857RsFont rsi_FontCreateFromFile(Context *rsc,
858 char const *name, size_t name_length,
859 float fontSize, uint32_t dpi) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700860 Font *newFont = Font::create(rsc, name, fontSize, dpi);
Alex Sakhartchoukafb743a2010-11-09 17:00:54 -0800861 if (newFont) {
Alex Sakhartchouka1ccecd2010-06-30 12:49:27 -0700862 newFont->incUserRef();
863 }
864 return newFont;
Alex Sakhartchoukd3e0ad42010-06-24 17:15:34 -0700865}
866
Alex Sakhartchouk70b83c12011-04-06 10:57:51 -0700867RsFont rsi_FontCreateFromMemory(Context *rsc,
868 char const *name, size_t name_length,
869 float fontSize, uint32_t dpi,
870 const void *data, size_t data_length) {
871 Font *newFont = Font::create(rsc, name, fontSize, dpi, data, data_length);
Alex Sakhartchouk5224a272011-01-07 11:12:08 -0800872 if (newFont) {
873 newFont->incUserRef();
874 }
875 return newFont;
876}
877
Rahul Chaudhry7974fc02017-02-09 12:33:28 -0800878} // namespace renderscript
879} // namespace android