• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "OpenGLRenderer"
18 
19 #include <cutils/compiler.h>
20 
21 #include <SkUtils.h>
22 
23 #include "Debug.h"
24 #include "FontUtil.h"
25 #include "Font.h"
26 #include "FontRenderer.h"
27 #include "Properties.h"
28 
29 namespace android {
30 namespace uirenderer {
31 
32 ///////////////////////////////////////////////////////////////////////////////
33 // Font
34 ///////////////////////////////////////////////////////////////////////////////
35 
Font(FontRenderer * state,uint32_t fontId,float fontSize,int flags,uint32_t italicStyle,uint32_t scaleX,SkPaint::Style style,uint32_t strokeWidth)36 Font::Font(FontRenderer* state, uint32_t fontId, float fontSize,
37         int flags, uint32_t italicStyle, uint32_t scaleX,
38         SkPaint::Style style, uint32_t strokeWidth) :
39         mState(state), mFontId(fontId), mFontSize(fontSize),
40         mFlags(flags), mItalicStyle(italicStyle), mScaleX(scaleX),
41         mStyle(style), mStrokeWidth(mStrokeWidth) {
42 }
43 
44 
~Font()45 Font::~Font() {
46     mState->removeFont(this);
47 
48     for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
49         delete mCachedGlyphs.valueAt(i);
50     }
51 }
52 
invalidateTextureCache(CacheTexture * cacheTexture)53 void Font::invalidateTextureCache(CacheTexture* cacheTexture) {
54     for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
55         CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueAt(i);
56         if (!cacheTexture || cachedGlyph->mCacheTexture == cacheTexture) {
57             cachedGlyph->mIsValid = false;
58         }
59     }
60 }
61 
measureCachedGlyph(CachedGlyphInfo * glyph,int x,int y,uint8_t * bitmap,uint32_t bitmapW,uint32_t bitmapH,Rect * bounds,const float * pos)62 void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y,
63         uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
64     int nPenX = x + glyph->mBitmapLeft;
65     int nPenY = y + glyph->mBitmapTop;
66 
67     int width = (int) glyph->mBitmapWidth;
68     int height = (int) glyph->mBitmapHeight;
69 
70     if (bounds->bottom > nPenY) {
71         bounds->bottom = nPenY;
72     }
73     if (bounds->left > nPenX) {
74         bounds->left = nPenX;
75     }
76     if (bounds->right < nPenX + width) {
77         bounds->right = nPenX + width;
78     }
79     if (bounds->top < nPenY + height) {
80         bounds->top = nPenY + height;
81     }
82 }
83 
drawCachedGlyph(CachedGlyphInfo * glyph,int x,int y,uint8_t * bitmap,uint32_t bitmapW,uint32_t bitmapH,Rect * bounds,const float * pos)84 void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
85         uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
86     int nPenX = x + glyph->mBitmapLeft;
87     int nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight;
88 
89     float u1 = glyph->mBitmapMinU;
90     float u2 = glyph->mBitmapMaxU;
91     float v1 = glyph->mBitmapMinV;
92     float v2 = glyph->mBitmapMaxV;
93 
94     int width = (int) glyph->mBitmapWidth;
95     int height = (int) glyph->mBitmapHeight;
96 
97     mState->appendMeshQuad(nPenX, nPenY, u1, v2,
98             nPenX + width, nPenY, u2, v2,
99             nPenX + width, nPenY - height, u2, v1,
100             nPenX, nPenY - height, u1, v1, glyph->mCacheTexture);
101 }
102 
drawCachedGlyphBitmap(CachedGlyphInfo * glyph,int x,int y,uint8_t * bitmap,uint32_t bitmapW,uint32_t bitmapH,Rect * bounds,const float * pos)103 void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y,
104         uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
105     int nPenX = x + glyph->mBitmapLeft;
106     int nPenY = y + glyph->mBitmapTop;
107 
108     uint32_t endX = glyph->mStartX + glyph->mBitmapWidth;
109     uint32_t endY = glyph->mStartY + glyph->mBitmapHeight;
110 
111     CacheTexture* cacheTexture = glyph->mCacheTexture;
112     uint32_t cacheWidth = cacheTexture->getWidth();
113     const uint8_t* cacheBuffer = cacheTexture->getTexture();
114 
115     uint32_t cacheX = 0, cacheY = 0;
116     int32_t bX = 0, bY = 0;
117     for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
118         for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
119 #if DEBUG_FONT_RENDERER
120             if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
121                 ALOGE("Skipping invalid index");
122                 continue;
123             }
124 #endif
125             uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
126             bitmap[bY * bitmapW + bX] = tempCol;
127         }
128     }
129 }
130 
drawCachedGlyph(CachedGlyphInfo * glyph,float x,float hOffset,float vOffset,SkPathMeasure & measure,SkPoint * position,SkVector * tangent)131 void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset,
132         SkPathMeasure& measure, SkPoint* position, SkVector* tangent) {
133     const float halfWidth = glyph->mBitmapWidth * 0.5f;
134     const float height = glyph->mBitmapHeight;
135 
136     vOffset += glyph->mBitmapTop + height;
137 
138     SkPoint destination[4];
139     measure.getPosTan(x + hOffset +  glyph->mBitmapLeft + halfWidth, position, tangent);
140 
141     // Move along the tangent and offset by the normal
142     destination[0].set(-tangent->fX * halfWidth - tangent->fY * vOffset,
143             -tangent->fY * halfWidth + tangent->fX * vOffset);
144     destination[1].set(tangent->fX * halfWidth - tangent->fY * vOffset,
145             tangent->fY * halfWidth + tangent->fX * vOffset);
146     destination[2].set(destination[1].fX + tangent->fY * height,
147             destination[1].fY - tangent->fX * height);
148     destination[3].set(destination[0].fX + tangent->fY * height,
149             destination[0].fY - tangent->fX * height);
150 
151     const float u1 = glyph->mBitmapMinU;
152     const float u2 = glyph->mBitmapMaxU;
153     const float v1 = glyph->mBitmapMinV;
154     const float v2 = glyph->mBitmapMaxV;
155 
156     mState->appendRotatedMeshQuad(
157             position->fX + destination[0].fX,
158             position->fY + destination[0].fY, u1, v2,
159             position->fX + destination[1].fX,
160             position->fY + destination[1].fY, u2, v2,
161             position->fX + destination[2].fX,
162             position->fY + destination[2].fY, u2, v1,
163             position->fX + destination[3].fX,
164             position->fY + destination[3].fY, u1, v1,
165             glyph->mCacheTexture);
166 }
167 
getCachedGlyph(SkPaint * paint,glyph_t textUnit,bool precaching)168 CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit, bool precaching) {
169     CachedGlyphInfo* cachedGlyph = NULL;
170     ssize_t index = mCachedGlyphs.indexOfKey(textUnit);
171     if (index >= 0) {
172         cachedGlyph = mCachedGlyphs.valueAt(index);
173     } else {
174         cachedGlyph = cacheGlyph(paint, textUnit, precaching);
175     }
176 
177     // Is the glyph still in texture cache?
178     if (!cachedGlyph->mIsValid) {
179         const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit);
180         updateGlyphCache(paint, skiaGlyph, cachedGlyph, precaching);
181     }
182 
183     return cachedGlyph;
184 }
185 
render(SkPaint * paint,const char * text,uint32_t start,uint32_t len,int numGlyphs,int x,int y,uint8_t * bitmap,uint32_t bitmapW,uint32_t bitmapH)186 void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
187         int numGlyphs, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) {
188     if (bitmap != NULL && bitmapW > 0 && bitmapH > 0) {
189         render(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap,
190                 bitmapW, bitmapH, NULL, NULL);
191     } else {
192         render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
193                 0, 0, NULL, NULL);
194     }
195 }
196 
render(SkPaint * paint,const char * text,uint32_t start,uint32_t len,int numGlyphs,int x,int y,const float * positions)197 void Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
198             int numGlyphs, int x, int y, const float* positions) {
199     render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
200             0, 0, NULL, positions);
201 }
202 
render(SkPaint * paint,const char * text,uint32_t start,uint32_t len,int numGlyphs,SkPath * path,float hOffset,float vOffset)203 void Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
204         int numGlyphs, SkPath* path, float hOffset, float vOffset) {
205     if (numGlyphs == 0 || text == NULL || len == 0) {
206         return;
207     }
208 
209     text += start;
210 
211     int glyphsCount = 0;
212     SkFixed prevRsbDelta = 0;
213 
214     float penX = 0.0f;
215 
216     SkPoint position;
217     SkVector tangent;
218 
219     SkPathMeasure measure(*path, false);
220     float pathLength = SkScalarToFloat(measure.getLength());
221 
222     if (paint->getTextAlign() != SkPaint::kLeft_Align) {
223         float textWidth = SkScalarToFloat(paint->measureText(text, len));
224         float pathOffset = pathLength;
225         if (paint->getTextAlign() == SkPaint::kCenter_Align) {
226             textWidth *= 0.5f;
227             pathOffset *= 0.5f;
228         }
229         penX += pathOffset - textWidth;
230     }
231 
232     while (glyphsCount < numGlyphs && penX < pathLength) {
233         glyph_t glyph = GET_GLYPH(text);
234 
235         if (IS_END_OF_STRING(glyph)) {
236             break;
237         }
238 
239         CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
240         penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta));
241         prevRsbDelta = cachedGlyph->mRsbDelta;
242 
243         if (cachedGlyph->mIsValid) {
244             drawCachedGlyph(cachedGlyph, penX, hOffset, vOffset, measure, &position, &tangent);
245         }
246 
247         penX += SkFixedToFloat(cachedGlyph->mAdvanceX);
248 
249         glyphsCount++;
250     }
251 }
252 
measure(SkPaint * paint,const char * text,uint32_t start,uint32_t len,int numGlyphs,Rect * bounds,const float * positions)253 void Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
254         int numGlyphs, Rect *bounds, const float* positions) {
255     if (bounds == NULL) {
256         ALOGE("No return rectangle provided to measure text");
257         return;
258     }
259     bounds->set(1e6, -1e6, -1e6, 1e6);
260     render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds, positions);
261 }
262 
precache(SkPaint * paint,const char * text,int numGlyphs)263 void Font::precache(SkPaint* paint, const char* text, int numGlyphs) {
264 
265     if (numGlyphs == 0 || text == NULL) {
266         return;
267     }
268     int glyphsCount = 0;
269 
270     while (glyphsCount < numGlyphs) {
271         glyph_t glyph = GET_GLYPH(text);
272 
273         // Reached the end of the string
274         if (IS_END_OF_STRING(glyph)) {
275             break;
276         }
277 
278         CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph, true);
279 
280         glyphsCount++;
281     }
282 }
283 
render(SkPaint * paint,const char * text,uint32_t start,uint32_t len,int numGlyphs,int x,int y,RenderMode mode,uint8_t * bitmap,uint32_t bitmapW,uint32_t bitmapH,Rect * bounds,const float * positions)284 void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
285         int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
286         uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* positions) {
287     if (numGlyphs == 0 || text == NULL || len == 0) {
288         return;
289     }
290 
291     static RenderGlyph gRenderGlyph[] = {
292             &android::uirenderer::Font::drawCachedGlyph,
293             &android::uirenderer::Font::drawCachedGlyphBitmap,
294             &android::uirenderer::Font::measureCachedGlyph
295     };
296     RenderGlyph render = gRenderGlyph[mode];
297 
298     text += start;
299     int glyphsCount = 0;
300 
301     if (CC_LIKELY(positions == NULL)) {
302         SkFixed prevRsbDelta = 0;
303 
304         float penX = x + 0.5f;
305         int penY = y;
306 
307         while (glyphsCount < numGlyphs) {
308             glyph_t glyph = GET_GLYPH(text);
309 
310             // Reached the end of the string
311             if (IS_END_OF_STRING(glyph)) {
312                 break;
313             }
314 
315             CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
316             penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta));
317             prevRsbDelta = cachedGlyph->mRsbDelta;
318 
319             // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
320             if (cachedGlyph->mIsValid) {
321                 (*this.*render)(cachedGlyph, (int) floorf(penX), penY,
322                         bitmap, bitmapW, bitmapH, bounds, positions);
323             }
324 
325             penX += SkFixedToFloat(cachedGlyph->mAdvanceX);
326 
327             glyphsCount++;
328         }
329     } else {
330         const SkPaint::Align align = paint->getTextAlign();
331 
332         // This is for renderPosText()
333         while (glyphsCount < numGlyphs) {
334             glyph_t glyph = GET_GLYPH(text);
335 
336             // Reached the end of the string
337             if (IS_END_OF_STRING(glyph)) {
338                 break;
339             }
340 
341             CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
342 
343             // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
344             if (cachedGlyph->mIsValid) {
345                 int penX = x + positions[(glyphsCount << 1)];
346                 int penY = y + positions[(glyphsCount << 1) + 1];
347 
348                 switch (align) {
349                     case SkPaint::kRight_Align:
350                         penX -= SkFixedToFloat(cachedGlyph->mAdvanceX);
351                         penY -= SkFixedToFloat(cachedGlyph->mAdvanceY);
352                         break;
353                     case SkPaint::kCenter_Align:
354                         penX -= SkFixedToFloat(cachedGlyph->mAdvanceX >> 1);
355                         penY -= SkFixedToFloat(cachedGlyph->mAdvanceY >> 1);
356                     default:
357                         break;
358                 }
359 
360                 (*this.*render)(cachedGlyph, penX, penY,
361                         bitmap, bitmapW, bitmapH, bounds, positions);
362             }
363 
364             glyphsCount++;
365         }
366     }
367 }
368 
updateGlyphCache(SkPaint * paint,const SkGlyph & skiaGlyph,CachedGlyphInfo * glyph,bool precaching)369 void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph,
370         bool precaching) {
371     glyph->mAdvanceX = skiaGlyph.fAdvanceX;
372     glyph->mAdvanceY = skiaGlyph.fAdvanceY;
373     glyph->mBitmapLeft = skiaGlyph.fLeft;
374     glyph->mBitmapTop = skiaGlyph.fTop;
375     glyph->mLsbDelta = skiaGlyph.fLsbDelta;
376     glyph->mRsbDelta = skiaGlyph.fRsbDelta;
377 
378     uint32_t startX = 0;
379     uint32_t startY = 0;
380 
381     // Get the bitmap for the glyph
382     paint->findImage(skiaGlyph);
383     mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY, precaching);
384 
385     if (!glyph->mIsValid) {
386         return;
387     }
388 
389     uint32_t endX = startX + skiaGlyph.fWidth;
390     uint32_t endY = startY + skiaGlyph.fHeight;
391 
392     glyph->mStartX = startX;
393     glyph->mStartY = startY;
394     glyph->mBitmapWidth = skiaGlyph.fWidth;
395     glyph->mBitmapHeight = skiaGlyph.fHeight;
396 
397     uint32_t cacheWidth = glyph->mCacheTexture->getWidth();
398     uint32_t cacheHeight = glyph->mCacheTexture->getHeight();
399 
400     glyph->mBitmapMinU = startX / (float) cacheWidth;
401     glyph->mBitmapMinV = startY / (float) cacheHeight;
402     glyph->mBitmapMaxU = endX / (float) cacheWidth;
403     glyph->mBitmapMaxV = endY / (float) cacheHeight;
404 
405     mState->setTextureDirty();
406 }
407 
cacheGlyph(SkPaint * paint,glyph_t glyph,bool precaching)408 CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph, bool precaching) {
409     CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
410     mCachedGlyphs.add(glyph, newGlyph);
411 
412     const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph);
413     newGlyph->mGlyphIndex = skiaGlyph.fID;
414     newGlyph->mIsValid = false;
415 
416     updateGlyphCache(paint, skiaGlyph, newGlyph, precaching);
417 
418     return newGlyph;
419 }
420 
create(FontRenderer * state,uint32_t fontId,float fontSize,int flags,uint32_t italicStyle,uint32_t scaleX,SkPaint::Style style,uint32_t strokeWidth)421 Font* Font::create(FontRenderer* state, uint32_t fontId, float fontSize,
422         int flags, uint32_t italicStyle, uint32_t scaleX,
423         SkPaint::Style style, uint32_t strokeWidth) {
424     Vector<Font*> &activeFonts = state->mActiveFonts;
425 
426     for (uint32_t i = 0; i < activeFonts.size(); i++) {
427         Font* font = activeFonts[i];
428         if (font->mFontId == fontId && font->mFontSize == fontSize &&
429                 font->mFlags == flags && font->mItalicStyle == italicStyle &&
430                 font->mScaleX == scaleX && font->mStyle == style &&
431                 (style == SkPaint::kFill_Style || font->mStrokeWidth == strokeWidth)) {
432             return font;
433         }
434     }
435 
436     Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle,
437             scaleX, style, strokeWidth);
438     activeFonts.push(newFont);
439     return newFont;
440 }
441 
442 }; // namespace uirenderer
443 }; // namespace android
444