FontRenderer.cpp revision 8668f8a633d9299091556c3b2e5ae07be8dce360
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 25c9855a53edfac818dc68714557185977556f849dRomain Guy#include "Debug.h" 2651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#include "FontRenderer.h" 2751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 28694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guynamespace android { 29694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guynamespace uirenderer { 30694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 31694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 3251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy// Defines 3351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy/////////////////////////////////////////////////////////////////////////////// 3451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 3551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#define DEFAULT_TEXT_CACHE_WIDTH 1024 3651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#define DEFAULT_TEXT_CACHE_HEIGHT 256 3751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 3851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy/////////////////////////////////////////////////////////////////////////////// 39694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Font 40694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 41694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 422577db1ec135a1470a2c42139772ec97a6c30e78Romain GuyFont::Font(FontRenderer* state, uint32_t fontId, float fontSize, 438668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase int flags, uint32_t italicStyle, uint32_t scaleX) : 442577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy mState(state), mFontId(fontId), mFontSize(fontSize), 458668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase mFlags(flags), mItalicStyle(italicStyle), mScaleX(scaleX) { 46694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 47694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 48694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 49694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFont::~Font() { 50694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t ct = 0; ct < mState->mActiveFonts.size(); ct++) { 51694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mState->mActiveFonts[ct] == this) { 52694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mState->mActiveFonts.removeAt(ct); 53694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 54694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 55694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 56694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 57694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) { 5851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy CachedGlyphInfo* glyph = mCachedGlyphs.valueAt(i); 59694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy delete glyph; 60694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 61694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 62694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 63694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid Font::invalidateTextureCache() { 64694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) { 65694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCachedGlyphs.valueAt(i)->mIsValid = false; 66694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 67694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 68694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 69f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchoukvoid Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y, Rect *bounds) { 70f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int nPenX = x + glyph->mBitmapLeft; 71f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int nPenY = y + glyph->mBitmapTop; 72f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 73f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int width = (int) glyph->mBitmapWidth; 74f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int height = (int) glyph->mBitmapHeight; 75f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 7661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->bottom > nPenY) { 77f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->bottom = nPenY; 78f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 7961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->left > nPenX) { 80f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->left = nPenX; 81f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 8261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->right < nPenX + width) { 83f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->right = nPenX + width; 84f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 8561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->top < nPenY + height) { 86f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->top = nPenY + height; 87f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 88f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 89f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 90694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y) { 91694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int nPenX = x + glyph->mBitmapLeft; 92694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight; 93694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 9451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float u1 = glyph->mBitmapMinU; 9551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float u2 = glyph->mBitmapMaxU; 9651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float v1 = glyph->mBitmapMinV; 9751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float v2 = glyph->mBitmapMaxV; 9851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 9951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy int width = (int) glyph->mBitmapWidth; 10051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy int height = (int) glyph->mBitmapHeight; 10151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 10251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mState->appendMeshQuad(nPenX, nPenY, 0, u1, v2, 10351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy nPenX + width, nPenY, 0, u2, v2, 10451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy nPenX + width, nPenY - height, 0, u2, v1, 10551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy nPenX, nPenY - height, 0, u1, v1); 106694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 107694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 108b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guyvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, 109b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) { 11089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int nPenX = x + glyph->mBitmapLeft; 11189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int nPenY = y + glyph->mBitmapTop; 11289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 11389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint32_t endX = glyph->mStartX + glyph->mBitmapWidth; 11489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint32_t endY = glyph->mStartY + glyph->mBitmapHeight; 11589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 11689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint32_t cacheWidth = mState->getCacheWidth(); 11789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* cacheBuffer = mState->getTextTextureData(); 11889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 119f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk uint32_t cacheX = 0, cacheY = 0; 120f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int32_t bX = 0, bY = 0; 12189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) { 12289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) { 123b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) { 124f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk LOGE("Skipping invalid index"); 125f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk continue; 126f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 12789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX]; 12889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk bitmap[bY * bitmapW + bX] = tempCol; 12989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 13089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 13189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 13289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 13389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 13465ef909776c03417d8b597738da54ca211e37e4fAlex SakhartchoukFont::CachedGlyphInfo* Font::getCachedUTFChar(SkPaint* paint, int32_t utfChar) { 1351e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy CachedGlyphInfo* cachedGlyph = NULL; 1361e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy ssize_t index = mCachedGlyphs.indexOfKey(utfChar); 1371e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (index >= 0) { 1381e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy cachedGlyph = mCachedGlyphs.valueAt(index); 1391e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } else { 14065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk cachedGlyph = cacheGlyph(paint, utfChar); 14165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 14265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 14365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk // Is the glyph still in texture cache? 14465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk if (!cachedGlyph->mIsValid) { 14565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk const SkGlyph& skiaGlyph = paint->getUnicharMetrics(utfChar); 14665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk updateGlyphCache(paint, skiaGlyph, cachedGlyph); 14765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 14865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 14965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk return cachedGlyph; 15065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk} 15165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 15251769a68a5cb34e9564740c6a854fcb93018789dRomain Guyvoid Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 15361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy int numGlyphs, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) { 15461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bitmap != NULL && bitmapW > 0 && bitmapH > 0) { 15561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy renderUTF(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap, 15661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy bitmapW, bitmapH, NULL); 15761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy } else { 15861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy renderUTF(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL, 0, 0, NULL); 159f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 160f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 161f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 162f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 163f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchoukvoid Font::measureUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 16461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy int numGlyphs, Rect *bounds) { 16561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds == NULL) { 166f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk LOGE("No return rectangle provided to measure text"); 167f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk return; 168f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 169f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->set(1e6, -1e6, -1e6, 1e6); 170f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk renderUTF(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds); 171f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 172f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 17358ef7fbf16864164efe98bf613b15c64deb1afc0Romain Guy#define SkAutoKern_AdjustF(prev, next) (((next) - (prev) + 32) >> 6 << 16) 1742bffd268f135df8308c9e67af110525a5c463424Romain Guy 175f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchoukvoid Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 17661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap, 17761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy uint32_t bitmapW, uint32_t bitmapH,Rect *bounds) { 178694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (numGlyphs == 0 || text == NULL || len == 0) { 179694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 180694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 181694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1822bffd268f135df8308c9e67af110525a5c463424Romain Guy SkFixed penX = SkIntToFixed(x); 1832bffd268f135df8308c9e67af110525a5c463424Romain Guy int penY = y; 184694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int glyphsLeft = 1; 185694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (numGlyphs > 0) { 186694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyphsLeft = numGlyphs; 187694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 188694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1892bffd268f135df8308c9e67af110525a5c463424Romain Guy SkFixed prevRsbDelta = 0; 1902bffd268f135df8308c9e67af110525a5c463424Romain Guy penX += SK_Fixed1 / 2; 1912bffd268f135df8308c9e67af110525a5c463424Romain Guy 192694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy text += start; 193694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 194694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy while (glyphsLeft > 0) { 195694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int32_t utfChar = SkUTF16_NextUnichar((const uint16_t**) &text); 196694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 19761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy // Reached the end of the string 198694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (utfChar < 0) { 199694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 200694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 201694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 20265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk CachedGlyphInfo* cachedGlyph = getCachedUTFChar(paint, utfChar); 2032bffd268f135df8308c9e67af110525a5c463424Romain Guy penX += SkAutoKern_AdjustF(prevRsbDelta, cachedGlyph->mLsbDelta); 2042bffd268f135df8308c9e67af110525a5c463424Romain Guy prevRsbDelta = cachedGlyph->mRsbDelta; 205694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 206694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage 207694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (cachedGlyph->mIsValid) { 208f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk switch(mode) { 209f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk case FRAMEBUFFER: 2102bffd268f135df8308c9e67af110525a5c463424Romain Guy drawCachedGlyph(cachedGlyph, SkFixedFloor(penX), penY); 211f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk break; 212f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk case BITMAP: 2132bffd268f135df8308c9e67af110525a5c463424Romain Guy drawCachedGlyph(cachedGlyph, SkFixedFloor(penX), penY, bitmap, bitmapW, bitmapH); 214f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk break; 215f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk case MEASURE: 2162bffd268f135df8308c9e67af110525a5c463424Romain Guy measureCachedGlyph(cachedGlyph, SkFixedFloor(penX), penY, bounds); 217f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk break; 21889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 219694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 220694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 2212bffd268f135df8308c9e67af110525a5c463424Romain Guy penX += cachedGlyph->mAdvanceX; 222694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 223694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If we were given a specific number of glyphs, decrement 224694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (numGlyphs > 0) { 225694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyphsLeft--; 226694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 227694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 228694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 229694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 23051769a68a5cb34e9564740c6a854fcb93018789dRomain Guyvoid Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph) { 231694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mAdvanceX = skiaGlyph.fAdvanceX; 232694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mAdvanceY = skiaGlyph.fAdvanceY; 233694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapLeft = skiaGlyph.fLeft; 234694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapTop = skiaGlyph.fTop; 2352bffd268f135df8308c9e67af110525a5c463424Romain Guy glyph->mLsbDelta = skiaGlyph.fLsbDelta; 2362bffd268f135df8308c9e67af110525a5c463424Romain Guy glyph->mRsbDelta = skiaGlyph.fRsbDelta; 237694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 238694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startX = 0; 239694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startY = 0; 240694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 241694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Get the bitmap for the glyph 242694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy paint->findImage(skiaGlyph); 24351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy glyph->mIsValid = mState->cacheBitmap(skiaGlyph, &startX, &startY); 244694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 245694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!glyph->mIsValid) { 246694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 247694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 248694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 249694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endX = startX + skiaGlyph.fWidth; 250694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endY = startY + skiaGlyph.fHeight; 251694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 25289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk glyph->mStartX = startX; 25389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk glyph->mStartY = startY; 254694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapWidth = skiaGlyph.fWidth; 255694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapHeight = skiaGlyph.fHeight; 256694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 25751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy uint32_t cacheWidth = mState->getCacheWidth(); 25851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy uint32_t cacheHeight = mState->getCacheHeight(); 259694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 260694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapMinU = (float) startX / (float) cacheWidth; 261694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapMinV = (float) startY / (float) cacheHeight; 262694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapMaxU = (float) endX / (float) cacheWidth; 263694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapMaxV = (float) endY / (float) cacheHeight; 264694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 26551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mState->mUploadTexture = true; 266694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 267694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 26851769a68a5cb34e9564740c6a854fcb93018789dRomain GuyFont::CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, int32_t glyph) { 26951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy CachedGlyphInfo* newGlyph = new CachedGlyphInfo(); 270694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCachedGlyphs.add(glyph, newGlyph); 271694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 272694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy const SkGlyph& skiaGlyph = paint->getUnicharMetrics(glyph); 273694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy newGlyph->mGlyphIndex = skiaGlyph.fID; 274694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy newGlyph->mIsValid = false; 275694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 276694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy updateGlyphCache(paint, skiaGlyph, newGlyph); 277694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 278694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return newGlyph; 279694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 280694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 2812577db1ec135a1470a2c42139772ec97a6c30e78Romain GuyFont* Font::create(FontRenderer* state, uint32_t fontId, float fontSize, 2828668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase int flags, uint32_t italicStyle, uint32_t scaleX) { 283694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy Vector<Font*> &activeFonts = state->mActiveFonts; 284694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 285694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < activeFonts.size(); i++) { 28651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy Font* font = activeFonts[i]; 2872577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy if (font->mFontId == fontId && font->mFontSize == fontSize && 2888668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase font->mFlags == flags && font->mItalicStyle == italicStyle && 2898668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase font->mScaleX == scaleX) { 29051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy return font; 291694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 292694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 293694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 2948668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle, scaleX); 295694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy activeFonts.push(newFont); 296694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return newFont; 297694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 298694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 299694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 300694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// FontRenderer 301694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 302694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 303514fb18827186591d66973c2362c859b64b63556Romain Guystatic bool sLogFontRendererCreate = true; 304514fb18827186591d66973c2362c859b64b63556Romain Guy 305694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::FontRenderer() { 306c9855a53edfac818dc68714557185977556f849dRomain Guy if (sLogFontRendererCreate) { 307c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD("Creating FontRenderer"); 308c9855a53edfac818dc68714557185977556f849dRomain Guy } 30951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 310b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy mGammaTable = NULL; 311694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mInitialized = false; 312694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mMaxNumberOfQuads = 1024; 313694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 3149b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mTextureId = 0; 315694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 3169cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy mTextMeshPtr = NULL; 3179cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy mTextTexture = NULL; 3189cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy 319694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mIndexBufferID = 0; 320894df17eee708688c8a6e67941add2017239c790Alex Sakhartchouk mPositionAttrSlot = -1; 321894df17eee708688c8a6e67941add2017239c790Alex Sakhartchouk mTexcoordAttrSlot = -1; 322694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 32351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheWidth = DEFAULT_TEXT_CACHE_WIDTH; 3249b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT; 32551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 32651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy char property[PROPERTY_VALUE_MAX]; 32751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) { 328c9855a53edfac818dc68714557185977556f849dRomain Guy if (sLogFontRendererCreate) { 329c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD(" Setting text cache width to %s pixels", property); 330c9855a53edfac818dc68714557185977556f849dRomain Guy } 33151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheWidth = atoi(property); 33251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } else { 333514fb18827186591d66973c2362c859b64b63556Romain Guy if (sLogFontRendererCreate) { 334c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD(" Using default text cache width of %i pixels", mCacheWidth); 335514fb18827186591d66973c2362c859b64b63556Romain Guy } 33651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } 33751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 33851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy if (property_get(PROPERTY_TEXT_CACHE_HEIGHT, property, NULL) > 0) { 339c9855a53edfac818dc68714557185977556f849dRomain Guy if (sLogFontRendererCreate) { 340c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD(" Setting text cache width to %s pixels", property); 341c9855a53edfac818dc68714557185977556f849dRomain Guy } 34251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheHeight = atoi(property); 34351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } else { 344514fb18827186591d66973c2362c859b64b63556Romain Guy if (sLogFontRendererCreate) { 345c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD(" Using default text cache height of %i pixels", mCacheHeight); 346514fb18827186591d66973c2362c859b64b63556Romain Guy } 34751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } 348514fb18827186591d66973c2362c859b64b63556Romain Guy 349514fb18827186591d66973c2362c859b64b63556Romain Guy sLogFontRendererCreate = false; 350694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 351694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 352694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::~FontRenderer() { 353694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 354694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy delete mCacheLines[i]; 355694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 356694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCacheLines.clear(); 357694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 3589cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy if (mInitialized) { 3599cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy delete[] mTextMeshPtr; 3609cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy delete[] mTextTexture; 3619cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy } 3629b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 3639cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy if (mTextureId) { 3649b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk glDeleteTextures(1, &mTextureId); 3659b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 366694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 367694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy Vector<Font*> fontsToDereference = mActiveFonts; 368694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < fontsToDereference.size(); i++) { 369694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy delete fontsToDereference[i]; 370694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 371694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 372694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 373694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::flushAllAndInvalidate() { 374694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex != 0) { 375694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 376694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 377694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 378694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mActiveFonts.size(); i++) { 379694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mActiveFonts[i]->invalidateTextureCache(); 380694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 381694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 382694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCacheLines[i]->mCurrentCol = 0; 383694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 384694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 385694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 38651769a68a5cb34e9564740c6a854fcb93018789dRomain Guybool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) { 387694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If the glyph is too tall, don't cache it 3882bffd268f135df8308c9e67af110525a5c463424Romain Guy if (glyph.fHeight > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) { 389694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy LOGE("Font size to large to fit in cache. width, height = %i, %i", 390694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (int) glyph.fWidth, (int) glyph.fHeight); 391694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return false; 392694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 393694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 394694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Now copy the bitmap into the cache texture 395694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startX = 0; 396694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startY = 0; 397694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 398694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bool bitmapFit = false; 399694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 400694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY); 401694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (bitmapFit) { 402694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 403694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 404694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 405694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 406694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If the new glyph didn't fit, flush the state so far and invalidate everything 407694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!bitmapFit) { 408694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy flushAllAndInvalidate(); 409694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 410694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Try to fit it again 411694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 412694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY); 413694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (bitmapFit) { 414694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 415694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 416694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 417694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 418694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // if we still don't fit, something is wrong and we shouldn't draw 419694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!bitmapFit) { 420694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", 421694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (int) glyph.fWidth, (int) glyph.fHeight); 422694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return false; 423694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 424694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 425694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 426694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *retOriginX = startX; 427694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *retOriginY = startY; 428694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 429694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endX = startX + glyph.fWidth; 430694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endY = startY + glyph.fHeight; 431694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 432694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t cacheWidth = mCacheWidth; 433694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 43489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* cacheBuffer = mTextTexture; 43589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage; 436694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy unsigned int stride = glyph.rowBytes(); 437694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 438694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; 439694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) { 440694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) { 44189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t tempCol = bitmapBuffer[bY * stride + bX]; 442b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol]; 443694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 444694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 445694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 446694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return true; 447694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 448694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 449694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::initTextTexture() { 45089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk mTextTexture = new uint8_t[mCacheWidth * mCacheHeight]; 4511de1083e98cde9bdd5e8539dbc54fdea6531906eRomain Guy memset(mTextTexture, 0, mCacheWidth * mCacheHeight * sizeof(uint8_t)); 4521de1083e98cde9bdd5e8539dbc54fdea6531906eRomain Guy 453694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mUploadTexture = false; 454694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 455694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glGenTextures(1, &mTextureId); 456694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glBindTexture(GL_TEXTURE_2D, mTextureId); 457694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 4589b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk // Initialize texture dimentions 4599b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mCacheWidth, mCacheHeight, 0, 46061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy GL_ALPHA, GL_UNSIGNED_BYTE, 0); 461694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 462e8cb9c14309b0f01c0159efdf9a7198f44a62642Romain Guy mLinearFiltering = false; 463e8cb9c14309b0f01c0159efdf9a7198f44a62642Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 464e8cb9c14309b0f01c0159efdf9a7198f44a62642Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 465694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 466694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 467694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 468694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 469694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Split up our cache texture into lines of certain widths 470694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int nextLine = 0; 4717975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 18, nextLine, 0)); 472694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 4737975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 26, nextLine, 0)); 474694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 4757975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 26, nextLine, 0)); 47665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk nextLine += mCacheLines.top()->mMaxHeight; 4777975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 34, nextLine, 0)); 478694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 4797975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 34, nextLine, 0)); 480694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 4817975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 42, nextLine, 0)); 482694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 48351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, mCacheHeight - nextLine, nextLine, 0)); 484694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 485694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 486694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Avoid having to reallocate memory and render quad by quad 487694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::initVertexArrayBuffers() { 488694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t numIndicies = mMaxNumberOfQuads * 6; 489694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t indexBufferSizeBytes = numIndicies * sizeof(uint16_t); 49051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes); 491694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 492694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Four verts, two triangles , six indices per quad 493694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mMaxNumberOfQuads; i++) { 494694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int i6 = i * 6; 495694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int i4 = i * 4; 496694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 497694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 0] = i4 + 0; 498694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 1] = i4 + 1; 499694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 2] = i4 + 2; 500694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 501694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 3] = i4 + 0; 502694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 4] = i4 + 2; 503694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 5] = i4 + 3; 504694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 505694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 506694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glGenBuffers(1, &mIndexBufferID); 5075d794412e3e429e47404395badcd11b0b8639e8bRomain Guy glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID); 5085d794412e3e429e47404395badcd11b0b8639e8bRomain Guy glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_STATIC_DRAW); 5095d794412e3e429e47404395badcd11b0b8639e8bRomain Guy glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 510694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 511694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy free(indexBufferData); 512694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 513694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t coordSize = 3; 514694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t uvSize = 2; 515694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t vertsPerQuad = 4; 5169b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize; 5179b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mTextMeshPtr = new float[vertexBufferSize]; 518694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 519694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 520694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// We don't want to allocate anything unless we actually draw text 521694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::checkInit() { 522694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mInitialized) { 523694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 524694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 525694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 526694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy initTextTexture(); 527694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy initVertexArrayBuffers(); 528694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 52965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk // We store a string with letters in a rough frequency of occurrence 53065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mLatinPrecache = String16("eisarntolcdugpmhbyfvkwzxjq "); 53165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mLatinPrecache += String16("EISARNTOLCDUGPMHBYFVKWZXJQ"); 53265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mLatinPrecache += String16(",.?!()-+@;:`'"); 53365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mLatinPrecache += String16("0123456789"); 53465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 535694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mInitialized = true; 536694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 537694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 5389b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::checkTextureUpdate() { 5399b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk if (!mUploadTexture) { 5409b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk return; 5419b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 5429b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5439b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk glBindTexture(GL_TEXTURE_2D, mTextureId); 5449b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5459b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk // Iterate over all the cache lines and see which ones need to be updated 5469b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk for (uint32_t i = 0; i < mCacheLines.size(); i++) { 5479b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk CacheTextureLine* cl = mCacheLines[i]; 5489b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk if(cl->mDirty) { 5499b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t xOffset = 0; 5509b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t yOffset = cl->mCurrentRow; 5519b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t width = mCacheWidth; 5529b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t height = cl->mMaxHeight; 5531e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy void* textureData = mTextTexture + yOffset*width; 5549b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5559b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height, 5561e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy GL_ALPHA, GL_UNSIGNED_BYTE, textureData); 5579b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5589b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk cl->mDirty = false; 5599b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 560694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 561694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 5629b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mUploadTexture = false; 5639b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk} 5649b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5659b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::issueDrawCommand() { 5669b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk checkTextureUpdate(); 5679b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 56851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float* vtx = mTextMeshPtr; 56951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float* tex = vtx + 3; 570694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 571894df17eee708688c8a6e67941add2017239c790Alex Sakhartchouk glVertexAttribPointer(mPositionAttrSlot, 3, GL_FLOAT, false, 20, vtx); 572894df17eee708688c8a6e67941add2017239c790Alex Sakhartchouk glVertexAttribPointer(mTexcoordAttrSlot, 2, GL_FLOAT, false, 20, tex); 573694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 574694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID); 575694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL); 5765b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 5775b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mDrawn = true; 578694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 579694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 580694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::appendMeshQuad(float x1, float y1, float z1, float u1, float v1, float x2, 581694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3, 582694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy float x4, float y4, float z4, float u4, float v4) { 58309147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy if (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom) { 58409147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy return; 58509147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy } 58609147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy 587694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy const uint32_t vertsPerQuad = 4; 588694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy const uint32_t floatsPerVert = 5; 58951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float* currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert; 590694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 591694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x1; 592694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y1; 593694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = z1; 594694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u1; 595694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v1; 596694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 597694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x2; 598694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y2; 599694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = z2; 600694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u2; 601694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v2; 602694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 603694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x3; 604694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y3; 605694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = z3; 606694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u3; 607694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v3; 608694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 609694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x4; 610694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y4; 611694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = z4; 612694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u4; 613694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v4; 614694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 615694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex++; 616694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 6175b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy if (mBounds) { 6185b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->left = fmin(mBounds->left, x1); 6195b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->top = fmin(mBounds->top, y3); 6205b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->right = fmax(mBounds->right, x3); 6215b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->bottom = fmax(mBounds->bottom, y1); 6225b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy } 6235b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 624694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex == mMaxNumberOfQuads) { 625694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 626694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 627694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 628694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 629694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 63065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukuint32_t FontRenderer::getRemainingCacheCapacity() { 63165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t remainingCapacity = 0; 63265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk float totalPixels = 0; 63365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 63465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol); 63565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk totalPixels += mCacheLines[i]->mMaxWidth; 63665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 63765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk remainingCapacity = (remainingCapacity * 100) / totalPixels; 63865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk return remainingCapacity; 63965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk} 64065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 64165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::precacheLatin(SkPaint* paint) { 64265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk // Remaining capacity is measured in % 64365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t remainingCapacity = getRemainingCacheCapacity(); 64465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t precacheIdx = 0; 645054dc1840941665e32036f9523df51720ad069c8Romain Guy while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) { 646054dc1840941665e32036f9523df51720ad069c8Romain Guy mCurrentFont->getCachedUTFChar(paint, (int32_t) mLatinPrecache[precacheIdx]); 64765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk remainingCapacity = getRemainingCacheCapacity(); 64865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk precacheIdx ++; 64965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 65065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk} 65165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 65265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) { 65365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t currentNumFonts = mActiveFonts.size(); 654325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy int flags = 0; 655325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (paint->isFakeBoldText()) { 656325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy flags |= Font::kFakeBold; 657325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy } 6582577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy 6592577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy const float skewX = paint->getTextSkewX(); 6602577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy uint32_t italicStyle = *(uint32_t*) &skewX; 6618668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase const float scaleXFloat = paint->getTextScaleX(); 6628668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase uint32_t scaleX = *(uint32_t*) &scaleXFloat; 6638668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle, scaleX); 66465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 66565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk const float maxPrecacheFontSize = 40.0f; 66665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk bool isNewFont = currentNumFonts != mActiveFonts.size(); 66765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 6682bffd268f135df8308c9e67af110525a5c463424Romain Guy if (isNewFont && fontSize <= maxPrecacheFontSize) { 66965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk precacheLatin(paint); 67065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 671694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 6727975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy 673f18136cb3c881a9d16c1a4f0f341732c276936bfAlex SakhartchoukFontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text, 6741e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius) { 6751e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy checkInit(); 6761e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 6771e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (!mCurrentFont) { 6781e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy DropShadow image; 6791e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.width = 0; 6801e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.height = 0; 6811e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.image = NULL; 6821e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.penX = 0; 6831e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.penY = 0; 6841e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy return image; 6851e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } 686f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 687f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk Rect bounds; 688f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk mCurrentFont->measureUTF(paint, text, startIndex, len, numGlyphs, &bounds); 6891e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius; 6901e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius; 691f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight]; 6921e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy for (uint32_t i = 0; i < paddedWidth * paddedHeight; i++) { 693f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk dataBuffer[i] = 0; 694f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 6951e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 696f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int penX = radius - bounds.left; 697f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int penY = radius - bounds.bottom; 698f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 699f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, penX, penY, 7001e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy dataBuffer, paddedWidth, paddedHeight); 701f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk blurImage(dataBuffer, paddedWidth, paddedHeight, radius); 702f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 703f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk DropShadow image; 704f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.width = paddedWidth; 705f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.height = paddedHeight; 706f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.image = dataBuffer; 707f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.penX = penX; 708f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.penY = penY; 709f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk return image; 710f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 711694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 7125b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guybool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text, 7135b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, Rect* bounds) { 714694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy checkInit(); 715694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 71609147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy if (!mCurrentFont) { 71709147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy LOGE("No font set"); 7185b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy return false; 719694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 720694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 721894df17eee708688c8a6e67941add2017239c790Alex Sakhartchouk if (mPositionAttrSlot < 0 || mTexcoordAttrSlot < 0) { 722894df17eee708688c8a6e67941add2017239c790Alex Sakhartchouk LOGE("Font renderer unable to draw, attribute slots undefined"); 723894df17eee708688c8a6e67941add2017239c790Alex Sakhartchouk return false; 724894df17eee708688c8a6e67941add2017239c790Alex Sakhartchouk } 725894df17eee708688c8a6e67941add2017239c790Alex Sakhartchouk 7265b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mDrawn = false; 7275b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds = bounds; 72809147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy mClip = clip; 72951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, x, y); 7305b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds = NULL; 731694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 732694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex != 0) { 733694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 734694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 735694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 7365b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 7375b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy return mDrawn; 738694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 739694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 74089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::computeGaussianWeights(float* weights, int32_t radius) { 74189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Compute gaussian weights for the blur 74289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // e is the euler's number 74389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float e = 2.718281828459045f; 74489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float pi = 3.1415926535897932f; 74589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 ) 74689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // x is of the form [-radius .. 0 .. radius] 74789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // and sigma varies with radius. 74889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Based on some experimental radius values and sigma's 74989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // we approximately fit sigma = f(radius) as 750f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk // sigma = radius * 0.3 + 0.6 75189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // The larger the radius gets, the more our gaussian blur 75289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // will resemble a box blur since with large sigma 75389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // the gaussian curve begins to lose its shape 754325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy float sigma = 0.3f * (float) radius + 0.6f; 75589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 75689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Now compute the coefficints 75789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // We will store some redundant values to save some math during 75889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // the blur calculations 75989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // precompute some values 76089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma); 76189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float coeff2 = - 1.0f / (2.0f * sigma * sigma); 76289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 76389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float normalizeFactor = 0.0f; 764325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 7657975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy float floatR = (float) r; 76689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2); 76789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk normalizeFactor += weights[r + radius]; 76889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 76989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 77089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk //Now we need to normalize the weights because all our coefficients need to add up to one 77189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk normalizeFactor = 1.0f / normalizeFactor; 772325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 77389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk weights[r + radius] *= normalizeFactor; 77489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 77589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 77689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 77789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::horizontalBlur(float* weights, int32_t radius, 7781e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) { 77989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float blurredPixel = 0.0f; 78089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float currentPixel = 0.0f; 78189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 782325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t y = 0; y < height; y ++) { 78389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 78489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* input = source + y * width; 78589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* output = dest + y * width; 78689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 787325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t x = 0; x < width; x ++) { 78889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel = 0.0f; 78989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const float* gPtr = weights; 79089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Optimization for non-border pixels 791325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (x > radius && x < (width - radius)) { 79289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + (x - radius); 793325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int r = -radius; r <= radius; r ++) { 7947975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy currentPixel = (float) (*i); 79589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 79689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 79789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk i++; 79889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 79989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } else { 800325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 80189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Stepping left and right away from the pixel 80289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int validW = x + r; 803325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validW < 0) { 80489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validW = 0; 80589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 806325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validW > width - 1) { 80789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validW = width - 1; 80889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 80989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 810325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy currentPixel = (float) input[validW]; 81189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 81289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 81389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 81489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 81589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk *output = (uint8_t)blurredPixel; 81689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk output ++; 81789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 81889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 81989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 82089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 82189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::verticalBlur(float* weights, int32_t radius, 8221e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) { 82389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float blurredPixel = 0.0f; 82489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float currentPixel = 0.0f; 82589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 826325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t y = 0; y < height; y ++) { 82789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 82889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* output = dest + y * width; 82989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 830325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t x = 0; x < width; x ++) { 83189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel = 0.0f; 83289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const float* gPtr = weights; 83389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* input = source + x; 83489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Optimization for non-border pixels 835325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (y > radius && y < (height - radius)) { 83689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + ((y - radius) * width); 837325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 83889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk currentPixel = (float)(*i); 83989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 84089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 84189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk i += width; 84289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 84389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } else { 844325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 84589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int validH = y + r; 84689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Clamp to zero and width 847325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validH < 0) { 84889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validH = 0; 84989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 850325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validH > height - 1) { 85189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validH = height - 1; 85289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 85389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 85489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + validH * width; 855325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy currentPixel = (float) (*i); 85689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 85789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 85889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 85989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 860325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy *output = (uint8_t) blurredPixel; 86189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk output ++; 86289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 86389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 86489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 86589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 86689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 86789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::blurImage(uint8_t *image, int32_t width, int32_t height, int32_t radius) { 86889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float *gaussian = new float[2 * radius + 1]; 86989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk computeGaussianWeights(gaussian, radius); 87089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* scratch = new uint8_t[width * height]; 87189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk horizontalBlur(gaussian, radius, image, scratch, width, height); 87289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk verticalBlur(gaussian, radius, scratch, image, width, height); 87389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk delete[] gaussian; 87489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk delete[] scratch; 87589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 87689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 877694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace uirenderer 878694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace android 879