FontRenderer.cpp revision 2a47c14e2a6f152496b43104bc785c488583fd59
1694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/* 2694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * Copyright (C) 2010 The Android Open Source Project 3694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * 4694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * Licensed under the Apache License, Version 2.0 (the "License"); 5694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * you may not use this file except in compliance with the License. 6694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * You may obtain a copy of the License at 7694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * 8694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * http://www.apache.org/licenses/LICENSE-2.0 9694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * 10694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * Unless required by applicable law or agreed to in writing, software 11694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * distributed under the License is distributed on an "AS IS" BASIS, 12694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * See the License for the specific language governing permissions and 14694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * limitations under the License. 15694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy */ 16694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 17694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy#define LOG_TAG "OpenGLRenderer" 18694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 19694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy#include <SkUtils.h> 20694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 2151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#include <cutils/properties.h> 22e2d345ea67e2960b37bfdc0fc8626d1bfa747404Romain Guy 2351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#include <utils/Log.h> 2451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 2515bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy#include "Caches.h" 26c9855a53edfac818dc68714557185977556f849dRomain Guy#include "Debug.h" 2751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#include "FontRenderer.h" 287de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase#include "Caches.h" 2951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 30694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guynamespace android { 31694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guynamespace uirenderer { 32694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 33694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 3451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy// Defines 3551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy/////////////////////////////////////////////////////////////////////////////// 3651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 3751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#define DEFAULT_TEXT_CACHE_WIDTH 1024 3851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy#define DEFAULT_TEXT_CACHE_HEIGHT 256 3944984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase#define MAX_TEXT_CACHE_WIDTH 2048 407de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase#define TEXTURE_BORDER_SIZE 2 417de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 427de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase/////////////////////////////////////////////////////////////////////////////// 437de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase// CacheTextureLine 447de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase/////////////////////////////////////////////////////////////////////////////// 457de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 467de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasebool CacheTextureLine::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) { 477de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (glyph.fHeight + TEXTURE_BORDER_SIZE > mMaxHeight) { 487de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase return false; 497de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 507de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 517de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (mCurrentCol + glyph.fWidth + TEXTURE_BORDER_SIZE < mMaxWidth) { 527de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase *retOriginX = mCurrentCol + 1; 537de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase *retOriginY = mCurrentRow + 1; 547de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCurrentCol += glyph.fWidth + TEXTURE_BORDER_SIZE; 557de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mDirty = true; 567de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase return true; 577de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 587de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 597de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase return false; 607de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase} 6144984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase 6251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy/////////////////////////////////////////////////////////////////////////////// 63694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Font 64694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 65694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 662577db1ec135a1470a2c42139772ec97a6c30e78Romain GuyFont::Font(FontRenderer* state, uint32_t fontId, float fontSize, 67bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy int flags, uint32_t italicStyle, uint32_t scaleX, 68bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy SkPaint::Style style, uint32_t strokeWidth) : 692577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy mState(state), mFontId(fontId), mFontSize(fontSize), 70bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy mFlags(flags), mItalicStyle(italicStyle), mScaleX(scaleX), 71bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy mStyle(style), mStrokeWidth(mStrokeWidth) { 72694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 73694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 74694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 75694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFont::~Font() { 76694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t ct = 0; ct < mState->mActiveFonts.size(); ct++) { 77694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mState->mActiveFonts[ct] == this) { 78694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mState->mActiveFonts.removeAt(ct); 79694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 80694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 81694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 82694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 83694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) { 84726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy delete mCachedGlyphs.valueAt(i); 85694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 86694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 87694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 88694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid Font::invalidateTextureCache() { 89694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) { 90694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCachedGlyphs.valueAt(i)->mIsValid = false; 91694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 92694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 93694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 94f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchoukvoid Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y, Rect *bounds) { 95f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int nPenX = x + glyph->mBitmapLeft; 96f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int nPenY = y + glyph->mBitmapTop; 97f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 98f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int width = (int) glyph->mBitmapWidth; 99f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int height = (int) glyph->mBitmapHeight; 100f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 10161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->bottom > nPenY) { 102f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->bottom = nPenY; 103f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 10461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->left > nPenX) { 105f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->left = nPenX; 106f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 10761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->right < nPenX + width) { 108f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->right = nPenX + width; 109f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 11061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->top < nPenY + height) { 111f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->top = nPenY + height; 112f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 113f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 114f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 115694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y) { 116694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int nPenX = x + glyph->mBitmapLeft; 117694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight; 118694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 11951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float u1 = glyph->mBitmapMinU; 12051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float u2 = glyph->mBitmapMaxU; 12151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float v1 = glyph->mBitmapMinV; 12251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float v2 = glyph->mBitmapMaxV; 12351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 12451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy int width = (int) glyph->mBitmapWidth; 12551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy int height = (int) glyph->mBitmapHeight; 12651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 127d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy mState->appendMeshQuad(nPenX, nPenY, u1, v2, 128d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy nPenX + width, nPenY, u2, v2, 129d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy nPenX + width, nPenY - height, u2, v1, 1307de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase nPenX, nPenY - height, u1, v1, glyph->mCachedTextureLine->mCacheTexture); 131694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 132694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 133b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guyvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, 134b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH) { 13589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int nPenX = x + glyph->mBitmapLeft; 13689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int nPenY = y + glyph->mBitmapTop; 13789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 13889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint32_t endX = glyph->mStartX + glyph->mBitmapWidth; 13989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint32_t endY = glyph->mStartY + glyph->mBitmapHeight; 14089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1417de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase CacheTexture *cacheTexture = glyph->mCachedTextureLine->mCacheTexture; 1427de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint32_t cacheWidth = cacheTexture->mWidth; 1437de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase const uint8_t* cacheBuffer = cacheTexture->mTexture; 14489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 145f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk uint32_t cacheX = 0, cacheY = 0; 146f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int32_t bX = 0, bY = 0; 14789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) { 14889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) { 149b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) { 150f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk LOGE("Skipping invalid index"); 151f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk continue; 152f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 15389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX]; 15489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk bitmap[bY * bitmapW + bX] = tempCol; 15589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 15689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 15789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 15889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1597de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet HaaseCachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) { 1601e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy CachedGlyphInfo* cachedGlyph = NULL; 161726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy ssize_t index = mCachedGlyphs.indexOfKey(textUnit); 1621e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (index >= 0) { 1631e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy cachedGlyph = mCachedGlyphs.valueAt(index); 1641e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } else { 165726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy cachedGlyph = cacheGlyph(paint, textUnit); 16665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 16765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 16865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk // Is the glyph still in texture cache? 16965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk if (!cachedGlyph->mIsValid) { 170726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit); 17165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk updateGlyphCache(paint, skiaGlyph, cachedGlyph); 17265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 17365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 17465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk return cachedGlyph; 17565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk} 17665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 177726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guyvoid Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 17861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy int numGlyphs, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) { 17961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bitmap != NULL && bitmapW > 0 && bitmapH > 0) { 180726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy render(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap, 18161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy bitmapW, bitmapH, NULL); 18261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy } else { 183726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL, 184726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy 0, 0, NULL); 185f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 186f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 187f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 188726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guyvoid Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 18961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy int numGlyphs, Rect *bounds) { 19061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds == NULL) { 191f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk LOGE("No return rectangle provided to measure text"); 192f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk return; 193f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 194f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->set(1e6, -1e6, -1e6, 1e6); 195726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds); 196f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 197f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 19858ef7fbf16864164efe98bf613b15c64deb1afc0Romain Guy#define SkAutoKern_AdjustF(prev, next) (((next) - (prev) + 32) >> 6 << 16) 1992bffd268f135df8308c9e67af110525a5c463424Romain Guy 200726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guyvoid Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 20161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap, 20261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy uint32_t bitmapW, uint32_t bitmapH,Rect *bounds) { 203694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (numGlyphs == 0 || text == NULL || len == 0) { 204694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 205694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 206694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 2075a6d3a4c0311318e6f1d4ee06aa47606e055a81bRomain Guy float penX = x; 2082bffd268f135df8308c9e67af110525a5c463424Romain Guy int penY = y; 209694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int glyphsLeft = 1; 210694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (numGlyphs > 0) { 211694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyphsLeft = numGlyphs; 212694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 213694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 2142bffd268f135df8308c9e67af110525a5c463424Romain Guy SkFixed prevRsbDelta = 0; 2155a6d3a4c0311318e6f1d4ee06aa47606e055a81bRomain Guy penX += 0.5f; 2162bffd268f135df8308c9e67af110525a5c463424Romain Guy 217694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy text += start; 218694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 219694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy while (glyphsLeft > 0) { 220726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy glyph_t glyph = GET_GLYPH(text); 221694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 22261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy // Reached the end of the string 223726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy if (IS_END_OF_STRING(glyph)) { 224694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 225694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 226694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 227726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph); 2285a6d3a4c0311318e6f1d4ee06aa47606e055a81bRomain Guy penX += SkFixedToFloat(SkAutoKern_AdjustF(prevRsbDelta, cachedGlyph->mLsbDelta)); 2292bffd268f135df8308c9e67af110525a5c463424Romain Guy prevRsbDelta = cachedGlyph->mRsbDelta; 230694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 231694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage 232694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (cachedGlyph->mIsValid) { 233f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk switch(mode) { 234f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk case FRAMEBUFFER: 2355a6d3a4c0311318e6f1d4ee06aa47606e055a81bRomain Guy drawCachedGlyph(cachedGlyph, (int) floorf(penX), penY); 236f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk break; 237f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk case BITMAP: 2385a6d3a4c0311318e6f1d4ee06aa47606e055a81bRomain Guy drawCachedGlyph(cachedGlyph, (int) floorf(penX), penY, bitmap, bitmapW, bitmapH); 239f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk break; 240f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk case MEASURE: 2415a6d3a4c0311318e6f1d4ee06aa47606e055a81bRomain Guy measureCachedGlyph(cachedGlyph, (int) floorf(penX), penY, bounds); 242f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk break; 24389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 244694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 245694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 2465a6d3a4c0311318e6f1d4ee06aa47606e055a81bRomain Guy penX += SkFixedToFloat(cachedGlyph->mAdvanceX); 247694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 248694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If we were given a specific number of glyphs, decrement 249694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (numGlyphs > 0) { 250694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyphsLeft--; 251694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 252694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 253694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 254694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 25551769a68a5cb34e9564740c6a854fcb93018789dRomain Guyvoid Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph) { 256694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mAdvanceX = skiaGlyph.fAdvanceX; 257694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mAdvanceY = skiaGlyph.fAdvanceY; 258694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapLeft = skiaGlyph.fLeft; 259694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapTop = skiaGlyph.fTop; 2602bffd268f135df8308c9e67af110525a5c463424Romain Guy glyph->mLsbDelta = skiaGlyph.fLsbDelta; 2612bffd268f135df8308c9e67af110525a5c463424Romain Guy glyph->mRsbDelta = skiaGlyph.fRsbDelta; 262694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 263694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startX = 0; 264694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startY = 0; 265694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 266694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Get the bitmap for the glyph 267694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy paint->findImage(skiaGlyph); 2687de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY); 269694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 270694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!glyph->mIsValid) { 271694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 272694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 273694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 274694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endX = startX + skiaGlyph.fWidth; 275694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endY = startY + skiaGlyph.fHeight; 276694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 27789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk glyph->mStartX = startX; 27889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk glyph->mStartY = startY; 279694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapWidth = skiaGlyph.fWidth; 280694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapHeight = skiaGlyph.fHeight; 281694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 2827de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint32_t cacheWidth = glyph->mCachedTextureLine->mCacheTexture->mWidth; 2837de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint32_t cacheHeight = glyph->mCachedTextureLine->mCacheTexture->mHeight; 284694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 285694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapMinU = (float) startX / (float) cacheWidth; 286694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapMinV = (float) startY / (float) cacheHeight; 287694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapMaxU = (float) endX / (float) cacheWidth; 288694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapMaxV = (float) endY / (float) cacheHeight; 289694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 29051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mState->mUploadTexture = true; 291694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 292694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 2937de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet HaaseCachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph) { 29451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy CachedGlyphInfo* newGlyph = new CachedGlyphInfo(); 295694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCachedGlyphs.add(glyph, newGlyph); 296694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 297726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph); 298694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy newGlyph->mGlyphIndex = skiaGlyph.fID; 299694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy newGlyph->mIsValid = false; 300694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 301694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy updateGlyphCache(paint, skiaGlyph, newGlyph); 302694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 303694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return newGlyph; 304694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 305694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 3062577db1ec135a1470a2c42139772ec97a6c30e78Romain GuyFont* Font::create(FontRenderer* state, uint32_t fontId, float fontSize, 307bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy int flags, uint32_t italicStyle, uint32_t scaleX, 308bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy SkPaint::Style style, uint32_t strokeWidth) { 309694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy Vector<Font*> &activeFonts = state->mActiveFonts; 310694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 311694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < activeFonts.size(); i++) { 31251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy Font* font = activeFonts[i]; 3132577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy if (font->mFontId == fontId && font->mFontSize == fontSize && 3148668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase font->mFlags == flags && font->mItalicStyle == italicStyle && 315bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy font->mScaleX == scaleX && font->mStyle == style && 316bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy (style == SkPaint::kFill_Style || font->mStrokeWidth == strokeWidth)) { 31751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy return font; 318694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 319694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 320694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 321bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle, 322bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy scaleX, style, strokeWidth); 323694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy activeFonts.push(newFont); 324694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return newFont; 325694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 326694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 327694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 328694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// FontRenderer 329694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 330694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 331514fb18827186591d66973c2362c859b64b63556Romain Guystatic bool sLogFontRendererCreate = true; 332514fb18827186591d66973c2362c859b64b63556Romain Guy 333694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::FontRenderer() { 334c9855a53edfac818dc68714557185977556f849dRomain Guy if (sLogFontRendererCreate) { 335c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD("Creating FontRenderer"); 336c9855a53edfac818dc68714557185977556f849dRomain Guy } 33751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 338b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy mGammaTable = NULL; 339694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mInitialized = false; 340694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mMaxNumberOfQuads = 1024; 341694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 342694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 3439cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy mTextMeshPtr = NULL; 3447de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCurrentCacheTexture = NULL; 3457de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mLastCacheTexture = NULL; 3467de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTextureSmall = NULL; 3477de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTexture128 = NULL; 3487de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTexture256 = NULL; 3497de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTexture512 = NULL; 3509cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy 3512a47c14e2a6f152496b43104bc785c488583fd59Chet Haase mLinearFiltering = false; 3522a47c14e2a6f152496b43104bc785c488583fd59Chet Haase 353694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mIndexBufferID = 0; 354694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 3557de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mSmallCacheWidth = DEFAULT_TEXT_CACHE_WIDTH; 3567de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mSmallCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT; 35751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 35851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy char property[PROPERTY_VALUE_MAX]; 35951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) { 360c9855a53edfac818dc68714557185977556f849dRomain Guy if (sLogFontRendererCreate) { 361c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD(" Setting text cache width to %s pixels", property); 362c9855a53edfac818dc68714557185977556f849dRomain Guy } 3637de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mSmallCacheWidth = atoi(property); 36451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } else { 365514fb18827186591d66973c2362c859b64b63556Romain Guy if (sLogFontRendererCreate) { 3667de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase INIT_LOGD(" Using default text cache width of %i pixels", mSmallCacheWidth); 367514fb18827186591d66973c2362c859b64b63556Romain Guy } 36851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } 36951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 37051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy if (property_get(PROPERTY_TEXT_CACHE_HEIGHT, property, NULL) > 0) { 371c9855a53edfac818dc68714557185977556f849dRomain Guy if (sLogFontRendererCreate) { 372c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD(" Setting text cache width to %s pixels", property); 373c9855a53edfac818dc68714557185977556f849dRomain Guy } 3747de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mSmallCacheHeight = atoi(property); 37551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } else { 376514fb18827186591d66973c2362c859b64b63556Romain Guy if (sLogFontRendererCreate) { 3777de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase INIT_LOGD(" Using default text cache height of %i pixels", mSmallCacheHeight); 378514fb18827186591d66973c2362c859b64b63556Romain Guy } 37951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } 380514fb18827186591d66973c2362c859b64b63556Romain Guy 381514fb18827186591d66973c2362c859b64b63556Romain Guy sLogFontRendererCreate = false; 382694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 383694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 384694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::~FontRenderer() { 385694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 386694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy delete mCacheLines[i]; 387694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 388694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCacheLines.clear(); 389694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 3909cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy if (mInitialized) { 3919cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy delete[] mTextMeshPtr; 3927de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase delete mCacheTextureSmall; 3937de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase delete mCacheTexture128; 3947de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase delete mCacheTexture256; 3957de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase delete mCacheTexture512; 3969b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 397694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 398694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy Vector<Font*> fontsToDereference = mActiveFonts; 399694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < fontsToDereference.size(); i++) { 400694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy delete fontsToDereference[i]; 401694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 402694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 403694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 404694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::flushAllAndInvalidate() { 405694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex != 0) { 406694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 407694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 408694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 409694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mActiveFonts.size(); i++) { 410694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mActiveFonts[i]->invalidateTextureCache(); 411694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 412694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 413694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCacheLines[i]->mCurrentCol = 0; 414694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 415694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 416694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 4172a47c14e2a6f152496b43104bc785c488583fd59Chet Haasevoid FontRenderer::allocateTextureMemory(CacheTexture *cacheTexture) { 4182a47c14e2a6f152496b43104bc785c488583fd59Chet Haase int width = cacheTexture->mWidth; 4192a47c14e2a6f152496b43104bc785c488583fd59Chet Haase int height = cacheTexture->mHeight; 4202a47c14e2a6f152496b43104bc785c488583fd59Chet Haase cacheTexture->mTexture = new uint8_t[width * height]; 4212a47c14e2a6f152496b43104bc785c488583fd59Chet Haase memset(cacheTexture->mTexture, 0, width * height * sizeof(uint8_t)); 4222a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId); 4232a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 4242a47c14e2a6f152496b43104bc785c488583fd59Chet Haase // Initialize texture dimensions 4252a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, 4262a47c14e2a6f152496b43104bc785c488583fd59Chet Haase GL_ALPHA, GL_UNSIGNED_BYTE, 0); 4272a47c14e2a6f152496b43104bc785c488583fd59Chet Haase 4282a47c14e2a6f152496b43104bc785c488583fd59Chet Haase const GLenum filtering = cacheTexture->mLinearFiltering ? GL_LINEAR : GL_NEAREST; 4292a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); 4302a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); 4317de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 4322a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 4332a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 4347de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase} 4357de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 4367de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasevoid FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph, 4377de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint32_t* retOriginX, uint32_t* retOriginY) { 4387de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase cachedGlyph->mIsValid = false; 439694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If the glyph is too tall, don't cache it 4407de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (glyph.fHeight + TEXTURE_BORDER_SIZE > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) { 4417de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase LOGE("Font size to large to fit in cache. width, height = %i, %i", 4427de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase (int) glyph.fWidth, (int) glyph.fHeight); 4437de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase return; 444694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 445694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 446694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Now copy the bitmap into the cache texture 447694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startX = 0; 448694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startY = 0; 449694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 450694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bool bitmapFit = false; 4517de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase CacheTextureLine *cacheLine; 452694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 453694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY); 454694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (bitmapFit) { 4557de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase cacheLine = mCacheLines[i]; 456694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 457694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 458694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 459694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 460694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If the new glyph didn't fit, flush the state so far and invalidate everything 461694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!bitmapFit) { 462694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy flushAllAndInvalidate(); 463694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 464694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Try to fit it again 465694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 466694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY); 467694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (bitmapFit) { 4687de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase cacheLine = mCacheLines[i]; 469694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 470694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 471694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 472694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 473694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // if we still don't fit, something is wrong and we shouldn't draw 474694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!bitmapFit) { 4757de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase return; 476694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 477694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 478694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 4797de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase cachedGlyph->mCachedTextureLine = cacheLine; 4807de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 481694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *retOriginX = startX; 482694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *retOriginY = startY; 483694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 484694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endX = startX + glyph.fWidth; 485694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endY = startY + glyph.fHeight; 486694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 4877de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint32_t cacheWidth = cacheLine->mMaxWidth; 488694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 4897de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase CacheTexture *cacheTexture = cacheLine->mCacheTexture; 4907de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (cacheTexture->mTexture == NULL) { 4917de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // Large-glyph texture memory is allocated only as needed 4922a47c14e2a6f152496b43104bc785c488583fd59Chet Haase allocateTextureMemory(cacheTexture); 4937de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 4947de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint8_t* cacheBuffer = cacheTexture->mTexture; 49589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage; 496694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy unsigned int stride = glyph.rowBytes(); 497694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 498694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; 499694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) { 500694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) { 50189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t tempCol = bitmapBuffer[bY * stride + bX]; 502b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol]; 503694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 504694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 5057de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase cachedGlyph->mIsValid = true; 506694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 507694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 5087de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet HaaseCacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) { 5097de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase GLuint textureId; 5107de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase glGenTextures(1, &textureId); 5112a47c14e2a6f152496b43104bc785c488583fd59Chet Haase uint8_t* textureMemory = NULL; 512694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 5132a47c14e2a6f152496b43104bc785c488583fd59Chet Haase CacheTexture* cacheTexture = new CacheTexture(textureMemory, textureId, width, height); 5142a47c14e2a6f152496b43104bc785c488583fd59Chet Haase if (allocate) { 5152a47c14e2a6f152496b43104bc785c488583fd59Chet Haase allocateTextureMemory(cacheTexture); 5162a47c14e2a6f152496b43104bc785c488583fd59Chet Haase } 5172a47c14e2a6f152496b43104bc785c488583fd59Chet Haase return cacheTexture; 5187de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase} 5197de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 5207de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasevoid FontRenderer::initTextTexture() { 5217de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.clear(); 5227de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 5237de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // Next, use other, separate caches for large glyphs. 5247de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint16_t maxWidth = 0; 5257de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (Caches::hasInstance()) { 5267de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase maxWidth = Caches::getInstance().maxTextureSize; 5277de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 5287de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (maxWidth > MAX_TEXT_CACHE_WIDTH || maxWidth == 0) { 5297de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase maxWidth = MAX_TEXT_CACHE_WIDTH; 5307de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 5317de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (mCacheTextureSmall != NULL) { 5327de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase delete mCacheTextureSmall; 5337de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase delete mCacheTexture128; 5347de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase delete mCacheTexture256; 5357de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase delete mCacheTexture512; 5367de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 5377de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTextureSmall = createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true); 5387de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTexture128 = createCacheTexture(maxWidth, 256, false); 5397de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTexture256 = createCacheTexture(maxWidth, 256, false); 5407de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTexture512 = createCacheTexture(maxWidth, 512, false); 5417de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCurrentCacheTexture = mCacheTextureSmall; 5427de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 5437de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mUploadTexture = false; 5447de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // Split up our default cache texture into lines of certain widths 545694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int nextLine = 0; 5467de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 18, nextLine, 0, mCacheTextureSmall)); 547694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 5487de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, 0, mCacheTextureSmall)); 549694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 5507de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, 0, mCacheTextureSmall)); 55165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk nextLine += mCacheLines.top()->mMaxHeight; 5527de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, 0, mCacheTextureSmall)); 553694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 5547de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, 0, mCacheTextureSmall)); 555694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 5567de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 42, nextLine, 0, mCacheTextureSmall)); 557694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 5587de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, mSmallCacheHeight - nextLine, 5597de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase nextLine, 0, mCacheTextureSmall)); 5607de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 5617de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // The first cache is split into 2 lines of height 128, the rest have just one cache line. 5627de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(maxWidth, 128, 0, 0, mCacheTexture128)); 5637de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(maxWidth, 128, 128, 0, mCacheTexture128)); 5647de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(maxWidth, 256, 0, 0, mCacheTexture256)); 5657de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(maxWidth, 512, 0, 0, mCacheTexture512)); 566694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 567694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 568694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Avoid having to reallocate memory and render quad by quad 569694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::initVertexArrayBuffers() { 570d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy uint32_t numIndices = mMaxNumberOfQuads * 6; 571d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy uint32_t indexBufferSizeBytes = numIndices * sizeof(uint16_t); 57251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes); 573694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 574694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Four verts, two triangles , six indices per quad 575694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mMaxNumberOfQuads; i++) { 576694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int i6 = i * 6; 577694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int i4 = i * 4; 578694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 579694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 0] = i4 + 0; 580694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 1] = i4 + 1; 581694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 2] = i4 + 2; 582694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 583694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 3] = i4 + 0; 584694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 4] = i4 + 2; 585694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 5] = i4 + 3; 586694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 587694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 588694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glGenBuffers(1, &mIndexBufferID); 58915bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy Caches::getInstance().bindIndicesBuffer(mIndexBufferID); 5905d794412e3e429e47404395badcd11b0b8639e8bRomain Guy glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_STATIC_DRAW); 591694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 592694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy free(indexBufferData); 593694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 594d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy uint32_t coordSize = 2; 595694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t uvSize = 2; 596694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t vertsPerQuad = 4; 5979b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize; 5989b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mTextMeshPtr = new float[vertexBufferSize]; 599694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 600694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 601694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// We don't want to allocate anything unless we actually draw text 602694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::checkInit() { 603694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mInitialized) { 604694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 605694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 606694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 607694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy initTextTexture(); 608694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy initVertexArrayBuffers(); 609694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 61065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk // We store a string with letters in a rough frequency of occurrence 61165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mLatinPrecache = String16("eisarntolcdugpmhbyfvkwzxjq "); 61265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mLatinPrecache += String16("EISARNTOLCDUGPMHBYFVKWZXJQ"); 61365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mLatinPrecache += String16(",.?!()-+@;:`'"); 61465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk mLatinPrecache += String16("0123456789"); 61565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 616694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mInitialized = true; 617694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 618694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 6199b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::checkTextureUpdate() { 6207de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (!mUploadTexture && mLastCacheTexture == mCurrentCacheTexture) { 6219b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk return; 6229b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 6239b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 6242d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy Caches& caches = Caches::getInstance(); 6252d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy GLuint lastTextureId = 0; 6269b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk // Iterate over all the cache lines and see which ones need to be updated 6279b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk for (uint32_t i = 0; i < mCacheLines.size(); i++) { 6289b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk CacheTextureLine* cl = mCacheLines[i]; 6297de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (cl->mDirty && cl->mCacheTexture->mTexture != NULL) { 6307de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase CacheTexture* cacheTexture = cl->mCacheTexture; 6319b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t xOffset = 0; 6329b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t yOffset = cl->mCurrentRow; 6337de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint32_t width = cl->mMaxWidth; 6349b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t height = cl->mMaxHeight; 6357de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase void* textureData = cacheTexture->mTexture + (yOffset * width); 6369b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 6372d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy if (cacheTexture->mTextureId != lastTextureId) { 6382d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy caches.activeTexture(0); 6392d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId); 6402d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy lastTextureId = cacheTexture->mTextureId; 6412d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy } 6429b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height, 6431e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy GL_ALPHA, GL_UNSIGNED_BYTE, textureData); 6449b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 6459b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk cl->mDirty = false; 6469b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 647694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 648694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 6497de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase glBindTexture(GL_TEXTURE_2D, mCurrentCacheTexture->mTextureId); 6502a47c14e2a6f152496b43104bc785c488583fd59Chet Haase if (mLinearFiltering != mCurrentCacheTexture->mLinearFiltering) { 6512a47c14e2a6f152496b43104bc785c488583fd59Chet Haase const GLenum filtering = mLinearFiltering ? GL_LINEAR : GL_NEAREST; 6522a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); 6532a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); 6542a47c14e2a6f152496b43104bc785c488583fd59Chet Haase mCurrentCacheTexture->mLinearFiltering = mLinearFiltering; 6552a47c14e2a6f152496b43104bc785c488583fd59Chet Haase } 6567de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mLastCacheTexture = mCurrentCacheTexture; 6577de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 6589b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mUploadTexture = false; 6599b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk} 6609b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 6619b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::issueDrawCommand() { 6629b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk checkTextureUpdate(); 6639b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 66415bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy Caches& caches = Caches::getInstance(); 6652d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy caches.bindIndicesBuffer(mIndexBufferID); 66615bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy if (!mDrawn) { 66715bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy float* buffer = mTextMeshPtr; 66815bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy int offset = 2; 66915bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy 67015bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy bool force = caches.unbindMeshBuffer(); 67115bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy caches.bindPositionVertexPointer(force, caches.currentProgram->position, buffer); 67215bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy caches.bindTexCoordsVertexPointer(force, caches.currentProgram->texCoords, 67315bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy buffer + offset); 67415bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy } 67515bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy 676694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL); 6775b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 6785b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mDrawn = true; 679694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 680694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 681d71dd367af604571c7d00ca473184a1b9240eca2Romain Guyvoid FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1, 682d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy float x2, float y2, float u2, float v2, 683d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy float x3, float y3, float u3, float v3, 6847de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase float x4, float y4, float u4, float v4, CacheTexture* texture) { 685d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy 686ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy if (mClip && 687ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) { 68809147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy return; 68909147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy } 6907de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (texture != mCurrentCacheTexture) { 6917de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (mCurrentQuadIndex != 0) { 6927de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // First, draw everything stored already which uses the previous texture 6937de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase issueDrawCommand(); 6947de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCurrentQuadIndex = 0; 6957de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 6967de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // Now use the new texture id 6977de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCurrentCacheTexture = texture; 6987de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 69909147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy 700694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy const uint32_t vertsPerQuad = 4; 701d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy const uint32_t floatsPerVert = 4; 70251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float* currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert; 703694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 704694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x1; 705694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y1; 706694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u1; 707694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v1; 708694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 709694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x2; 710694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y2; 711694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u2; 712694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v2; 713694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 714694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x3; 715694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y3; 716694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u3; 717694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v3; 718694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 719694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x4; 720694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y4; 721694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u4; 722694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v4; 723694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 724694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex++; 725694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 7265b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy if (mBounds) { 7275b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->left = fmin(mBounds->left, x1); 7285b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->top = fmin(mBounds->top, y3); 7295b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->right = fmax(mBounds->right, x3); 7305b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->bottom = fmax(mBounds->bottom, y1); 7315b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy } 7325b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 733694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex == mMaxNumberOfQuads) { 734694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 735694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 736694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 737694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 738694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 73965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukuint32_t FontRenderer::getRemainingCacheCapacity() { 74065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t remainingCapacity = 0; 74165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk float totalPixels = 0; 74265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 74365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol); 74465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk totalPixels += mCacheLines[i]->mMaxWidth; 74565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 74665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk remainingCapacity = (remainingCapacity * 100) / totalPixels; 74765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk return remainingCapacity; 74865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk} 74965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 75065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::precacheLatin(SkPaint* paint) { 75165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk // Remaining capacity is measured in % 75265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t remainingCapacity = getRemainingCacheCapacity(); 75365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t precacheIdx = 0; 754054dc1840941665e32036f9523df51720ad069c8Romain Guy while (remainingCapacity > 25 && precacheIdx < mLatinPrecache.size()) { 755726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy mCurrentFont->getCachedGlyph(paint, (int32_t) mLatinPrecache[precacheIdx]); 75665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk remainingCapacity = getRemainingCacheCapacity(); 75765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk precacheIdx ++; 75865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 75965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk} 76065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 76165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) { 76265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t currentNumFonts = mActiveFonts.size(); 763325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy int flags = 0; 764325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (paint->isFakeBoldText()) { 765325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy flags |= Font::kFakeBold; 766325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy } 7672577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy 7682577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy const float skewX = paint->getTextSkewX(); 7692577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy uint32_t italicStyle = *(uint32_t*) &skewX; 7708668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase const float scaleXFloat = paint->getTextScaleX(); 7718668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase uint32_t scaleX = *(uint32_t*) &scaleXFloat; 772bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy SkPaint::Style style = paint->getStyle(); 773bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy const float strokeWidthFloat = paint->getStrokeWidth(); 774bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy uint32_t strokeWidth = *(uint32_t*) &strokeWidthFloat; 775bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle, 776bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy scaleX, style, strokeWidth); 77765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 77865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk const float maxPrecacheFontSize = 40.0f; 77965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk bool isNewFont = currentNumFonts != mActiveFonts.size(); 78065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 7812bffd268f135df8308c9e67af110525a5c463424Romain Guy if (isNewFont && fontSize <= maxPrecacheFontSize) { 78265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk precacheLatin(paint); 78365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 784694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 7857975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy 786f18136cb3c881a9d16c1a4f0f341732c276936bfAlex SakhartchoukFontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text, 7871e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius) { 7881e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy checkInit(); 7891e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 7901e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (!mCurrentFont) { 7911e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy DropShadow image; 7921e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.width = 0; 7931e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.height = 0; 7941e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.image = NULL; 7951e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.penX = 0; 7961e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.penY = 0; 7971e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy return image; 7981e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } 799f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 8002d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy mDrawn = false; 801ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy mClip = NULL; 802ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy mBounds = NULL; 803ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 804f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk Rect bounds; 805726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds); 806ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 8071e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius; 8081e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius; 809f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight]; 810ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 8111e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy for (uint32_t i = 0; i < paddedWidth * paddedHeight; i++) { 812f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk dataBuffer[i] = 0; 813f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 8141e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 815f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int penX = radius - bounds.left; 816f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int penY = radius - bounds.bottom; 817f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 818726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY, 8191e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy dataBuffer, paddedWidth, paddedHeight); 820f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk blurImage(dataBuffer, paddedWidth, paddedHeight, radius); 821f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 822f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk DropShadow image; 823f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.width = paddedWidth; 824f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.height = paddedHeight; 825f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.image = dataBuffer; 826f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.penX = penX; 827f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.penY = penY; 8282d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy 829f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk return image; 830f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 831694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 8325b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guybool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text, 8335b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, Rect* bounds) { 834694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy checkInit(); 835694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 83609147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy if (!mCurrentFont) { 83709147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy LOGE("No font set"); 8385b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy return false; 839694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 840694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 8415b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mDrawn = false; 8425b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds = bounds; 84309147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy mClip = clip; 844ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 845726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y); 846ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 8475b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds = NULL; 848ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy mClip = NULL; 849694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 850694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex != 0) { 851694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 852694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 853694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 8545b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 8555b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy return mDrawn; 856694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 857694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 85889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::computeGaussianWeights(float* weights, int32_t radius) { 85989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Compute gaussian weights for the blur 86089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // e is the euler's number 86189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float e = 2.718281828459045f; 86289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float pi = 3.1415926535897932f; 86389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 ) 86489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // x is of the form [-radius .. 0 .. radius] 86589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // and sigma varies with radius. 86689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Based on some experimental radius values and sigma's 86789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // we approximately fit sigma = f(radius) as 868f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk // sigma = radius * 0.3 + 0.6 86989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // The larger the radius gets, the more our gaussian blur 87089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // will resemble a box blur since with large sigma 87189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // the gaussian curve begins to lose its shape 872325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy float sigma = 0.3f * (float) radius + 0.6f; 87389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 87489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Now compute the coefficints 87589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // We will store some redundant values to save some math during 87689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // the blur calculations 87789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // precompute some values 87889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma); 87989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float coeff2 = - 1.0f / (2.0f * sigma * sigma); 88089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 88189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float normalizeFactor = 0.0f; 882325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 8837975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy float floatR = (float) r; 88489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2); 88589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk normalizeFactor += weights[r + radius]; 88689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 88789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 88889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk //Now we need to normalize the weights because all our coefficients need to add up to one 88989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk normalizeFactor = 1.0f / normalizeFactor; 890325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 89189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk weights[r + radius] *= normalizeFactor; 89289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 89389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 89489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 89589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::horizontalBlur(float* weights, int32_t radius, 8961e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) { 89789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float blurredPixel = 0.0f; 89889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float currentPixel = 0.0f; 89989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 900325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t y = 0; y < height; y ++) { 90189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 90289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* input = source + y * width; 90389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* output = dest + y * width; 90489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 905325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t x = 0; x < width; x ++) { 90689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel = 0.0f; 90789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const float* gPtr = weights; 90889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Optimization for non-border pixels 909325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (x > radius && x < (width - radius)) { 91089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + (x - radius); 911325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int r = -radius; r <= radius; r ++) { 9127975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy currentPixel = (float) (*i); 91389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 91489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 91589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk i++; 91689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 91789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } else { 918325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 91989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Stepping left and right away from the pixel 92089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int validW = x + r; 921325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validW < 0) { 92289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validW = 0; 92389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 924325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validW > width - 1) { 92589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validW = width - 1; 92689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 92789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 928325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy currentPixel = (float) input[validW]; 92989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 93089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 93189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 93289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 93389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk *output = (uint8_t)blurredPixel; 93489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk output ++; 93589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 93689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 93789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 93889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 93989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::verticalBlur(float* weights, int32_t radius, 9401e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) { 94189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float blurredPixel = 0.0f; 94289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float currentPixel = 0.0f; 94389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 944325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t y = 0; y < height; y ++) { 94589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 94689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* output = dest + y * width; 94789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 948325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t x = 0; x < width; x ++) { 94989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel = 0.0f; 95089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const float* gPtr = weights; 95189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* input = source + x; 95289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Optimization for non-border pixels 953325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (y > radius && y < (height - radius)) { 95489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + ((y - radius) * width); 955325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 95689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk currentPixel = (float)(*i); 95789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 95889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 95989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk i += width; 96089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 96189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } else { 962325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 96389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int validH = y + r; 96489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Clamp to zero and width 965325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validH < 0) { 96689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validH = 0; 96789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 968325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validH > height - 1) { 96989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validH = height - 1; 97089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 97189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 97289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + validH * width; 973325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy currentPixel = (float) (*i); 97489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 97589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 97689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 97789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 978325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy *output = (uint8_t) blurredPixel; 97989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk output ++; 98089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 98189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 98289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 98389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 98489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 98589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::blurImage(uint8_t *image, int32_t width, int32_t height, int32_t radius) { 98689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float *gaussian = new float[2 * radius + 1]; 98789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk computeGaussianWeights(gaussian, radius); 988d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy 98989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* scratch = new uint8_t[width * height]; 990d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy 99189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk horizontalBlur(gaussian, radius, image, scratch, width, height); 99289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk verticalBlur(gaussian, radius, scratch, image, width, height); 993d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy 99489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk delete[] gaussian; 99589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk delete[] scratch; 99689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 99789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 998694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace uirenderer 999694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace android 1000