FontRenderer.cpp revision 1e45aae5de003657e5d18f74d34998f5de5db5b7
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> 2251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#include <utils/Log.h> 2351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 2451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#include "FontRenderer.h" 2551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 26694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guynamespace android { 27694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guynamespace uirenderer { 28694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 29694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 3051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy// Defines 3151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy/////////////////////////////////////////////////////////////////////////////// 3251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 3351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#define DEFAULT_TEXT_CACHE_WIDTH 1024 3451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#define DEFAULT_TEXT_CACHE_HEIGHT 256 3551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 3651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy/////////////////////////////////////////////////////////////////////////////// 37694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Font 38694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 39694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 40694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFont::Font(FontRenderer* state, uint32_t fontId, float fontSize) : 41694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mState(state), mFontId(fontId), mFontSize(fontSize) { 42694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 43694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 44694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 45694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFont::~Font() { 46694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t ct = 0; ct < mState->mActiveFonts.size(); ct++) { 47694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mState->mActiveFonts[ct] == this) { 48694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mState->mActiveFonts.removeAt(ct); 49694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 50694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 51694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 52694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 53694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) { 5451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy CachedGlyphInfo* glyph = mCachedGlyphs.valueAt(i); 55694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy delete glyph; 56694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 57694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 58694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 59694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid Font::invalidateTextureCache() { 60694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) { 61694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCachedGlyphs.valueAt(i)->mIsValid = false; 62694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 63694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 64694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 65f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchoukvoid Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y, Rect *bounds) { 66f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int nPenX = x + glyph->mBitmapLeft; 67f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int nPenY = y + glyph->mBitmapTop; 68f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 69f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int width = (int) glyph->mBitmapWidth; 70f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int height = (int) glyph->mBitmapHeight; 71f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 7261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->bottom > nPenY) { 73f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->bottom = nPenY; 74f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 7561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->left > nPenX) { 76f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->left = nPenX; 77f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 7861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->right < nPenX + width) { 79f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->right = nPenX + width; 80f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 8161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->top < nPenY + height) { 82f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->top = nPenY + height; 83f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 84f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 85f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 86694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y) { 87694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int nPenX = x + glyph->mBitmapLeft; 88694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight; 89694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 9051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float u1 = glyph->mBitmapMinU; 9151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float u2 = glyph->mBitmapMaxU; 9251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float v1 = glyph->mBitmapMinV; 9351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float v2 = glyph->mBitmapMaxV; 9451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 9551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy int width = (int) glyph->mBitmapWidth; 9651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy int height = (int) glyph->mBitmapHeight; 9751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 9851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mState->appendMeshQuad(nPenX, nPenY, 0, u1, v2, 9951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy nPenX + width, nPenY, 0, u2, v2, 10051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy nPenX + width, nPenY - height, 0, u2, v1, 10151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy nPenX, nPenY - height, 0, u1, v1); 102694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 103694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 10489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid Font::drawCachedGlyph(CachedGlyphInfo *glyph, int x, int y, 10561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) { 10689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int nPenX = x + glyph->mBitmapLeft; 10789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int nPenY = y + glyph->mBitmapTop; 10889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 10989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint32_t endX = glyph->mStartX + glyph->mBitmapWidth; 11089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint32_t endY = glyph->mStartY + glyph->mBitmapHeight; 11189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 11289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint32_t cacheWidth = mState->getCacheWidth(); 11389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* cacheBuffer = mState->getTextTextureData(); 11489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 115f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk uint32_t cacheX = 0, cacheY = 0; 116f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int32_t bX = 0, bY = 0; 11789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) { 11889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) { 11961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bX < 0 || bY < 0 || bX >= (int32_t)bitmapW || bY >= (int32_t)bitmapH) { 120f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk LOGE("Skipping invalid index"); 121f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk continue; 122f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 12389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX]; 12489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk bitmap[bY * bitmapW + bX] = tempCol; 12589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 12689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 12789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 12889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 12989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 13065ef909776c03417d8b597738da54ca211e37e4fAlex SakhartchoukFont::CachedGlyphInfo* Font::getCachedUTFChar(SkPaint* paint, int32_t utfChar) { 1311e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy CachedGlyphInfo* cachedGlyph = NULL; 1321e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy ssize_t index = mCachedGlyphs.indexOfKey(utfChar); 1331e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (index >= 0) { 1341e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy cachedGlyph = mCachedGlyphs.valueAt(index); 1351e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } else { 13665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk cachedGlyph = cacheGlyph(paint, utfChar); 13765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 13865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 13965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk // Is the glyph still in texture cache? 14065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk if (!cachedGlyph->mIsValid) { 14165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk const SkGlyph& skiaGlyph = paint->getUnicharMetrics(utfChar); 14265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk updateGlyphCache(paint, skiaGlyph, cachedGlyph); 14365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 14465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 14565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk return cachedGlyph; 14665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk} 14765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 14851769a68a5cb34e9564740c6a854fcb93018789dRomain Guyvoid Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 14961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy int numGlyphs, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) { 15061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bitmap != NULL && bitmapW > 0 && bitmapH > 0) { 15161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy renderUTF(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap, 15261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy bitmapW, bitmapH, NULL); 15361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy } else { 15461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy renderUTF(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL, 0, 0, NULL); 155f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 156f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 157f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 158f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 159f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchoukvoid Font::measureUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 16061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy int numGlyphs, Rect *bounds) { 16161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds == NULL) { 162f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk LOGE("No return rectangle provided to measure text"); 163f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk return; 164f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 165f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->set(1e6, -1e6, -1e6, 1e6); 166f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk renderUTF(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds); 167f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 168f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 169f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchoukvoid Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 17061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap, 17161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy uint32_t bitmapW, uint32_t bitmapH,Rect *bounds) { 172694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (numGlyphs == 0 || text == NULL || len == 0) { 173694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 174694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 175694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 176694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int penX = x, penY = y; 177694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int glyphsLeft = 1; 178694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (numGlyphs > 0) { 179694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyphsLeft = numGlyphs; 180694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 181694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 182694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy text += start; 183694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 184694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy while (glyphsLeft > 0) { 185694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int32_t utfChar = SkUTF16_NextUnichar((const uint16_t**) &text); 186694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 18761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy // Reached the end of the string 188694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (utfChar < 0) { 189694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 190694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 191694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 19265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk CachedGlyphInfo* cachedGlyph = getCachedUTFChar(paint, utfChar); 193694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 194694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage 195694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (cachedGlyph->mIsValid) { 196f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk switch(mode) { 197f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk case FRAMEBUFFER: 19889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk drawCachedGlyph(cachedGlyph, penX, penY); 199f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk break; 200f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk case BITMAP: 201f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH); 202f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk break; 203f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk case MEASURE: 204f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk measureCachedGlyph(cachedGlyph, penX, penY, bounds); 205f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk break; 20689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 207694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 208694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 20909147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy penX += SkFixedFloor(cachedGlyph->mAdvanceX); 210694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 211694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If we were given a specific number of glyphs, decrement 212694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (numGlyphs > 0) { 213694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyphsLeft--; 214694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 215694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 216694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 217694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 21851769a68a5cb34e9564740c6a854fcb93018789dRomain Guyvoid Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph) { 219694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mAdvanceX = skiaGlyph.fAdvanceX; 220694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mAdvanceY = skiaGlyph.fAdvanceY; 221694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapLeft = skiaGlyph.fLeft; 222694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapTop = skiaGlyph.fTop; 223694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 224694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startX = 0; 225694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startY = 0; 226694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 227694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Get the bitmap for the glyph 228694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy paint->findImage(skiaGlyph); 22951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy glyph->mIsValid = mState->cacheBitmap(skiaGlyph, &startX, &startY); 230694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 231694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!glyph->mIsValid) { 232694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 233694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 234694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 235694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endX = startX + skiaGlyph.fWidth; 236694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endY = startY + skiaGlyph.fHeight; 237694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 23889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk glyph->mStartX = startX; 23989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk glyph->mStartY = startY; 240694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapWidth = skiaGlyph.fWidth; 241694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapHeight = skiaGlyph.fHeight; 242694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 24351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy uint32_t cacheWidth = mState->getCacheWidth(); 24451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy uint32_t cacheHeight = mState->getCacheHeight(); 245694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 246694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapMinU = (float) startX / (float) cacheWidth; 247694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapMinV = (float) startY / (float) cacheHeight; 248694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapMaxU = (float) endX / (float) cacheWidth; 249694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapMaxV = (float) endY / (float) cacheHeight; 250694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 25151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mState->mUploadTexture = true; 252694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 253694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 25451769a68a5cb34e9564740c6a854fcb93018789dRomain GuyFont::CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, int32_t glyph) { 25551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy CachedGlyphInfo* newGlyph = new CachedGlyphInfo(); 256694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCachedGlyphs.add(glyph, newGlyph); 257694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 258694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy const SkGlyph& skiaGlyph = paint->getUnicharMetrics(glyph); 259694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy newGlyph->mGlyphIndex = skiaGlyph.fID; 260694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy newGlyph->mIsValid = false; 261694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 262694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy updateGlyphCache(paint, skiaGlyph, newGlyph); 263694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 264694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return newGlyph; 265694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 266694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 267694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFont* Font::create(FontRenderer* state, uint32_t fontId, float fontSize) { 268694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy Vector<Font*> &activeFonts = state->mActiveFonts; 269694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 270694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < activeFonts.size(); i++) { 27151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy Font* font = activeFonts[i]; 27251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy if (font->mFontId == fontId && font->mFontSize == fontSize) { 27351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy return font; 274694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 275694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 276694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 277694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy Font* newFont = new Font(state, fontId, fontSize); 278694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy activeFonts.push(newFont); 279694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return newFont; 280694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 281694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 282694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 283694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// FontRenderer 284694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 285694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 286694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::FontRenderer() { 28751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy LOGD("Creating FontRenderer"); 28851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 289694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mInitialized = false; 290694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mMaxNumberOfQuads = 1024; 291694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 2929b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mTextureId = 0; 293694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 2949cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy mTextMeshPtr = NULL; 2959cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy mTextTexture = NULL; 2969cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy 297694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mIndexBufferID = 0; 298694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 29951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheWidth = DEFAULT_TEXT_CACHE_WIDTH; 3009b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT; 30151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 30251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy char property[PROPERTY_VALUE_MAX]; 30351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) { 30451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy LOGD(" Setting text cache width to %s pixels", property); 30551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheWidth = atoi(property); 30651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } else { 30751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy LOGD(" Using default text cache width of %i pixels", mCacheWidth); 30851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } 30951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 31051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy if (property_get(PROPERTY_TEXT_CACHE_HEIGHT, property, NULL) > 0) { 31151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy LOGD(" Setting text cache width to %s pixels", property); 31251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheHeight = atoi(property); 31351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } else { 31451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy LOGD(" Using default text cache height of %i pixels", mCacheHeight); 31551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } 316694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 317694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 318694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::~FontRenderer() { 319694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 320694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy delete mCacheLines[i]; 321694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 322694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCacheLines.clear(); 323694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 3249cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy if (mInitialized) { 3259cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy delete[] mTextMeshPtr; 3269cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy delete[] mTextTexture; 3279cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy } 3289b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 3299cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy if (mTextureId) { 3309b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk glDeleteTextures(1, &mTextureId); 3319b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 332694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 333694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy Vector<Font*> fontsToDereference = mActiveFonts; 334694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < fontsToDereference.size(); i++) { 335694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy delete fontsToDereference[i]; 336694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 337694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 338694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 339694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::flushAllAndInvalidate() { 340694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex != 0) { 341694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 342694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 343694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 344694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mActiveFonts.size(); i++) { 345694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mActiveFonts[i]->invalidateTextureCache(); 346694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 347694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 348694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCacheLines[i]->mCurrentCol = 0; 349694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 350694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 351694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 35251769a68a5cb34e9564740c6a854fcb93018789dRomain Guybool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) { 353694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If the glyph is too tall, don't cache it 354694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (glyph.fWidth > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) { 355694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy LOGE("Font size to large to fit in cache. width, height = %i, %i", 356694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (int) glyph.fWidth, (int) glyph.fHeight); 357694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return false; 358694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 359694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 360694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Now copy the bitmap into the cache texture 361694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startX = 0; 362694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startY = 0; 363694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 364694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bool bitmapFit = false; 365694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 366694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY); 367694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (bitmapFit) { 368694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 369694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 370694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 371694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 372694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If the new glyph didn't fit, flush the state so far and invalidate everything 373694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!bitmapFit) { 374694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy flushAllAndInvalidate(); 375694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 376694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Try to fit it again 377694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 378694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY); 379694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (bitmapFit) { 380694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 381694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 382694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 383694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 384694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // if we still don't fit, something is wrong and we shouldn't draw 385694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!bitmapFit) { 386694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", 387694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (int) glyph.fWidth, (int) glyph.fHeight); 388694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return false; 389694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 390694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 391694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 392694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *retOriginX = startX; 393694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *retOriginY = startY; 394694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 395694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endX = startX + glyph.fWidth; 396694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endY = startY + glyph.fHeight; 397694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 398694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t cacheWidth = mCacheWidth; 399694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 40089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* cacheBuffer = mTextTexture; 40189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage; 402694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy unsigned int stride = glyph.rowBytes(); 403694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 404694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; 405694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) { 406694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) { 40789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t tempCol = bitmapBuffer[bY * stride + bX]; 408694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy cacheBuffer[cacheY * cacheWidth + cacheX] = tempCol; 409694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 410694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 411694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 412694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return true; 413694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 414694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 415694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::initTextTexture() { 41689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk mTextTexture = new uint8_t[mCacheWidth * mCacheHeight]; 417694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mUploadTexture = false; 418694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 419694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glGenTextures(1, &mTextureId); 420694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glBindTexture(GL_TEXTURE_2D, mTextureId); 421694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 4229b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk // Initialize texture dimentions 4239b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mCacheWidth, mCacheHeight, 0, 42461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy GL_ALPHA, GL_UNSIGNED_BYTE, 0); 425694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 426694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 427694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 428694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 429694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 430694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 431694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 432694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Split up our cache texture into lines of certain widths 433694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int nextLine = 0; 43451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 16, nextLine, 0)); 435694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 43651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 24, nextLine, 0)); 437694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 43865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mCacheLines.push(new CacheTextureLine(mCacheWidth, 24, nextLine, 0)); 43965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk nextLine += mCacheLines.top()->mMaxHeight; 44051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 32, nextLine, 0)); 441694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 44251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 32, nextLine, 0)); 443694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 44451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 40, nextLine, 0)); 445694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 44651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, mCacheHeight - nextLine, nextLine, 0)); 447694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 448694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 449694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Avoid having to reallocate memory and render quad by quad 450694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::initVertexArrayBuffers() { 451694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t numIndicies = mMaxNumberOfQuads * 6; 452694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t indexBufferSizeBytes = numIndicies * sizeof(uint16_t); 45351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes); 454694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 455694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Four verts, two triangles , six indices per quad 456694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mMaxNumberOfQuads; i++) { 457694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int i6 = i * 6; 458694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int i4 = i * 4; 459694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 460694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 0] = i4 + 0; 461694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 1] = i4 + 1; 462694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 2] = i4 + 2; 463694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 464694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 3] = i4 + 0; 465694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 4] = i4 + 2; 466694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 5] = i4 + 3; 467694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 468694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 469694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glGenBuffers(1, &mIndexBufferID); 470694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glBindBuffer(GL_ARRAY_BUFFER, mIndexBufferID); 471694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glBufferData(GL_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_DYNAMIC_DRAW); 472694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glBindBuffer(GL_ARRAY_BUFFER, 0); 473694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 474694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy free(indexBufferData); 475694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 476694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t coordSize = 3; 477694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t uvSize = 2; 478694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t vertsPerQuad = 4; 4799b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize; 4809b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mTextMeshPtr = new float[vertexBufferSize]; 481694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 482694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 483694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// We don't want to allocate anything unless we actually draw text 484694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::checkInit() { 485694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mInitialized) { 486694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 487694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 488694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 489694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy initTextTexture(); 490694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy initVertexArrayBuffers(); 491694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 49265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk // We store a string with letters in a rough frequency of occurrence 49365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mLatinPrecache = String16("eisarntolcdugpmhbyfvkwzxjq "); 49465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mLatinPrecache += String16("EISARNTOLCDUGPMHBYFVKWZXJQ"); 49565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mLatinPrecache += String16(",.?!()-+@;:`'"); 49665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mLatinPrecache += String16("0123456789"); 49765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 498694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mInitialized = true; 499694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 500694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 5019b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::checkTextureUpdate() { 5029b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk if (!mUploadTexture) { 5039b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk return; 5049b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 5059b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5069b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk glBindTexture(GL_TEXTURE_2D, mTextureId); 5079b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5089b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk // Iterate over all the cache lines and see which ones need to be updated 5099b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk for (uint32_t i = 0; i < mCacheLines.size(); i++) { 5109b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk CacheTextureLine* cl = mCacheLines[i]; 5119b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk if(cl->mDirty) { 5129b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t xOffset = 0; 5139b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t yOffset = cl->mCurrentRow; 5149b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t width = mCacheWidth; 5159b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t height = cl->mMaxHeight; 5161e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy void* textureData = mTextTexture + yOffset*width; 5179b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5189b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height, 5191e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy GL_ALPHA, GL_UNSIGNED_BYTE, textureData); 5209b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5219b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk cl->mDirty = false; 5229b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 523694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 524694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 5259b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mUploadTexture = false; 5269b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk} 5279b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5289b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::issueDrawCommand() { 5299b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk checkTextureUpdate(); 5309b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 53151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float* vtx = mTextMeshPtr; 53251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float* tex = vtx + 3; 533694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 534694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // position is slot 0 535694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t slot = 0; 536694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glVertexAttribPointer(slot, 3, GL_FLOAT, false, 20, vtx); 537694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 538694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // texture0 is slot 1 539694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy slot = 1; 540694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glVertexAttribPointer(slot, 2, GL_FLOAT, false, 20, tex); 541694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 542694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID); 543694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL); 544694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 545694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 546694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::appendMeshQuad(float x1, float y1, float z1, float u1, float v1, float x2, 547694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3, 548694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy float x4, float y4, float z4, float u4, float v4) { 54909147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy if (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom) { 55009147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy return; 55109147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy } 55209147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy 553694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy const uint32_t vertsPerQuad = 4; 554694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy const uint32_t floatsPerVert = 5; 55551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float* currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert; 556694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 557694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x1; 558694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y1; 559694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = z1; 560694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u1; 561694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v1; 562694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 563694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x2; 564694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y2; 565694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = z2; 566694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u2; 567694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v2; 568694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 569694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x3; 570694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y3; 571694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = z3; 572694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u3; 573694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v3; 574694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 575694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x4; 576694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y4; 577694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = z4; 578694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u4; 579694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v4; 580694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 581694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex++; 582694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 583694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex == mMaxNumberOfQuads) { 584694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 585694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 586694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 587694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 588694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 58965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukuint32_t FontRenderer::getRemainingCacheCapacity() { 59065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t remainingCapacity = 0; 59165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk float totalPixels = 0; 59265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 59365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol); 59465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk totalPixels += mCacheLines[i]->mMaxWidth; 59565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 59665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk remainingCapacity = (remainingCapacity * 100) / totalPixels; 59765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk return remainingCapacity; 59865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk} 59965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 60065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::precacheLatin(SkPaint* paint) { 60165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk // Remaining capacity is measured in % 60265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t remainingCapacity = getRemainingCacheCapacity(); 60365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t precacheIdx = 0; 60465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) { 60565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mCurrentFont->getCachedUTFChar(paint, (int32_t)mLatinPrecache[precacheIdx]); 60665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk remainingCapacity = getRemainingCacheCapacity(); 60765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk precacheIdx ++; 60865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 60965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk} 61065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 61165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) { 61265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t currentNumFonts = mActiveFonts.size(); 613694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentFont = Font::create(this, fontId, fontSize); 61465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 61565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk const float maxPrecacheFontSize = 40.0f; 61665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk bool isNewFont = currentNumFonts != mActiveFonts.size(); 61765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 61865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk if(isNewFont && fontSize <= maxPrecacheFontSize ){ 61965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk precacheLatin(paint); 62065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 621694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 622f18136cb3c881a9d16c1a4f0f341732c276936bfAlex SakhartchoukFontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text, 6231e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius) { 6241e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy checkInit(); 6251e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 6261e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (!mCurrentFont) { 6271e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy DropShadow image; 6281e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.width = 0; 6291e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.height = 0; 6301e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.image = NULL; 6311e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.penX = 0; 6321e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.penY = 0; 6331e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy return image; 6341e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } 635f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 636f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk Rect bounds; 637f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk mCurrentFont->measureUTF(paint, text, startIndex, len, numGlyphs, &bounds); 6381e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius; 6391e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius; 640f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight]; 6411e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy for (uint32_t i = 0; i < paddedWidth * paddedHeight; i++) { 642f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk dataBuffer[i] = 0; 643f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 6441e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 645f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int penX = radius - bounds.left; 646f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int penY = radius - bounds.bottom; 647f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 648f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, penX, penY, 6491e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy dataBuffer, paddedWidth, paddedHeight); 650f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk blurImage(dataBuffer, paddedWidth, paddedHeight, radius); 651f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 652f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk DropShadow image; 653f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.width = paddedWidth; 654f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.height = paddedHeight; 655f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.image = dataBuffer; 656f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.penX = penX; 657f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.penY = penY; 658f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk return image; 659f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 660694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 66151769a68a5cb34e9564740c6a854fcb93018789dRomain Guyvoid FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text, 66251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y) { 663694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy checkInit(); 664694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 66509147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy if (!mCurrentFont) { 66609147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy LOGE("No font set"); 667694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 668694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 669694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 67009147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy mClip = clip; 67151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, x, y); 672694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 673694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex != 0) { 674694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 675694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 676694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 677694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 678694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 67989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::computeGaussianWeights(float* weights, int32_t radius) { 68089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Compute gaussian weights for the blur 68189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // e is the euler's number 68289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float e = 2.718281828459045f; 68389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float pi = 3.1415926535897932f; 68489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 ) 68589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // x is of the form [-radius .. 0 .. radius] 68689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // and sigma varies with radius. 68789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Based on some experimental radius values and sigma's 68889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // we approximately fit sigma = f(radius) as 689f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk // sigma = radius * 0.3 + 0.6 69089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // The larger the radius gets, the more our gaussian blur 69189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // will resemble a box blur since with large sigma 69289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // the gaussian curve begins to lose its shape 693f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk float sigma = 0.3f * (float)radius + 0.6f; 69489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 69589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Now compute the coefficints 69689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // We will store some redundant values to save some math during 69789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // the blur calculations 69889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // precompute some values 69989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma); 70089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float coeff2 = - 1.0f / (2.0f * sigma * sigma); 70189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 70289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float normalizeFactor = 0.0f; 70389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for(int32_t r = -radius; r <= radius; r ++) { 70489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float floatR = (float)r; 70589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2); 70689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk normalizeFactor += weights[r + radius]; 70789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 70889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 70989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk //Now we need to normalize the weights because all our coefficients need to add up to one 71089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk normalizeFactor = 1.0f / normalizeFactor; 71189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for(int32_t r = -radius; r <= radius; r ++) { 71289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk weights[r + radius] *= normalizeFactor; 71389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 71489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 71589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 71689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::horizontalBlur(float* weights, int32_t radius, 7171e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) { 71889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float blurredPixel = 0.0f; 71989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float currentPixel = 0.0f; 72089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 72189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for(int32_t y = 0; y < height; y ++) { 72289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 72389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* input = source + y * width; 72489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* output = dest + y * width; 72589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 72689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for(int32_t x = 0; x < width; x ++) { 72789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel = 0.0f; 72889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const float* gPtr = weights; 72989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Optimization for non-border pixels 73089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk if ((x > radius) && (x < (width - radius))) { 73189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + (x - radius); 73289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for(int r = -radius; r <= radius; r ++) { 73389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk currentPixel = (float)(*i); 73489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 73589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 73689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk i++; 73789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 73889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } else { 73989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for(int32_t r = -radius; r <= radius; r ++) { 74089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Stepping left and right away from the pixel 74189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int validW = x + r; 74289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk if(validW < 0) { 74389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validW = 0; 74489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 74589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk if(validW > width - 1) { 74689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validW = width - 1; 74789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 74889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 74989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk currentPixel = (float)(input[validW]); 75089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 75189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 75289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 75389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 75489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk *output = (uint8_t)blurredPixel; 75589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk output ++; 75689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 75789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 75889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 75989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 76089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::verticalBlur(float* weights, int32_t radius, 7611e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) { 76289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float blurredPixel = 0.0f; 76389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float currentPixel = 0.0f; 76489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 76589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for(int32_t y = 0; y < height; y ++) { 76689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 76789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* output = dest + y * width; 76889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 76989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for(int32_t x = 0; x < width; x ++) { 77089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel = 0.0f; 77189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const float* gPtr = weights; 77289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* input = source + x; 77389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Optimization for non-border pixels 77489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk if ((y > radius) && (y < (height - radius))) { 77589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + ((y - radius) * width); 77689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for(int32_t r = -radius; r <= radius; r ++) { 77789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk currentPixel = (float)(*i); 77889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 77989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 78089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk i += width; 78189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 78289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } else { 78389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for(int32_t r = -radius; r <= radius; r ++) { 78489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int validH = y + r; 78589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Clamp to zero and width 78689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk if(validH < 0) { 78789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validH = 0; 78889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 78989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk if(validH > height - 1) { 79089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validH = height - 1; 79189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 79289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 79389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + validH * width; 79489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk currentPixel = (float)(*i); 79589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 79689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 79789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 79889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 79989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk *output = (uint8_t)blurredPixel; 80089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk output ++; 80189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 80289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 80389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 80489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 80589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 80689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::blurImage(uint8_t *image, int32_t width, int32_t height, int32_t radius) { 80789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float *gaussian = new float[2 * radius + 1]; 80889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk computeGaussianWeights(gaussian, radius); 80989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* scratch = new uint8_t[width * height]; 81089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk horizontalBlur(gaussian, radius, image, scratch, width, height); 81189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk verticalBlur(gaussian, radius, scratch, image, width, height); 81289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk delete[] gaussian; 81389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk delete[] scratch; 81489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 81589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 816694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace uirenderer 817694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace android 818