FontRenderer.cpp revision f18136cb3c881a9d16c1a4f0f341732c276936bf
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 72f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk if(bounds->bottom > nPenY) { 73f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->bottom = nPenY; 74f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 75f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk if(bounds->left > nPenX) { 76f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->left = nPenX; 77f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 78f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk if(bounds->right < nPenX + width) { 79f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->right = nPenX + width; 80f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 81f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 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, 10589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 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++) { 119f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 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) { 13165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueFor(utfChar); 13265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk if (cachedGlyph == NULL) { 13365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk cachedGlyph = cacheGlyph(paint, utfChar); 13465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 13565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 13665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk // Is the glyph still in texture cache? 13765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk if (!cachedGlyph->mIsValid) { 13865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk const SkGlyph& skiaGlyph = paint->getUnicharMetrics(utfChar); 13965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk updateGlyphCache(paint, skiaGlyph, cachedGlyph); 14065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 14165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 14265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk return cachedGlyph; 14365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk} 14465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 14551769a68a5cb34e9564740c6a854fcb93018789dRomain Guyvoid Font::renderUTF(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 146f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int numGlyphs, int x, int y, 147f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) { 148f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk if(bitmap != NULL && bitmapW > 0 && bitmapH > 0) { 149f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk renderUTF(paint, text, start, len, numGlyphs, x, y, BITMAP, 150f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bitmap, bitmapW, bitmapH, NULL); 151f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 152f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk else { 153f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk renderUTF(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, 154f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 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, 160f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int numGlyphs, Rect *bounds) { 161f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 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, 170f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int numGlyphs, int x, int y, RenderMode mode, 171f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH, 172f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk Rect *bounds) { 173694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (numGlyphs == 0 || text == NULL || len == 0) { 174694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 175694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 176694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 177694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int penX = x, penY = y; 178694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int glyphsLeft = 1; 179694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (numGlyphs > 0) { 180694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyphsLeft = numGlyphs; 181694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 182694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 183694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy text += start; 184694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 185694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy while (glyphsLeft > 0) { 186694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int32_t utfChar = SkUTF16_NextUnichar((const uint16_t**) &text); 187694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 188694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Reached the end of the string or encountered 189694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (utfChar < 0) { 190694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 191694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 192694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 19365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk CachedGlyphInfo* cachedGlyph = getCachedUTFChar(paint, utfChar); 194694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 195694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage 196694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (cachedGlyph->mIsValid) { 197f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk switch(mode) { 198f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk case FRAMEBUFFER: 19989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk drawCachedGlyph(cachedGlyph, penX, penY); 200f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk break; 201f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk case BITMAP: 202f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk drawCachedGlyph(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH); 203f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk break; 204f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk case MEASURE: 205f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk measureCachedGlyph(cachedGlyph, penX, penY, bounds); 206f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk break; 20789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 208694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 209694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 21009147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy penX += SkFixedFloor(cachedGlyph->mAdvanceX); 211694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 212694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If we were given a specific number of glyphs, decrement 213694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (numGlyphs > 0) { 214694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyphsLeft--; 215694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 216694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 217694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 218694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 21951769a68a5cb34e9564740c6a854fcb93018789dRomain Guyvoid Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph) { 220694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mAdvanceX = skiaGlyph.fAdvanceX; 221694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mAdvanceY = skiaGlyph.fAdvanceY; 222694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapLeft = skiaGlyph.fLeft; 223694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapTop = skiaGlyph.fTop; 224694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 225694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startX = 0; 226694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startY = 0; 227694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 228694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Get the bitmap for the glyph 229694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy paint->findImage(skiaGlyph); 23051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy glyph->mIsValid = mState->cacheBitmap(skiaGlyph, &startX, &startY); 231694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 232694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!glyph->mIsValid) { 233694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 234694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 235694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 236694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endX = startX + skiaGlyph.fWidth; 237694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endY = startY + skiaGlyph.fHeight; 238694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 23989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk glyph->mStartX = startX; 24089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk glyph->mStartY = startY; 241694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapWidth = skiaGlyph.fWidth; 242694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapHeight = skiaGlyph.fHeight; 243694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 24451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy uint32_t cacheWidth = mState->getCacheWidth(); 24551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy uint32_t cacheHeight = mState->getCacheHeight(); 246694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 247694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapMinU = (float) startX / (float) cacheWidth; 248694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapMinV = (float) startY / (float) cacheHeight; 249694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapMaxU = (float) endX / (float) cacheWidth; 250694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapMaxV = (float) endY / (float) cacheHeight; 251694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 25251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mState->mUploadTexture = true; 253694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 254694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 25551769a68a5cb34e9564740c6a854fcb93018789dRomain GuyFont::CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, int32_t glyph) { 25651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy CachedGlyphInfo* newGlyph = new CachedGlyphInfo(); 257694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCachedGlyphs.add(glyph, newGlyph); 258694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 259694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy const SkGlyph& skiaGlyph = paint->getUnicharMetrics(glyph); 260694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy newGlyph->mGlyphIndex = skiaGlyph.fID; 261694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy newGlyph->mIsValid = false; 262694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 263694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy updateGlyphCache(paint, skiaGlyph, newGlyph); 264694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 265694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return newGlyph; 266694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 267694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 268694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFont* Font::create(FontRenderer* state, uint32_t fontId, float fontSize) { 269694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy Vector<Font*> &activeFonts = state->mActiveFonts; 270694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 271694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < activeFonts.size(); i++) { 27251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy Font* font = activeFonts[i]; 27351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy if (font->mFontId == fontId && font->mFontSize == fontSize) { 27451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy return font; 275694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 276694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 277694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 278694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy Font* newFont = new Font(state, fontId, fontSize); 279694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy activeFonts.push(newFont); 280694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return newFont; 281694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 282694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 283694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 284694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// FontRenderer 285694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 286694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 287694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::FontRenderer() { 28851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy LOGD("Creating FontRenderer"); 28951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 290694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mInitialized = false; 291694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mMaxNumberOfQuads = 1024; 292694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 2939b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mTextureId = 0; 294694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 295694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mIndexBufferID = 0; 296694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 29751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheWidth = DEFAULT_TEXT_CACHE_WIDTH; 2989b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT; 29951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 30051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy char property[PROPERTY_VALUE_MAX]; 30151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) { 30251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy LOGD(" Setting text cache width to %s pixels", property); 30351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheWidth = atoi(property); 30451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } else { 30551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy LOGD(" Using default text cache width of %i pixels", mCacheWidth); 30651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } 30751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 30851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy if (property_get(PROPERTY_TEXT_CACHE_HEIGHT, property, NULL) > 0) { 30951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy LOGD(" Setting text cache width to %s pixels", property); 31051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheHeight = atoi(property); 31151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } else { 31251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy LOGD(" Using default text cache height of %i pixels", mCacheHeight); 31351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } 314694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 315694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 316694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::~FontRenderer() { 317694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 318694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy delete mCacheLines[i]; 319694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 320694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCacheLines.clear(); 321694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 32289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk delete[] mTextMeshPtr; 32389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk delete[] mTextTexture; 3249b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 3259b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk if(mTextureId) { 3269b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk glDeleteTextures(1, &mTextureId); 3279b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 328694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 329694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy Vector<Font*> fontsToDereference = mActiveFonts; 330694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < fontsToDereference.size(); i++) { 331694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy delete fontsToDereference[i]; 332694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 333694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 334694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 335694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::flushAllAndInvalidate() { 336694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex != 0) { 337694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 338694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 339694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 340694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mActiveFonts.size(); i++) { 341694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mActiveFonts[i]->invalidateTextureCache(); 342694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 343694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 344694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCacheLines[i]->mCurrentCol = 0; 345694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 346694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 347694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 34851769a68a5cb34e9564740c6a854fcb93018789dRomain Guybool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) { 349694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If the glyph is too tall, don't cache it 350694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (glyph.fWidth > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) { 351694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy LOGE("Font size to large to fit in cache. width, height = %i, %i", 352694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (int) glyph.fWidth, (int) glyph.fHeight); 353694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return false; 354694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 355694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 356694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Now copy the bitmap into the cache texture 357694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startX = 0; 358694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startY = 0; 359694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 360694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bool bitmapFit = false; 361694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 362694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY); 363694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (bitmapFit) { 364694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 365694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 366694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 367694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 368694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If the new glyph didn't fit, flush the state so far and invalidate everything 369694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!bitmapFit) { 370694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy flushAllAndInvalidate(); 371694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 372694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Try to fit it again 373694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 374694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY); 375694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (bitmapFit) { 376694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 377694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 378694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 379694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 380694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // if we still don't fit, something is wrong and we shouldn't draw 381694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!bitmapFit) { 382694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy LOGE("Bitmap doesn't fit in cache. width, height = %i, %i", 383694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (int) glyph.fWidth, (int) glyph.fHeight); 384694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return false; 385694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 386694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 387694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 388694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *retOriginX = startX; 389694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *retOriginY = startY; 390694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 391694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endX = startX + glyph.fWidth; 392694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endY = startY + glyph.fHeight; 393694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 394694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t cacheWidth = mCacheWidth; 395694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 39689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* cacheBuffer = mTextTexture; 39789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage; 398694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy unsigned int stride = glyph.rowBytes(); 399694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 400694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; 401694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) { 402694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) { 40389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t tempCol = bitmapBuffer[bY * stride + bX]; 404694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy cacheBuffer[cacheY * cacheWidth + cacheX] = tempCol; 405694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 406694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 407694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 408694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return true; 409694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 410694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 411694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::initTextTexture() { 41289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk mTextTexture = new uint8_t[mCacheWidth * mCacheHeight]; 413694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mUploadTexture = false; 414694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 415694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glGenTextures(1, &mTextureId); 416694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glBindTexture(GL_TEXTURE_2D, mTextureId); 417694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 4189b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk // Initialize texture dimentions 4199b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mCacheWidth, mCacheHeight, 0, 4209b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk GL_ALPHA, GL_UNSIGNED_BYTE, 0); 421694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 422694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 423694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 424694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 425694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 426694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 427694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 428694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Split up our cache texture into lines of certain widths 429694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int nextLine = 0; 43051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 16, nextLine, 0)); 431694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 43251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 24, nextLine, 0)); 433694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 43465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mCacheLines.push(new CacheTextureLine(mCacheWidth, 24, nextLine, 0)); 43565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk nextLine += mCacheLines.top()->mMaxHeight; 43651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 32, nextLine, 0)); 437694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 43851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 32, nextLine, 0)); 439694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 44051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, 40, nextLine, 0)); 441694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 44251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCacheLines.push(new CacheTextureLine(mCacheWidth, mCacheHeight - nextLine, nextLine, 0)); 443694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 444694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 445694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Avoid having to reallocate memory and render quad by quad 446694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::initVertexArrayBuffers() { 447694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t numIndicies = mMaxNumberOfQuads * 6; 448694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t indexBufferSizeBytes = numIndicies * sizeof(uint16_t); 44951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes); 450694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 451694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Four verts, two triangles , six indices per quad 452694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mMaxNumberOfQuads; i++) { 453694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int i6 = i * 6; 454694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int i4 = i * 4; 455694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 456694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 0] = i4 + 0; 457694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 1] = i4 + 1; 458694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 2] = i4 + 2; 459694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 460694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 3] = i4 + 0; 461694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 4] = i4 + 2; 462694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 5] = i4 + 3; 463694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 464694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 465694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glGenBuffers(1, &mIndexBufferID); 466694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glBindBuffer(GL_ARRAY_BUFFER, mIndexBufferID); 467694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glBufferData(GL_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_DYNAMIC_DRAW); 468694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glBindBuffer(GL_ARRAY_BUFFER, 0); 469694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 470694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy free(indexBufferData); 471694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 472694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t coordSize = 3; 473694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t uvSize = 2; 474694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t vertsPerQuad = 4; 4759b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize; 4769b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mTextMeshPtr = new float[vertexBufferSize]; 477694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 478694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 479694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// We don't want to allocate anything unless we actually draw text 480694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::checkInit() { 481694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mInitialized) { 482694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 483694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 484694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 485694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy initTextTexture(); 486694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy initVertexArrayBuffers(); 487694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 48865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk // We store a string with letters in a rough frequency of occurrence 48965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mLatinPrecache = String16("eisarntolcdugpmhbyfvkwzxjq "); 49065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mLatinPrecache += String16("EISARNTOLCDUGPMHBYFVKWZXJQ"); 49165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mLatinPrecache += String16(",.?!()-+@;:`'"); 49265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mLatinPrecache += String16("0123456789"); 49365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 494694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mInitialized = true; 495694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 496694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 4979b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::checkTextureUpdate() { 4989b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk if (!mUploadTexture) { 4999b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk return; 5009b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 5019b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5029b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk glBindTexture(GL_TEXTURE_2D, mTextureId); 5039b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5049b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk // Iterate over all the cache lines and see which ones need to be updated 5059b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk for (uint32_t i = 0; i < mCacheLines.size(); i++) { 5069b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk CacheTextureLine* cl = mCacheLines[i]; 5079b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk if(cl->mDirty) { 5089b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t xOffset = 0; 5099b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t yOffset = cl->mCurrentRow; 5109b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t width = mCacheWidth; 5119b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t height = cl->mMaxHeight; 5129b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk void* textureData = mTextTexture + yOffset*width; 5139b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5149b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height, 5159b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk GL_ALPHA, GL_UNSIGNED_BYTE, textureData); 5169b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5179b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk cl->mDirty = false; 5189b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 519694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 520694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 5219b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mUploadTexture = false; 5229b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk} 5239b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5249b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::issueDrawCommand() { 5259b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 5269b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk checkTextureUpdate(); 5279b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 52851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float* vtx = mTextMeshPtr; 52951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float* tex = vtx + 3; 530694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 531694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // position is slot 0 532694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t slot = 0; 533694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glVertexAttribPointer(slot, 3, GL_FLOAT, false, 20, vtx); 534694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 535694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // texture0 is slot 1 536694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy slot = 1; 537694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glVertexAttribPointer(slot, 2, GL_FLOAT, false, 20, tex); 538694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 539694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID); 540694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL); 541694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 542694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 543694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::appendMeshQuad(float x1, float y1, float z1, float u1, float v1, float x2, 544694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3, 545694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy float x4, float y4, float z4, float u4, float v4) { 54609147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy if (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom) { 54709147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy return; 54809147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy } 54909147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy 550694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy const uint32_t vertsPerQuad = 4; 551694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy const uint32_t floatsPerVert = 5; 55251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float* currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert; 553694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 554694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x1; 555694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y1; 556694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = z1; 557694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u1; 558694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v1; 559694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 560694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x2; 561694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y2; 562694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = z2; 563694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u2; 564694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v2; 565694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 566694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x3; 567694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y3; 568694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = z3; 569694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u3; 570694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v3; 571694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 572694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x4; 573694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y4; 574694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = z4; 575694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u4; 576694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v4; 577694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 578694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex++; 579694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 580694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex == mMaxNumberOfQuads) { 581694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 582694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 583694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 584694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 585694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 58665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukuint32_t FontRenderer::getRemainingCacheCapacity() { 58765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t remainingCapacity = 0; 58865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk float totalPixels = 0; 58965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 59065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol); 59165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk totalPixels += mCacheLines[i]->mMaxWidth; 59265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 59365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk remainingCapacity = (remainingCapacity * 100) / totalPixels; 59465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk return remainingCapacity; 59565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk} 59665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 59765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::precacheLatin(SkPaint* paint) { 59865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk // Remaining capacity is measured in % 59965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t remainingCapacity = getRemainingCacheCapacity(); 60065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t precacheIdx = 0; 60165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk while(remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) { 60265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mCurrentFont->getCachedUTFChar(paint, (int32_t)mLatinPrecache[precacheIdx]); 60365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk remainingCapacity = getRemainingCacheCapacity(); 60465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk precacheIdx ++; 60565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 60665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk} 60765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 60865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) { 60965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t currentNumFonts = mActiveFonts.size(); 610694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentFont = Font::create(this, fontId, fontSize); 61165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 61265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk const float maxPrecacheFontSize = 40.0f; 61365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk bool isNewFont = currentNumFonts != mActiveFonts.size(); 61465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 61565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk if(isNewFont && fontSize <= maxPrecacheFontSize ){ 61665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk precacheLatin(paint); 61765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 618694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 619f18136cb3c881a9d16c1a4f0f341732c276936bfAlex SakhartchoukFontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text, 620f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius) { 621f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 622f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk Rect bounds; 623f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk mCurrentFont->measureUTF(paint, text, startIndex, len, numGlyphs, &bounds); 624f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk uint32_t paddedWidth = (uint32_t)(bounds.right - bounds.left) + 2*radius; 625f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk uint32_t paddedHeight = (uint32_t)(bounds.top - bounds.bottom) + 2*radius; 626f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight]; 627f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk for(uint32_t i = 0; i < paddedWidth * paddedHeight; i ++) { 628f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk dataBuffer[i] = 0; 629f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 630f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int penX = radius - bounds.left; 631f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int penY = radius - bounds.bottom; 632f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 633f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, penX, penY, 634f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk dataBuffer, paddedWidth, paddedHeight); 635f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk blurImage(dataBuffer, paddedWidth, paddedHeight, radius); 636f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 637f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk DropShadow image; 638f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.width = paddedWidth; 639f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.height = paddedHeight; 640f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.image = dataBuffer; 641f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.penX = penX; 642f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.penY = penY; 643f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk return image; 644f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 645694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 64651769a68a5cb34e9564740c6a854fcb93018789dRomain Guyvoid FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text, 64751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y) { 648694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy checkInit(); 649694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 65009147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy if (!mCurrentFont) { 65109147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy LOGE("No font set"); 652694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 653694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 654694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 65509147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy mClip = clip; 65651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, x, y); 657694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 658694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex != 0) { 659694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 660694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 661694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 662694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 663694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 66489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::computeGaussianWeights(float* weights, int32_t radius) { 66589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Compute gaussian weights for the blur 66689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // e is the euler's number 66789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float e = 2.718281828459045f; 66889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float pi = 3.1415926535897932f; 66989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 ) 67089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // x is of the form [-radius .. 0 .. radius] 67189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // and sigma varies with radius. 67289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Based on some experimental radius values and sigma's 67389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // we approximately fit sigma = f(radius) as 674f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk // sigma = radius * 0.3 + 0.6 67589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // The larger the radius gets, the more our gaussian blur 67689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // will resemble a box blur since with large sigma 67789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // the gaussian curve begins to lose its shape 678f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk float sigma = 0.3f * (float)radius + 0.6f; 67989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 68089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Now compute the coefficints 68189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // We will store some redundant values to save some math during 68289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // the blur calculations 68389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // precompute some values 68489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma); 68589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float coeff2 = - 1.0f / (2.0f * sigma * sigma); 68689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 68789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float normalizeFactor = 0.0f; 68889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for(int32_t r = -radius; r <= radius; r ++) { 68989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float floatR = (float)r; 69089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2); 69189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk normalizeFactor += weights[r + radius]; 69289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 69389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 69489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk //Now we need to normalize the weights because all our coefficients need to add up to one 69589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk normalizeFactor = 1.0f / normalizeFactor; 69689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for(int32_t r = -radius; r <= radius; r ++) { 69789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk weights[r + radius] *= normalizeFactor; 69889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 69989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 70089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 70189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::horizontalBlur(float* weights, int32_t radius, 70289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* source, uint8_t* dest, 70389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int32_t width, int32_t height) { 70489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float blurredPixel = 0.0f; 70589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float currentPixel = 0.0f; 70689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 70789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for(int32_t y = 0; y < height; y ++) { 70889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 70989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* input = source + y * width; 71089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* output = dest + y * width; 71189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 71289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for(int32_t x = 0; x < width; x ++) { 71389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel = 0.0f; 71489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const float* gPtr = weights; 71589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Optimization for non-border pixels 71689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk if ((x > radius) && (x < (width - radius))) { 71789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + (x - radius); 71889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for(int r = -radius; r <= radius; r ++) { 71989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk currentPixel = (float)(*i); 72089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 72189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 72289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk i++; 72389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 72489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } else { 72589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for(int32_t r = -radius; r <= radius; r ++) { 72689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Stepping left and right away from the pixel 72789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int validW = x + r; 72889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk if(validW < 0) { 72989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validW = 0; 73089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 73189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk if(validW > width - 1) { 73289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validW = width - 1; 73389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 73489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 73589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk currentPixel = (float)(input[validW]); 73689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 73789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 73889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 73989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 74089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk *output = (uint8_t)blurredPixel; 74189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk output ++; 74289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 74389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 74489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 74589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 74689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::verticalBlur(float* weights, int32_t radius, 74789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* source, uint8_t* dest, 74889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int32_t width, int32_t height) { 74989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float blurredPixel = 0.0f; 75089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float currentPixel = 0.0f; 75189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 75289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for(int32_t y = 0; y < height; y ++) { 75389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 75489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* output = dest + y * width; 75589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 75689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for(int32_t x = 0; x < width; x ++) { 75789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel = 0.0f; 75889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const float* gPtr = weights; 75989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* input = source + x; 76089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Optimization for non-border pixels 76189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk if ((y > radius) && (y < (height - radius))) { 76289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + ((y - radius) * width); 76389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for(int32_t r = -radius; r <= radius; r ++) { 76489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk currentPixel = (float)(*i); 76589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 76689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 76789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk i += width; 76889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 76989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } else { 77089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for(int32_t r = -radius; r <= radius; r ++) { 77189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int validH = y + r; 77289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Clamp to zero and width 77389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk if(validH < 0) { 77489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validH = 0; 77589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 77689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk if(validH > height - 1) { 77789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validH = height - 1; 77889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 77989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 78089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + validH * width; 78189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk currentPixel = (float)(*i); 78289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 78389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 78489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 78589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 78689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk *output = (uint8_t)blurredPixel; 78789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk output ++; 78889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 78989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 79089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 79189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 79289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 79389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::blurImage(uint8_t *image, int32_t width, int32_t height, int32_t radius) { 79489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float *gaussian = new float[2 * radius + 1]; 79589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk computeGaussianWeights(gaussian, radius); 79689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* scratch = new uint8_t[width * height]; 79789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk horizontalBlur(gaussian, radius, image, scratch, width, height); 79889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk verticalBlur(gaussian, radius, scratch, image, width, height); 79989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk delete[] gaussian; 80089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk delete[] scratch; 80189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 80289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 803694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace uirenderer 804694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace android 805