FontRenderer.cpp revision 2577db1ec135a1470a2c42139772ec97a6c30e78
1694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/* 2694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * Copyright (C) 2010 The Android Open Source Project 3694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * 4694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * Licensed under the Apache License, Version 2.0 (the "License"); 5694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * you may not use this file except in compliance with the License. 6694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * You may obtain a copy of the License at 7694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * 8694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * http://www.apache.org/licenses/LICENSE-2.0 9694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * 10694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * Unless required by applicable law or agreed to in writing, software 11694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * distributed under the License is distributed on an "AS IS" BASIS, 12694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * See the License for the specific language governing permissions and 14694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * limitations under the License. 15694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy */ 16694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 17694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy#define LOG_TAG "OpenGLRenderer" 18694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 19694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy#include <SkUtils.h> 20694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 2151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#include <cutils/properties.h> 22e2d345ea67e2960b37bfdc0fc8626d1bfa747404Romain Guy 2351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#include <utils/Log.h> 2451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 2551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#include "FontRenderer.h" 2651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 27694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guynamespace android { 28694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guynamespace uirenderer { 29694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 30694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 3151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy// Defines 3251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy/////////////////////////////////////////////////////////////////////////////// 3351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 3451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#define DEFAULT_TEXT_CACHE_WIDTH 1024 3551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#define DEFAULT_TEXT_CACHE_HEIGHT 256 3651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 3751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy/////////////////////////////////////////////////////////////////////////////// 38694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Font 39694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 40694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 412577db1ec135a1470a2c42139772ec97a6c30e78Romain GuyFont::Font(FontRenderer* state, uint32_t fontId, float fontSize, 422577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy int flags, uint32_t italicStyle) : 432577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy mState(state), mFontId(fontId), mFontSize(fontSize), 442577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy mFlags(flags), mItalicStyle(italicStyle) { 45694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 46694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 47694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 48694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFont::~Font() { 49694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t ct = 0; ct < mState->mActiveFonts.size(); ct++) { 50694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mState->mActiveFonts[ct] == this) { 51694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mState->mActiveFonts.removeAt(ct); 52694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 53694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 54694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 55694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 56694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) { 5751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy CachedGlyphInfo* glyph = mCachedGlyphs.valueAt(i); 58694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy delete glyph; 59694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 60694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 61694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 62694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid Font::invalidateTextureCache() { 63694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) { 64694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCachedGlyphs.valueAt(i)->mIsValid = false; 65694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 66694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 67694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 68f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchoukvoid Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y, Rect *bounds) { 69f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int nPenX = x + glyph->mBitmapLeft; 70f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int nPenY = y + glyph->mBitmapTop; 71f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 72f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int width = (int) glyph->mBitmapWidth; 73f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int height = (int) glyph->mBitmapHeight; 74f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 7561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->bottom > nPenY) { 76f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->bottom = nPenY; 77f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 7861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->left > nPenX) { 79f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->left = nPenX; 80f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 8161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->right < nPenX + width) { 82f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->right = nPenX + width; 83f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 8461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->top < nPenY + height) { 85f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->top = nPenY + height; 86f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 87f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 88f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 89694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y) { 90694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int nPenX = x + glyph->mBitmapLeft; 91694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight; 92694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 9351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float u1 = glyph->mBitmapMinU; 9451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float u2 = glyph->mBitmapMaxU; 9551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float v1 = glyph->mBitmapMinV; 9651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float v2 = glyph->mBitmapMaxV; 9751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 9851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy int width = (int) glyph->mBitmapWidth; 9951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy int height = (int) glyph->mBitmapHeight; 10051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 10151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mState->appendMeshQuad(nPenX, nPenY, 0, u1, v2, 10251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy nPenX + width, nPenY, 0, u2, v2, 10351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy nPenX + width, nPenY - height, 0, u2, v1, 10451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy nPenX, nPenY - height, 0, u1, v1); 105694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 106694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 107b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guyvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, 108b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) { 10989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int nPenX = x + glyph->mBitmapLeft; 11089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int nPenY = y + glyph->mBitmapTop; 11189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 11289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint32_t endX = glyph->mStartX + glyph->mBitmapWidth; 11389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint32_t endY = glyph->mStartY + glyph->mBitmapHeight; 11489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 11589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint32_t cacheWidth = mState->getCacheWidth(); 11689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* cacheBuffer = mState->getTextTextureData(); 11789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 118f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk uint32_t cacheX = 0, cacheY = 0; 119f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int32_t bX = 0, bY = 0; 12089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) { 12189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) { 122b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) { 123f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk LOGE("Skipping invalid index"); 124f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk continue; 125f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 12689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX]; 12789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk bitmap[bY * bitmapW + bX] = tempCol; 12889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 12989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 13089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 13189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 13289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 13365ef909776c03417d8b597738da54ca211e37e4fAlex SakhartchoukFont::CachedGlyphInfo* Font::getCachedUTFChar(SkPaint* paint, int32_t utfChar) { 1341e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy CachedGlyphInfo* cachedGlyph = NULL; 1351e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy ssize_t index = mCachedGlyphs.indexOfKey(utfChar); 1361e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (index >= 0) { 1371e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy cachedGlyph = mCachedGlyphs.valueAt(index); 1381e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } else { 13965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk cachedGlyph = cacheGlyph(paint, utfChar); 14065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 14165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 14265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk // Is the glyph still in texture cache? 14365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk if (!cachedGlyph->mIsValid) { 14465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk const SkGlyph& skiaGlyph = paint->getUnicharMetrics(utfChar); 14565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk updateGlyphCache(paint, skiaGlyph, cachedGlyph); 14665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 14765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 14865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk return cachedGlyph; 14965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk} 15065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 15151769a68a5cb34e9564740c6a854fcb93018789dRomain Guyvoid Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 15261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy int numGlyphs, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) { 15361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bitmap != NULL && bitmapW > 0 && bitmapH > 0) { 15461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy renderUTF(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap, 15561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy bitmapW, bitmapH, NULL); 15661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy } else { 15761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy renderUTF(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL, 0, 0, NULL); 158f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 159f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 160f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 161f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 162f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchoukvoid Font::measureUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 16361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy int numGlyphs, Rect *bounds) { 16461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds == NULL) { 165f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk LOGE("No return rectangle provided to measure text"); 166f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk return; 167f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 168f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->set(1e6, -1e6, -1e6, 1e6); 169f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk renderUTF(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds); 170f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 171f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 17258ef7fbf16864164efe98bf613b15c64deb1afc0Romain Guy#define SkAutoKern_AdjustF(prev, next) (((next) - (prev) + 32) >> 6 << 16) 1732bffd268f135df8308c9e67af110525a5c463424Romain Guy 174f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchoukvoid Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 17561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap, 17661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy uint32_t bitmapW, uint32_t bitmapH,Rect *bounds) { 177694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (numGlyphs == 0 || text == NULL || len == 0) { 178694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 179694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 180694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1812bffd268f135df8308c9e67af110525a5c463424Romain Guy SkFixed penX = SkIntToFixed(x); 1822bffd268f135df8308c9e67af110525a5c463424Romain Guy int penY = y; 183694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int glyphsLeft = 1; 184694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (numGlyphs > 0) { 185694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyphsLeft = numGlyphs; 186694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 187694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1882bffd268f135df8308c9e67af110525a5c463424Romain Guy SkFixed prevRsbDelta = 0; 1892bffd268f135df8308c9e67af110525a5c463424Romain Guy penX += SK_Fixed1 / 2; 1902bffd268f135df8308c9e67af110525a5c463424Romain Guy 191694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy text += start; 192694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 193694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy while (glyphsLeft > 0) { 194694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int32_t utfChar = SkUTF16_NextUnichar((const uint16_t**) &text); 195694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 19661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy // Reached the end of the string 197694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (utfChar < 0) { 198694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 199694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 200694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 20165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk CachedGlyphInfo* cachedGlyph = getCachedUTFChar(paint, utfChar); 2022bffd268f135df8308c9e67af110525a5c463424Romain Guy penX += SkAutoKern_AdjustF(prevRsbDelta, cachedGlyph->mLsbDelta); 2032bffd268f135df8308c9e67af110525a5c463424Romain Guy prevRsbDelta = cachedGlyph->mRsbDelta; 204694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 205694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage 206694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (cachedGlyph->mIsValid) { 207f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk switch(mode) { 208f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk case FRAMEBUFFER: 2092bffd268f135df8308c9e67af110525a5c463424Romain Guy drawCachedGlyph(cachedGlyph, SkFixedFloor(penX), penY); 210f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk break; 211f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk case BITMAP: 2122bffd268f135df8308c9e67af110525a5c463424Romain Guy drawCachedGlyph(cachedGlyph, SkFixedFloor(penX), penY, bitmap, bitmapW, bitmapH); 213f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk break; 214f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk case MEASURE: 2152bffd268f135df8308c9e67af110525a5c463424Romain Guy measureCachedGlyph(cachedGlyph, SkFixedFloor(penX), penY, bounds); 216f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk break; 21789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 218694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 219694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 2202bffd268f135df8308c9e67af110525a5c463424Romain Guy penX += cachedGlyph->mAdvanceX; 221694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 222694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If we were given a specific number of glyphs, decrement 223694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (numGlyphs > 0) { 224694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyphsLeft--; 225694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 226694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 227694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 228694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 22951769a68a5cb34e9564740c6a854fcb93018789dRomain Guyvoid Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph) { 230694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mAdvanceX = skiaGlyph.fAdvanceX; 231694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mAdvanceY = skiaGlyph.fAdvanceY; 232694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapLeft = skiaGlyph.fLeft; 233694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapTop = skiaGlyph.fTop; 2342bffd268f135df8308c9e67af110525a5c463424Romain Guy glyph->mLsbDelta = skiaGlyph.fLsbDelta; 2352bffd268f135df8308c9e67af110525a5c463424Romain Guy glyph->mRsbDelta = skiaGlyph.fRsbDelta; 236694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 237694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startX = 0; 238694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startY = 0; 239694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 240694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Get the bitmap for the glyph 241694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy paint->findImage(skiaGlyph); 24251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy glyph->mIsValid = mState->cacheBitmap(skiaGlyph, &startX, &startY); 243694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 244694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!glyph->mIsValid) { 245694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 246694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 247694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 248694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endX = startX + skiaGlyph.fWidth; 249694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endY = startY + skiaGlyph.fHeight; 250694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 25189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk glyph->mStartX = startX; 25289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk glyph->mStartY = startY; 253694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapWidth = skiaGlyph.fWidth; 254694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapHeight = skiaGlyph.fHeight; 255694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 25651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy uint32_t cacheWidth = mState->getCacheWidth(); 25751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy uint32_t cacheHeight = mState->getCacheHeight(); 258694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 259694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapMinU = (float) startX / (float) cacheWidth; 260694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapMinV = (float) startY / (float) cacheHeight; 261694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapMaxU = (float) endX / (float) cacheWidth; 262694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapMaxV = (float) endY / (float) cacheHeight; 263694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 26451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mState->mUploadTexture = true; 265694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 266694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 26751769a68a5cb34e9564740c6a854fcb93018789dRomain GuyFont::CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, int32_t glyph) { 26851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy CachedGlyphInfo* newGlyph = new CachedGlyphInfo(); 269694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCachedGlyphs.add(glyph, newGlyph); 270694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 271694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy const SkGlyph& skiaGlyph = paint->getUnicharMetrics(glyph); 272694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy newGlyph->mGlyphIndex = skiaGlyph.fID; 273694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy newGlyph->mIsValid = false; 274694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 275694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy updateGlyphCache(paint, skiaGlyph, newGlyph); 276694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 277694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return newGlyph; 278694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 279694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 2802577db1ec135a1470a2c42139772ec97a6c30e78Romain GuyFont* Font::create(FontRenderer* state, uint32_t fontId, float fontSize, 2812577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy int flags, uint32_t italicStyle) { 282694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy Vector<Font*> &activeFonts = state->mActiveFonts; 283694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 284694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < activeFonts.size(); i++) { 28551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy Font* font = activeFonts[i]; 2862577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy if (font->mFontId == fontId && font->mFontSize == fontSize && 2872577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy font->mFlags == flags && font->mItalicStyle == italicStyle) { 28851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy return font; 289694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 290694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 291694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 2922577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle); 293694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy activeFonts.push(newFont); 294694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return newFont; 295694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 296694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 297694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 298694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// FontRenderer 299694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 300694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 301694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::FontRenderer() { 30251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy LOGD("Creating FontRenderer"); 30351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 304b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy mGammaTable = NULL; 305694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mInitialized = false; 306694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mMaxNumberOfQuads = 1024; 307694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 3089b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mTextureId = 0; 309694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 3109cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy mTextMeshPtr = NULL; 3119cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy mTextTexture = NULL; 3129cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy 313694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mIndexBufferID = 0; 314694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 31551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheWidth = DEFAULT_TEXT_CACHE_WIDTH; 3169b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT; 31751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 31851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy char property[PROPERTY_VALUE_MAX]; 31951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) { 32051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy LOGD(" Setting text cache width to %s pixels", property); 32151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheWidth = atoi(property); 32251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } else { 32351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy LOGD(" Using default text cache width of %i pixels", mCacheWidth); 32451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } 32551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 32651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy if (property_get(PROPERTY_TEXT_CACHE_HEIGHT, property, NULL) > 0) { 32751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy LOGD(" Setting text cache width to %s pixels", property); 32851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheHeight = atoi(property); 32951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } else { 33051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy LOGD(" Using default text cache height of %i pixels", mCacheHeight); 33151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } 332694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 333694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 334694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::~FontRenderer() { 335694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 336694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy delete mCacheLines[i]; 337694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 338694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCacheLines.clear(); 339694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 3409cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy if (mInitialized) { 3419cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy delete[] mTextMeshPtr; 3429cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy delete[] mTextTexture; 3439cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy } 3449b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 3459cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy if (mTextureId) { 3469b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk glDeleteTextures(1, &mTextureId); 3479b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 348694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 349694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy Vector<Font*> fontsToDereference = mActiveFonts; 350694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < fontsToDereference.size(); i++) { 351694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy delete fontsToDereference[i]; 352694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 353694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 354694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 355694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::flushAllAndInvalidate() { 356694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex != 0) { 357694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 358694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 359694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 360694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mActiveFonts.size(); i++) { 361694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mActiveFonts[i]->invalidateTextureCache(); 362694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 363694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 364694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCacheLines[i]->mCurrentCol = 0; 365694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 366694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 367694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 36851769a68a5cb34e9564740c6a854fcb93018789dRomain Guybool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) { 369694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If the glyph is too tall, don't cache it 3702bffd268f135df8308c9e67af110525a5c463424Romain Guy if (glyph.fHeight > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) { 371694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy LOGE("Font size to large to fit in cache. width, height = %i, %i", 372694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (int) glyph.fWidth, (int) glyph.fHeight); 373694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return false; 374694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 375694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 376694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Now copy the bitmap into the cache texture 377694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startX = 0; 378694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startY = 0; 379694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 380694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bool bitmapFit = false; 381694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 382694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY); 383694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (bitmapFit) { 384694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 385694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 386694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 387694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 388694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If the new glyph didn't fit, flush the state so far and invalidate everything 389694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!bitmapFit) { 390694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy flushAllAndInvalidate(); 391694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 392694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Try to fit it again 393694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 394694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY); 395694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (bitmapFit) { 396694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 397694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 398694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 399694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 400694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // if we still don't fit, something is wrong and we shouldn't draw 401694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!bitmapFit) { 402694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", 403694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (int) glyph.fWidth, (int) glyph.fHeight); 404694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return false; 405694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 406694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 407694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 408694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *retOriginX = startX; 409694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *retOriginY = startY; 410694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 411694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endX = startX + glyph.fWidth; 412694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endY = startY + glyph.fHeight; 413694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 414694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t cacheWidth = mCacheWidth; 415694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 41689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* cacheBuffer = mTextTexture; 41789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage; 418694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy unsigned int stride = glyph.rowBytes(); 419694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 420694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; 421694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) { 422694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) { 42389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t tempCol = bitmapBuffer[bY * stride + bX]; 424b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol]; 425694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 426694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 427694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 428694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return true; 429694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 430694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 431694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::initTextTexture() { 43289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk mTextTexture = new uint8_t[mCacheWidth * mCacheHeight]; 4331de1083e98cde9bdd5e8539dbc54fdea6531906eRomain Guy memset(mTextTexture, 0, mCacheWidth * mCacheHeight * sizeof(uint8_t)); 4341de1083e98cde9bdd5e8539dbc54fdea6531906eRomain Guy 435694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mUploadTexture = false; 436694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 437694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glGenTextures(1, &mTextureId); 438694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glBindTexture(GL_TEXTURE_2D, mTextureId); 439694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 4409b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk // Initialize texture dimentions 4419b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mCacheWidth, mCacheHeight, 0, 44261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy GL_ALPHA, GL_UNSIGNED_BYTE, 0); 443694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 444e8cb9c14309b0f01c0159efdf9a7198f44a62642Romain Guy mLinearFiltering = false; 445e8cb9c14309b0f01c0159efdf9a7198f44a62642Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 446e8cb9c14309b0f01c0159efdf9a7198f44a62642Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 447694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 448694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 449694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 450694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 451694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Split up our cache texture into lines of certain widths 452694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int nextLine = 0; 4537975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 18, nextLine, 0)); 454694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 4557975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 26, nextLine, 0)); 456694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 4577975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 26, nextLine, 0)); 45865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk nextLine += mCacheLines.top()->mMaxHeight; 4597975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 34, nextLine, 0)); 460694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 4617975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 34, nextLine, 0)); 462694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 4637975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 42, nextLine, 0)); 464694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 46551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, mCacheHeight - nextLine, nextLine, 0)); 466694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 467694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 468694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Avoid having to reallocate memory and render quad by quad 469694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::initVertexArrayBuffers() { 470694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t numIndicies = mMaxNumberOfQuads * 6; 471694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t indexBufferSizeBytes = numIndicies * sizeof(uint16_t); 47251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes); 473694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 474694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Four verts, two triangles , six indices per quad 475694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mMaxNumberOfQuads; i++) { 476694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int i6 = i * 6; 477694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int i4 = i * 4; 478694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 479694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 0] = i4 + 0; 480694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 1] = i4 + 1; 481694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 2] = i4 + 2; 482694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 483694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 3] = i4 + 0; 484694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 4] = i4 + 2; 485694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 5] = i4 + 3; 486694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 487694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 488694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glGenBuffers(1, &mIndexBufferID); 4895d794412e3e429e47404395badcd11b0b8639e8bRomain Guy glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID); 4905d794412e3e429e47404395badcd11b0b8639e8bRomain Guy glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_STATIC_DRAW); 4915d794412e3e429e47404395badcd11b0b8639e8bRomain Guy glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 492694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 493694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy free(indexBufferData); 494694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 495694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t coordSize = 3; 496694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t uvSize = 2; 497694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t vertsPerQuad = 4; 4989b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize; 4999b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mTextMeshPtr = new float[vertexBufferSize]; 500694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 501694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 502694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// We don't want to allocate anything unless we actually draw text 503694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::checkInit() { 504694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mInitialized) { 505694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 506694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 507694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 508694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy initTextTexture(); 509694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy initVertexArrayBuffers(); 510694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 51165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk // We store a string with letters in a rough frequency of occurrence 51265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mLatinPrecache = String16("eisarntolcdugpmhbyfvkwzxjq "); 51365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mLatinPrecache += String16("EISARNTOLCDUGPMHBYFVKWZXJQ"); 51465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mLatinPrecache += String16(",.?!()-+@;:`'"); 51565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mLatinPrecache += String16("0123456789"); 51665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 517694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mInitialized = true; 518694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 519694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 5209b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::checkTextureUpdate() { 5219b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk if (!mUploadTexture) { 5229b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk return; 5239b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 5249b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5259b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk glBindTexture(GL_TEXTURE_2D, mTextureId); 5269b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5279b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk // Iterate over all the cache lines and see which ones need to be updated 5289b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk for (uint32_t i = 0; i < mCacheLines.size(); i++) { 5299b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk CacheTextureLine* cl = mCacheLines[i]; 5309b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk if(cl->mDirty) { 5319b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t xOffset = 0; 5329b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t yOffset = cl->mCurrentRow; 5339b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t width = mCacheWidth; 5349b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t height = cl->mMaxHeight; 5351e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy void* textureData = mTextTexture + yOffset*width; 5369b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5379b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height, 5381e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy GL_ALPHA, GL_UNSIGNED_BYTE, textureData); 5399b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5409b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk cl->mDirty = false; 5419b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 542694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 543694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 5449b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mUploadTexture = false; 5459b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk} 5469b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5479b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::issueDrawCommand() { 5489b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk checkTextureUpdate(); 5499b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 55051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float* vtx = mTextMeshPtr; 55151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float* tex = vtx + 3; 552694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 553694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // position is slot 0 554694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t slot = 0; 555694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glVertexAttribPointer(slot, 3, GL_FLOAT, false, 20, vtx); 556694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 557694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // texture0 is slot 1 558694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy slot = 1; 559694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glVertexAttribPointer(slot, 2, GL_FLOAT, false, 20, tex); 560694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 561694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID); 562694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL); 5635b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 5645b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mDrawn = true; 565694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 566694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 567694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::appendMeshQuad(float x1, float y1, float z1, float u1, float v1, float x2, 568694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3, 569694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy float x4, float y4, float z4, float u4, float v4) { 57009147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy if (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom) { 57109147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy return; 57209147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy } 57309147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy 574694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy const uint32_t vertsPerQuad = 4; 575694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy const uint32_t floatsPerVert = 5; 57651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float* currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert; 577694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 578694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x1; 579694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y1; 580694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = z1; 581694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u1; 582694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v1; 583694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 584694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x2; 585694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y2; 586694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = z2; 587694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u2; 588694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v2; 589694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 590694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x3; 591694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y3; 592694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = z3; 593694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u3; 594694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v3; 595694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 596694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x4; 597694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y4; 598694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = z4; 599694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u4; 600694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v4; 601694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 602694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex++; 603694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 6045b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy if (mBounds) { 6055b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->left = fmin(mBounds->left, x1); 6065b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->top = fmin(mBounds->top, y3); 6075b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->right = fmax(mBounds->right, x3); 6085b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->bottom = fmax(mBounds->bottom, y1); 6095b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy } 6105b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 611694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex == mMaxNumberOfQuads) { 612694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 613694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 614694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 615694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 616694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 61765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukuint32_t FontRenderer::getRemainingCacheCapacity() { 61865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t remainingCapacity = 0; 61965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk float totalPixels = 0; 62065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 62165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol); 62265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk totalPixels += mCacheLines[i]->mMaxWidth; 62365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 62465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk remainingCapacity = (remainingCapacity * 100) / totalPixels; 62565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk return remainingCapacity; 62665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk} 62765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 62865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::precacheLatin(SkPaint* paint) { 62965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk // Remaining capacity is measured in % 63065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t remainingCapacity = getRemainingCacheCapacity(); 63165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t precacheIdx = 0; 632054dc1840941665e32036f9523df51720ad069c8Romain Guy while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) { 633054dc1840941665e32036f9523df51720ad069c8Romain Guy mCurrentFont->getCachedUTFChar(paint, (int32_t) mLatinPrecache[precacheIdx]); 63465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk remainingCapacity = getRemainingCacheCapacity(); 63565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk precacheIdx ++; 63665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 63765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk} 63865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 63965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) { 64065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t currentNumFonts = mActiveFonts.size(); 641325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy int flags = 0; 642325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (paint->isFakeBoldText()) { 643325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy flags |= Font::kFakeBold; 644325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy } 6452577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy 6462577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy const float skewX = paint->getTextSkewX(); 6472577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy uint32_t italicStyle = *(uint32_t*) &skewX; 6482577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle); 64965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 65065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk const float maxPrecacheFontSize = 40.0f; 65165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk bool isNewFont = currentNumFonts != mActiveFonts.size(); 65265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 6532bffd268f135df8308c9e67af110525a5c463424Romain Guy if (isNewFont && fontSize <= maxPrecacheFontSize) { 65465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk precacheLatin(paint); 65565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 656694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 6577975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy 658f18136cb3c881a9d16c1a4f0f341732c276936bfAlex SakhartchoukFontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text, 6591e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius) { 6601e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy checkInit(); 6611e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 6621e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (!mCurrentFont) { 6631e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy DropShadow image; 6641e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.width = 0; 6651e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.height = 0; 6661e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.image = NULL; 6671e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.penX = 0; 6681e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.penY = 0; 6691e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy return image; 6701e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } 671f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 672f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk Rect bounds; 673f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk mCurrentFont->measureUTF(paint, text, startIndex, len, numGlyphs, &bounds); 6741e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius; 6751e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius; 676f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight]; 6771e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy for (uint32_t i = 0; i < paddedWidth * paddedHeight; i++) { 678f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk dataBuffer[i] = 0; 679f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 6801e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 681f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int penX = radius - bounds.left; 682f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int penY = radius - bounds.bottom; 683f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 684f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, penX, penY, 6851e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy dataBuffer, paddedWidth, paddedHeight); 686f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk blurImage(dataBuffer, paddedWidth, paddedHeight, radius); 687f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 688f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk DropShadow image; 689f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.width = paddedWidth; 690f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.height = paddedHeight; 691f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.image = dataBuffer; 692f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.penX = penX; 693f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.penY = penY; 694f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk return image; 695f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 696694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 6975b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guybool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text, 6985b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, Rect* bounds) { 699694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy checkInit(); 700694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 70109147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy if (!mCurrentFont) { 70209147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy LOGE("No font set"); 7035b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy return false; 704694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 705694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 7065b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mDrawn = false; 7075b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds = bounds; 70809147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy mClip = clip; 70951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, x, y); 7105b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds = NULL; 711694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 712694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex != 0) { 713694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 714694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 715694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 7165b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 7175b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy return mDrawn; 718694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 719694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 72089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::computeGaussianWeights(float* weights, int32_t radius) { 72189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Compute gaussian weights for the blur 72289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // e is the euler's number 72389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float e = 2.718281828459045f; 72489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float pi = 3.1415926535897932f; 72589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 ) 72689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // x is of the form [-radius .. 0 .. radius] 72789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // and sigma varies with radius. 72889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Based on some experimental radius values and sigma's 72989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // we approximately fit sigma = f(radius) as 730f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk // sigma = radius * 0.3 + 0.6 73189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // The larger the radius gets, the more our gaussian blur 73289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // will resemble a box blur since with large sigma 73389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // the gaussian curve begins to lose its shape 734325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy float sigma = 0.3f * (float) radius + 0.6f; 73589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 73689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Now compute the coefficints 73789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // We will store some redundant values to save some math during 73889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // the blur calculations 73989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // precompute some values 74089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma); 74189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float coeff2 = - 1.0f / (2.0f * sigma * sigma); 74289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 74389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float normalizeFactor = 0.0f; 744325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 7457975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy float floatR = (float) r; 74689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2); 74789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk normalizeFactor += weights[r + radius]; 74889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 74989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 75089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk //Now we need to normalize the weights because all our coefficients need to add up to one 75189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk normalizeFactor = 1.0f / normalizeFactor; 752325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 75389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk weights[r + radius] *= normalizeFactor; 75489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 75589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 75689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 75789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::horizontalBlur(float* weights, int32_t radius, 7581e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) { 75989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float blurredPixel = 0.0f; 76089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float currentPixel = 0.0f; 76189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 762325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t y = 0; y < height; y ++) { 76389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 76489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* input = source + y * width; 76589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* output = dest + y * width; 76689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 767325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t x = 0; x < width; x ++) { 76889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel = 0.0f; 76989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const float* gPtr = weights; 77089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Optimization for non-border pixels 771325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (x > radius && x < (width - radius)) { 77289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + (x - radius); 773325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int r = -radius; r <= radius; r ++) { 7747975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy currentPixel = (float) (*i); 77589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 77689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 77789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk i++; 77889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 77989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } else { 780325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 78189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Stepping left and right away from the pixel 78289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int validW = x + r; 783325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validW < 0) { 78489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validW = 0; 78589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 786325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validW > width - 1) { 78789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validW = width - 1; 78889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 78989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 790325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy currentPixel = (float) input[validW]; 79189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 79289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 79389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 79489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 79589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk *output = (uint8_t)blurredPixel; 79689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk output ++; 79789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 79889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 79989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 80089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 80189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::verticalBlur(float* weights, int32_t radius, 8021e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) { 80389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float blurredPixel = 0.0f; 80489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float currentPixel = 0.0f; 80589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 806325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t y = 0; y < height; y ++) { 80789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 80889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* output = dest + y * width; 80989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 810325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t x = 0; x < width; x ++) { 81189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel = 0.0f; 81289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const float* gPtr = weights; 81389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* input = source + x; 81489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Optimization for non-border pixels 815325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (y > radius && y < (height - radius)) { 81689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + ((y - radius) * width); 817325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 81889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk currentPixel = (float)(*i); 81989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 82089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 82189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk i += width; 82289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 82389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } else { 824325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 82589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int validH = y + r; 82689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Clamp to zero and width 827325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validH < 0) { 82889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validH = 0; 82989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 830325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validH > height - 1) { 83189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validH = height - 1; 83289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 83389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 83489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + validH * width; 835325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy currentPixel = (float) (*i); 83689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 83789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 83889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 83989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 840325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy *output = (uint8_t) blurredPixel; 84189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk output ++; 84289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 84389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 84489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 84589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 84689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 84789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::blurImage(uint8_t *image, int32_t width, int32_t height, int32_t radius) { 84889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float *gaussian = new float[2 * radius + 1]; 84989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk computeGaussianWeights(gaussian, radius); 85089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* scratch = new uint8_t[width * height]; 85189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk horizontalBlur(gaussian, radius, image, scratch, width, height); 85289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk verticalBlur(gaussian, radius, scratch, image, width, height); 85389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk delete[] gaussian; 85489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk delete[] scratch; 85589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 85689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 857694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace uirenderer 858694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace android 859