FontRenderer.cpp revision cb4d6009576cf08195dc23f341a3f4939c0878bb
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" 289f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#include "Rect.h" 2951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 30694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guynamespace android { 31694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guynamespace uirenderer { 32694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 33694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 34694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// FontRenderer 35694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 36694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 37514fb18827186591d66973c2362c859b64b63556Romain Guystatic bool sLogFontRendererCreate = true; 38514fb18827186591d66973c2362c859b64b63556Romain Guy 39694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::FontRenderer() { 40c9855a53edfac818dc68714557185977556f849dRomain Guy if (sLogFontRendererCreate) { 41c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD("Creating FontRenderer"); 42c9855a53edfac818dc68714557185977556f849dRomain Guy } 4351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 44b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy mGammaTable = NULL; 45694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mInitialized = false; 46694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mMaxNumberOfQuads = 1024; 47694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 48694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 499b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy mTextMesh = NULL; 507de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCurrentCacheTexture = NULL; 517de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mLastCacheTexture = NULL; 529cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy 532a47c14e2a6f152496b43104bc785c488583fd59Chet Haase mLinearFiltering = false; 542a47c14e2a6f152496b43104bc785c488583fd59Chet Haase 55694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mIndexBufferID = 0; 56694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 57eb32a499194119b3783b86c925172df02e5d2685Chet Haase mSmallCacheWidth = DEFAULT_TEXT_SMALL_CACHE_WIDTH; 58eb32a499194119b3783b86c925172df02e5d2685Chet Haase mSmallCacheHeight = DEFAULT_TEXT_SMALL_CACHE_HEIGHT; 59eb32a499194119b3783b86c925172df02e5d2685Chet Haase mLargeCacheWidth = DEFAULT_TEXT_LARGE_CACHE_WIDTH; 60eb32a499194119b3783b86c925172df02e5d2685Chet Haase mLargeCacheHeight = DEFAULT_TEXT_LARGE_CACHE_HEIGHT; 6151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 6251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy char property[PROPERTY_VALUE_MAX]; 63eb32a499194119b3783b86c925172df02e5d2685Chet Haase if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, NULL) > 0) { 647de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mSmallCacheWidth = atoi(property); 6551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } 669f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 67eb32a499194119b3783b86c925172df02e5d2685Chet Haase if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, NULL) > 0) { 687de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mSmallCacheHeight = atoi(property); 69eb32a499194119b3783b86c925172df02e5d2685Chet Haase } 709f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 71eb32a499194119b3783b86c925172df02e5d2685Chet Haase if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, NULL) > 0) { 72eb32a499194119b3783b86c925172df02e5d2685Chet Haase mLargeCacheWidth = atoi(property); 73eb32a499194119b3783b86c925172df02e5d2685Chet Haase } 749f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 75eb32a499194119b3783b86c925172df02e5d2685Chet Haase if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, NULL) > 0) { 76eb32a499194119b3783b86c925172df02e5d2685Chet Haase mLargeCacheHeight = atoi(property); 77eb32a499194119b3783b86c925172df02e5d2685Chet Haase } 789f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 799f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize; 809f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy mSmallCacheWidth = mSmallCacheWidth > maxTextureSize ? maxTextureSize : mSmallCacheWidth; 819f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy mSmallCacheHeight = mSmallCacheHeight > maxTextureSize ? maxTextureSize : mSmallCacheHeight; 829f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy mLargeCacheWidth = mLargeCacheWidth > maxTextureSize ? maxTextureSize : mLargeCacheWidth; 839f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy mLargeCacheHeight = mLargeCacheHeight > maxTextureSize ? maxTextureSize : mLargeCacheHeight; 849f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy 85eb32a499194119b3783b86c925172df02e5d2685Chet Haase if (sLogFontRendererCreate) { 86eb32a499194119b3783b86c925172df02e5d2685Chet Haase INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i", 87eb32a499194119b3783b86c925172df02e5d2685Chet Haase mSmallCacheWidth, mSmallCacheHeight, 88eb32a499194119b3783b86c925172df02e5d2685Chet Haase mLargeCacheWidth, mLargeCacheHeight >> 1, 89eb32a499194119b3783b86c925172df02e5d2685Chet Haase mLargeCacheWidth, mLargeCacheHeight >> 1, 90eb32a499194119b3783b86c925172df02e5d2685Chet Haase mLargeCacheWidth, mLargeCacheHeight); 9151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } 92514fb18827186591d66973c2362c859b64b63556Romain Guy 93514fb18827186591d66973c2362c859b64b63556Romain Guy sLogFontRendererCreate = false; 94694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 95694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 96694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::~FontRenderer() { 97378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase for (uint32_t i = 0; i < mCacheTextures.size(); i++) { 98378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase delete mCacheTextures[i]; 99694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 100378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase mCacheTextures.clear(); 101694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1029cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy if (mInitialized) { 103a9dd820184ee4d083bd9b2af735dcf50b78fc6cdRomain Guy // Unbinding the buffer shouldn't be necessary but it crashes with some drivers 104a9dd820184ee4d083bd9b2af735dcf50b78fc6cdRomain Guy Caches::getInstance().unbindIndicesBuffer(); 105b0317984d34da99b614597ad0a8b39268eacb783Romain Guy glDeleteBuffers(1, &mIndexBufferID); 106b0317984d34da99b614597ad0a8b39268eacb783Romain Guy 1079b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy delete[] mTextMesh; 1089b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 109694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 110694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy Vector<Font*> fontsToDereference = mActiveFonts; 111694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < fontsToDereference.size(); i++) { 112694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy delete fontsToDereference[i]; 113694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 114694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 115694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 116694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::flushAllAndInvalidate() { 117694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex != 0) { 118694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 119694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 120694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 1219d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 122694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mActiveFonts.size(); i++) { 123694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mActiveFonts[i]->invalidateTextureCache(); 124694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 1259d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 126378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase for (uint32_t i = 0; i < mCacheTextures.size(); i++) { 127378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase mCacheTextures[i]->init(); 128e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 129e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase 1308087246d9964b11de8ce116bc63b156faa4197e0Romain Guy#if DEBUG_FONT_RENDERER 131378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase uint16_t totalGlyphs = 0; 132378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase for (uint32_t i = 0; i < mCacheTextures.size(); i++) { 1338087246d9964b11de8ce116bc63b156faa4197e0Romain Guy totalGlyphs += mCacheTextures[i]->getGlyphCount(); 134378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase // Erase caches, just as a debugging facility 1358087246d9964b11de8ce116bc63b156faa4197e0Romain Guy if (mCacheTextures[i]->getTexture()) { 1368087246d9964b11de8ce116bc63b156faa4197e0Romain Guy memset(mCacheTextures[i]->getTexture(), 0, 1378087246d9964b11de8ce116bc63b156faa4197e0Romain Guy mCacheTextures[i]->getWidth() * mCacheTextures[i]->getHeight()); 138378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase } 139e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 140e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase ALOGD("Flushing caches: glyphs cached = %d", totalGlyphs); 141e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif 142694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 143694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1449a8245629d69d81e0b62e52970feaf9c02580e75Chet Haasevoid FontRenderer::flushLargeCaches() { 145378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase // Start from 1; don't deallocate smallest/default texture 146378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase for (uint32_t i = 1; i < mCacheTextures.size(); i++) { 147378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase CacheTexture* cacheTexture = mCacheTextures[i]; 1488087246d9964b11de8ce116bc63b156faa4197e0Romain Guy if (cacheTexture->getTexture()) { 149378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase cacheTexture->init(); 150378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase for (uint32_t j = 0; j < mActiveFonts.size(); j++) { 151378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase mActiveFonts[j]->invalidateTextureCache(cacheTexture); 1529a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase } 1538087246d9964b11de8ce116bc63b156faa4197e0Romain Guy cacheTexture->releaseTexture(); 1549a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase } 1559a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase } 1569a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase} 1579a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase 158378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet HaaseCacheTexture* FontRenderer::cacheBitmapInTexture(const SkGlyph& glyph, 159378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase uint32_t* startX, uint32_t* startY) { 160378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase for (uint32_t i = 0; i < mCacheTextures.size(); i++) { 161378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase if (mCacheTextures[i]->fitBitmap(glyph, startX, startY)) { 162378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase return mCacheTextures[i]; 163378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase } 164378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase } 165378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase // Could not fit glyph into current cache textures 166378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase return NULL; 167378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase} 168378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase 1697de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasevoid FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph, 170f942cf10e04567f6b9456f6258e29c803b8bfb41Chet Haase uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) { 1712efd5c5886d9acf747bc92f888d731ed558aabccChet Haase checkInit(); 1727de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase cachedGlyph->mIsValid = false; 173694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If the glyph is too tall, don't cache it 174378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > 1758087246d9964b11de8ce116bc63b156faa4197e0Romain Guy mCacheTextures[mCacheTextures.size() - 1]->getHeight()) { 1762efd5c5886d9acf747bc92f888d731ed558aabccChet Haase ALOGE("Font size too large to fit in cache. width, height = %i, %i", 1772efd5c5886d9acf747bc92f888d731ed558aabccChet Haase (int) glyph.fWidth, (int) glyph.fHeight); 1787de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase return; 179694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 180694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 181694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Now copy the bitmap into the cache texture 182694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startX = 0; 183694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startY = 0; 184694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 185378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase CacheTexture* cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY); 186694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 187378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase if (!cacheTexture) { 188f942cf10e04567f6b9456f6258e29c803b8bfb41Chet Haase if (!precaching) { 189f942cf10e04567f6b9456f6258e29c803b8bfb41Chet Haase // If the new glyph didn't fit and we are not just trying to precache it, 190f942cf10e04567f6b9456f6258e29c803b8bfb41Chet Haase // clear out the cache and try again 191f942cf10e04567f6b9456f6258e29c803b8bfb41Chet Haase flushAllAndInvalidate(); 192f942cf10e04567f6b9456f6258e29c803b8bfb41Chet Haase cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY); 193f942cf10e04567f6b9456f6258e29c803b8bfb41Chet Haase } 194694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 195378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase if (!cacheTexture) { 196f942cf10e04567f6b9456f6258e29c803b8bfb41Chet Haase // either the glyph didn't fit or we're precaching and will cache it when we draw 1977de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase return; 198694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 199694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 200694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 201378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase cachedGlyph->mCacheTexture = cacheTexture; 2027de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 203694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *retOriginX = startX; 204694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *retOriginY = startY; 205694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 206694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endX = startX + glyph.fWidth; 207694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endY = startY + glyph.fHeight; 208694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 2098087246d9964b11de8ce116bc63b156faa4197e0Romain Guy uint32_t cacheWidth = cacheTexture->getWidth(); 210694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 2118087246d9964b11de8ce116bc63b156faa4197e0Romain Guy if (!cacheTexture->getTexture()) { 2128087246d9964b11de8ce116bc63b156faa4197e0Romain Guy Caches::getInstance().activeTexture(0); 2137de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // Large-glyph texture memory is allocated only as needed 2148087246d9964b11de8ce116bc63b156faa4197e0Romain Guy cacheTexture->allocateTexture(); 2157de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 2169d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 2178087246d9964b11de8ce116bc63b156faa4197e0Romain Guy uint8_t* cacheBuffer = cacheTexture->getTexture(); 21889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage; 219694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy unsigned int stride = glyph.rowBytes(); 220694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 221694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; 22233fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy 22333fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy for (cacheX = startX - TEXTURE_BORDER_SIZE; cacheX < endX + TEXTURE_BORDER_SIZE; cacheX++) { 22433fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy cacheBuffer[(startY - TEXTURE_BORDER_SIZE) * cacheWidth + cacheX] = 0; 22533fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy cacheBuffer[(endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + cacheX] = 0; 22633fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy } 22733fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy 22833fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy for (cacheY = startY - TEXTURE_BORDER_SIZE + 1; 22933fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy cacheY < endY + TEXTURE_BORDER_SIZE - 1; cacheY++) { 23033fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy cacheBuffer[cacheY * cacheWidth + startX - TEXTURE_BORDER_SIZE] = 0; 23133fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy cacheBuffer[cacheY * cacheWidth + endX + TEXTURE_BORDER_SIZE - 1] = 0; 23233fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy } 23333fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy 234b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy if (mGammaTable) { 235b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) { 236b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) { 237b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy uint8_t tempCol = bitmapBuffer[bY * stride + bX]; 238b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol]; 239b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy } 240b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy } 241b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy } else { 242b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) { 243b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) { 244b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy uint8_t tempCol = bitmapBuffer[bY * stride + bX]; 245b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy cacheBuffer[cacheY * cacheWidth + cacheX] = tempCol; 246b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy } 247694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 248694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 2499777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 2507de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase cachedGlyph->mIsValid = true; 251694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 252694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 2537de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet HaaseCacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) { 2540aa87bbfc41e8b5f52de701ac17b4e66a7a7b609Romain Guy CacheTexture* cacheTexture = new CacheTexture(width, height); 2559d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 2562a47c14e2a6f152496b43104bc785c488583fd59Chet Haase if (allocate) { 2578087246d9964b11de8ce116bc63b156faa4197e0Romain Guy Caches::getInstance().activeTexture(0); 2588087246d9964b11de8ce116bc63b156faa4197e0Romain Guy cacheTexture->allocateTexture(); 2592a47c14e2a6f152496b43104bc785c488583fd59Chet Haase } 2609d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 2612a47c14e2a6f152496b43104bc785c488583fd59Chet Haase return cacheTexture; 2627de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase} 2637de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 2647de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasevoid FontRenderer::initTextTexture() { 265378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase for (uint32_t i = 0; i < mCacheTextures.size(); i++) { 266378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase delete mCacheTextures[i]; 2679d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy } 268378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase mCacheTextures.clear(); 2699d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 2707de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mUploadTexture = false; 271378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase mCacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true)); 272eb32a499194119b3783b86c925172df02e5d2685Chet Haase mCacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, false)); 273eb32a499194119b3783b86c925172df02e5d2685Chet Haase mCacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, false)); 274eb32a499194119b3783b86c925172df02e5d2685Chet Haase mCacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight, false)); 275378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase mCurrentCacheTexture = mCacheTextures[0]; 276694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 277694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 278694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Avoid having to reallocate memory and render quad by quad 279694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::initVertexArrayBuffers() { 280d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy uint32_t numIndices = mMaxNumberOfQuads * 6; 281d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy uint32_t indexBufferSizeBytes = numIndices * sizeof(uint16_t); 28251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes); 283694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 284694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Four verts, two triangles , six indices per quad 285694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mMaxNumberOfQuads; i++) { 286694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int i6 = i * 6; 287694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int i4 = i * 4; 288694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 289694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 0] = i4 + 0; 290694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 1] = i4 + 1; 291694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 2] = i4 + 2; 292694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 293694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 3] = i4 + 0; 294694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 4] = i4 + 2; 295694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 5] = i4 + 3; 296694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 297694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 298694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glGenBuffers(1, &mIndexBufferID); 29915bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy Caches::getInstance().bindIndicesBuffer(mIndexBufferID); 3005d794412e3e429e47404395badcd11b0b8639e8bRomain Guy glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_STATIC_DRAW); 301694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 302694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy free(indexBufferData); 303694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 304d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy uint32_t coordSize = 2; 305694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t uvSize = 2; 306694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t vertsPerQuad = 4; 3079b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize; 3089b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy mTextMesh = new float[vertexBufferSize]; 309694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 310694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 311694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// We don't want to allocate anything unless we actually draw text 312694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::checkInit() { 313694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mInitialized) { 314694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 315694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 316694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 317694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy initTextTexture(); 318694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy initVertexArrayBuffers(); 319694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 320694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mInitialized = true; 321694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 322694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 3239b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::checkTextureUpdate() { 3247de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (!mUploadTexture && mLastCacheTexture == mCurrentCacheTexture) { 3259b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk return; 3269b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 3279b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 3282d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy Caches& caches = Caches::getInstance(); 3292d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy GLuint lastTextureId = 0; 330378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase // Iterate over all the cache textures and see which ones need to be updated 331378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase for (uint32_t i = 0; i < mCacheTextures.size(); i++) { 332378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase CacheTexture* cacheTexture = mCacheTextures[i]; 3338087246d9964b11de8ce116bc63b156faa4197e0Romain Guy if (cacheTexture->isDirty() && cacheTexture->getTexture()) { 334b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase // Can't copy inner rect; glTexSubimage expects pointer to deal with entire buffer 335b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase // of data. So expand the dirty rect to the encompassing horizontal stripe. 336b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase const Rect* dirtyRect = cacheTexture->getDirtyRect(); 337b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase uint32_t x = 0; 338b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase uint32_t y = dirtyRect->top; 3398087246d9964b11de8ce116bc63b156faa4197e0Romain Guy uint32_t width = cacheTexture->getWidth(); 340b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase uint32_t height = dirtyRect->getHeight(); 341b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase void* textureData = cacheTexture->getTexture() + y * width; 3429b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 3438087246d9964b11de8ce116bc63b156faa4197e0Romain Guy if (cacheTexture->getTextureId() != lastTextureId) { 3448087246d9964b11de8ce116bc63b156faa4197e0Romain Guy lastTextureId = cacheTexture->getTextureId(); 3452d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy caches.activeTexture(0); 3468087246d9964b11de8ce116bc63b156faa4197e0Romain Guy glBindTexture(GL_TEXTURE_2D, lastTextureId); 3472d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy } 348e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#if DEBUG_FONT_RENDERER 349b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase ALOGD("glTexSubimage for cacheTexture %d: x, y, width height = %d, %d, %d, %d", 350b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase i, x, y, width, height); 351e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif 352b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, 3531e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy GL_ALPHA, GL_UNSIGNED_BYTE, textureData); 3548087246d9964b11de8ce116bc63b156faa4197e0Romain Guy cacheTexture->setDirty(false); 3559b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 356694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 357694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 35816c88085255c71a1a8fc034129aa2dcc61e1ddd0Romain Guy caches.activeTexture(0); 3598087246d9964b11de8ce116bc63b156faa4197e0Romain Guy glBindTexture(GL_TEXTURE_2D, mCurrentCacheTexture->getTextureId()); 3608087246d9964b11de8ce116bc63b156faa4197e0Romain Guy 3618087246d9964b11de8ce116bc63b156faa4197e0Romain Guy mCurrentCacheTexture->setLinearFiltering(mLinearFiltering, false); 3627de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mLastCacheTexture = mCurrentCacheTexture; 3637de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 3649b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mUploadTexture = false; 3659b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk} 3669b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 3679b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::issueDrawCommand() { 3689b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk checkTextureUpdate(); 3699b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 37015bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy Caches& caches = Caches::getInstance(); 3712d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy caches.bindIndicesBuffer(mIndexBufferID); 37215bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy if (!mDrawn) { 3739b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy float* buffer = mTextMesh; 37415bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy int offset = 2; 37515bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy 37615bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy bool force = caches.unbindMeshBuffer(); 377cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik caches.bindPositionVertexPointer(force, buffer); 378cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik caches.bindTexCoordsVertexPointer(force, buffer + offset); 37915bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy } 38015bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy 381694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL); 3825b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 3835b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mDrawn = true; 384694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 385694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 3869777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1, 3879777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3, 3887de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase float x4, float y4, float u4, float v4, CacheTexture* texture) { 3897de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (texture != mCurrentCacheTexture) { 3907de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (mCurrentQuadIndex != 0) { 3917de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // First, draw everything stored already which uses the previous texture 3927de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase issueDrawCommand(); 3937de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCurrentQuadIndex = 0; 3947de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 3957de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // Now use the new texture id 3967de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCurrentCacheTexture = texture; 3977de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 39809147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy 399694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy const uint32_t vertsPerQuad = 4; 400d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy const uint32_t floatsPerVert = 4; 4019b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy float* currentPos = mTextMesh + mCurrentQuadIndex * vertsPerQuad * floatsPerVert; 402694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 403694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x1; 404694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y1; 405694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u1; 406694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v1; 407694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 408694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x2; 409694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y2; 410694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u2; 411694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v2; 412694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 413694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x3; 414694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y3; 415694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u3; 416694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v3; 417694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 418694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x4; 419694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y4; 420694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u4; 421694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v4; 422694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 423694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex++; 4249777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy} 4259777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 4269777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1, 4279777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3, 4289777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float x4, float y4, float u4, float v4, CacheTexture* texture) { 4299777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 4309777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (mClip && 4319777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) { 4329777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy return; 4339777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 4349777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 4359777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture); 436694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 4375b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy if (mBounds) { 4385b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->left = fmin(mBounds->left, x1); 4395b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->top = fmin(mBounds->top, y3); 4405b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->right = fmax(mBounds->right, x3); 4415b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->bottom = fmax(mBounds->bottom, y1); 4425b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy } 4435b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 444694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex == mMaxNumberOfQuads) { 445694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 446694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 447694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 448694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 449694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 4509777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1, 4519777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3, 4529777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float x4, float y4, float u4, float v4, CacheTexture* texture) { 4539777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 4549777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture); 4559777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 4569777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (mBounds) { 4579777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mBounds->left = fmin(mBounds->left, fmin(x1, fmin(x2, fmin(x3, x4)))); 4589777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mBounds->top = fmin(mBounds->top, fmin(y1, fmin(y2, fmin(y3, y4)))); 4599777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mBounds->right = fmax(mBounds->right, fmax(x1, fmax(x2, fmax(x3, x4)))); 4609777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mBounds->bottom = fmax(mBounds->bottom, fmax(y1, fmax(y2, fmax(y3, y4)))); 4619777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 4629777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 4639777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (mCurrentQuadIndex == mMaxNumberOfQuads) { 4649777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy issueDrawCommand(); 4659777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mCurrentQuadIndex = 0; 4669777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 4679777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy} 4689777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 46965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) { 470325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy int flags = 0; 471325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (paint->isFakeBoldText()) { 472325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy flags |= Font::kFakeBold; 473325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy } 4742577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy 4752577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy const float skewX = paint->getTextSkewX(); 4762577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy uint32_t italicStyle = *(uint32_t*) &skewX; 4778668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase const float scaleXFloat = paint->getTextScaleX(); 4788668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase uint32_t scaleX = *(uint32_t*) &scaleXFloat; 479bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy SkPaint::Style style = paint->getStyle(); 480bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy const float strokeWidthFloat = paint->getStrokeWidth(); 481bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy uint32_t strokeWidth = *(uint32_t*) &strokeWidthFloat; 482bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle, 483bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy scaleX, style, strokeWidth); 48465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 485694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 4867975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy 487f18136cb3c881a9d16c1a4f0f341732c276936bfAlex SakhartchoukFontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text, 488416a847633680d94efb926837efdc18726d54918Raph Levien uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius, const float* positions) { 4891e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy checkInit(); 4901e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 4911e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (!mCurrentFont) { 4921e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy DropShadow image; 4931e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.width = 0; 4941e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.height = 0; 4951e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.image = NULL; 4961e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.penX = 0; 4971e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.penY = 0; 4981e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy return image; 4991e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } 500f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 5012d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy mDrawn = false; 502ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy mClip = NULL; 503ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy mBounds = NULL; 504ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 505f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk Rect bounds; 506416a847633680d94efb926837efdc18726d54918Raph Levien mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions); 507ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 5081e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius; 5091e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius; 510f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight]; 511ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 5121e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy for (uint32_t i = 0; i < paddedWidth * paddedHeight; i++) { 513f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk dataBuffer[i] = 0; 514f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 5151e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 516f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int penX = radius - bounds.left; 517f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int penY = radius - bounds.bottom; 518f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 519726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY, 520416a847633680d94efb926837efdc18726d54918Raph Levien Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions); 521f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk blurImage(dataBuffer, paddedWidth, paddedHeight, radius); 522f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 523f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk DropShadow image; 524f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.width = paddedWidth; 525f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.height = paddedHeight; 526f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.image = dataBuffer; 527f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.penX = penX; 528f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.penY = penY; 5292d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy 530f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk return image; 531f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 532694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 533671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid FontRenderer::initRender(const Rect* clip, Rect* bounds) { 534694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy checkInit(); 535694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 5365b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mDrawn = false; 5375b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds = bounds; 53809147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy mClip = clip; 539671d6cf460531825a321edb200523d0faa7792c9Romain Guy} 540ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 541671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid FontRenderer::finishRender() { 5425b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds = NULL; 543ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy mClip = NULL; 544694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 545694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex != 0) { 546694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 547694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 548694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 549671d6cf460531825a321edb200523d0faa7792c9Romain Guy} 550671d6cf460531825a321edb200523d0faa7792c9Romain Guy 551e816baea651476aca4407200d4a5e629b9ab8dfaChet Haasevoid FontRenderer::precache(SkPaint* paint, const char* text, int numGlyphs) { 552e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase int flags = 0; 553e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (paint->isFakeBoldText()) { 554e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase flags |= Font::kFakeBold; 555e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 556e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase const float skewX = paint->getTextSkewX(); 557e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase uint32_t italicStyle = *(uint32_t*) &skewX; 558e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase const float scaleXFloat = paint->getTextScaleX(); 559e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase uint32_t scaleX = *(uint32_t*) &scaleXFloat; 560e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase SkPaint::Style style = paint->getStyle(); 561e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase const float strokeWidthFloat = paint->getStrokeWidth(); 562e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase uint32_t strokeWidth = *(uint32_t*) &strokeWidthFloat; 563e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase float fontSize = paint->getTextSize(); 564e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase Font* font = Font::create(this, SkTypeface::UniqueID(paint->getTypeface()), 565e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase fontSize, flags, italicStyle, scaleX, style, strokeWidth); 566e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase 567e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase font->precache(paint, text, numGlyphs); 568e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase} 569e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase 570671d6cf460531825a321edb200523d0faa7792c9Romain Guybool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text, 571671d6cf460531825a321edb200523d0faa7792c9Romain Guy uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, Rect* bounds) { 572671d6cf460531825a321edb200523d0faa7792c9Romain Guy if (!mCurrentFont) { 573671d6cf460531825a321edb200523d0faa7792c9Romain Guy ALOGE("No font set"); 574671d6cf460531825a321edb200523d0faa7792c9Romain Guy return false; 575671d6cf460531825a321edb200523d0faa7792c9Romain Guy } 576671d6cf460531825a321edb200523d0faa7792c9Romain Guy 577671d6cf460531825a321edb200523d0faa7792c9Romain Guy initRender(clip, bounds); 578671d6cf460531825a321edb200523d0faa7792c9Romain Guy mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y); 579671d6cf460531825a321edb200523d0faa7792c9Romain Guy finishRender(); 580671d6cf460531825a321edb200523d0faa7792c9Romain Guy 581671d6cf460531825a321edb200523d0faa7792c9Romain Guy return mDrawn; 582671d6cf460531825a321edb200523d0faa7792c9Romain Guy} 583671d6cf460531825a321edb200523d0faa7792c9Romain Guy 584671d6cf460531825a321edb200523d0faa7792c9Romain Guybool FontRenderer::renderPosText(SkPaint* paint, const Rect* clip, const char *text, 585671d6cf460531825a321edb200523d0faa7792c9Romain Guy uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, 586671d6cf460531825a321edb200523d0faa7792c9Romain Guy const float* positions, Rect* bounds) { 587671d6cf460531825a321edb200523d0faa7792c9Romain Guy if (!mCurrentFont) { 588671d6cf460531825a321edb200523d0faa7792c9Romain Guy ALOGE("No font set"); 589671d6cf460531825a321edb200523d0faa7792c9Romain Guy return false; 590671d6cf460531825a321edb200523d0faa7792c9Romain Guy } 591671d6cf460531825a321edb200523d0faa7792c9Romain Guy 592671d6cf460531825a321edb200523d0faa7792c9Romain Guy initRender(clip, bounds); 593671d6cf460531825a321edb200523d0faa7792c9Romain Guy mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions); 594671d6cf460531825a321edb200523d0faa7792c9Romain Guy finishRender(); 5955b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 5965b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy return mDrawn; 5979777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy} 5989777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 5999777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guybool FontRenderer::renderTextOnPath(SkPaint* paint, const Rect* clip, const char *text, 6009777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy uint32_t startIndex, uint32_t len, int numGlyphs, SkPath* path, 6019777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float hOffset, float vOffset, Rect* bounds) { 6029777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (!mCurrentFont) { 6039777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy ALOGE("No font set"); 6049777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy return false; 6059777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 6069777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 6079777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy initRender(clip, bounds); 6089777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset); 6099777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy finishRender(); 6109777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 6119777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy return mDrawn; 612694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 613694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 6149b1204baf4740b4d443e72157dea98571cf84e1fRomain Guyvoid FontRenderer::removeFont(const Font* font) { 6159b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy for (uint32_t ct = 0; ct < mActiveFonts.size(); ct++) { 6169b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy if (mActiveFonts[ct] == font) { 6179b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy mActiveFonts.removeAt(ct); 6189b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy break; 6199b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy } 6209b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy } 6219b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy 6229b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy if (mCurrentFont == font) { 6239b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy mCurrentFont = NULL; 6249b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy } 6259b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy} 6269b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy 62789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::computeGaussianWeights(float* weights, int32_t radius) { 62889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Compute gaussian weights for the blur 62989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // e is the euler's number 63089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float e = 2.718281828459045f; 63189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float pi = 3.1415926535897932f; 63289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 ) 63389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // x is of the form [-radius .. 0 .. radius] 63489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // and sigma varies with radius. 63589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Based on some experimental radius values and sigma's 63689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // we approximately fit sigma = f(radius) as 637f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk // sigma = radius * 0.3 + 0.6 63889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // The larger the radius gets, the more our gaussian blur 63989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // will resemble a box blur since with large sigma 64089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // the gaussian curve begins to lose its shape 641325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy float sigma = 0.3f * (float) radius + 0.6f; 64289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 64389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Now compute the coefficints 64489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // We will store some redundant values to save some math during 64589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // the blur calculations 64689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // precompute some values 64789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma); 64889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float coeff2 = - 1.0f / (2.0f * sigma * sigma); 64989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 65089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float normalizeFactor = 0.0f; 651325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 6527975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy float floatR = (float) r; 65389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2); 65489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk normalizeFactor += weights[r + radius]; 65589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 65689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 65789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk //Now we need to normalize the weights because all our coefficients need to add up to one 65889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk normalizeFactor = 1.0f / normalizeFactor; 659325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 66089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk weights[r + radius] *= normalizeFactor; 66189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 66289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 66389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 66489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::horizontalBlur(float* weights, int32_t radius, 6651e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) { 66689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float blurredPixel = 0.0f; 66789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float currentPixel = 0.0f; 66889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 669325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t y = 0; y < height; y ++) { 67089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 67189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* input = source + y * width; 67289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* output = dest + y * width; 67389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 674325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t x = 0; x < width; x ++) { 67589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel = 0.0f; 67689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const float* gPtr = weights; 67789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Optimization for non-border pixels 678325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (x > radius && x < (width - radius)) { 67989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + (x - radius); 680325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int r = -radius; r <= radius; r ++) { 6817975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy currentPixel = (float) (*i); 68289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 68389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 68489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk i++; 68589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 68689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } else { 687325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 68889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Stepping left and right away from the pixel 68989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int validW = x + r; 690325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validW < 0) { 69189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validW = 0; 69289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 693325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validW > width - 1) { 69489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validW = width - 1; 69589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 69689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 697325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy currentPixel = (float) input[validW]; 69889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 69989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 70089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 70189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 70289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk *output = (uint8_t)blurredPixel; 70389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk output ++; 70489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 70589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 70689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 70789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 70889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::verticalBlur(float* weights, int32_t radius, 7091e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) { 71089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float blurredPixel = 0.0f; 71189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float currentPixel = 0.0f; 71289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 713325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t y = 0; y < height; y ++) { 71489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* output = dest + y * width; 71589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 716325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t x = 0; x < width; x ++) { 71789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel = 0.0f; 71889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const float* gPtr = weights; 71989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* input = source + x; 72089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Optimization for non-border pixels 721325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (y > radius && y < (height - radius)) { 72289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + ((y - radius) * width); 723325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 72489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk currentPixel = (float)(*i); 72589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 72689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 72789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk i += width; 72889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 72989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } else { 730325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 73189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int validH = y + r; 73289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Clamp to zero and width 733325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validH < 0) { 73489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validH = 0; 73589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 736325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validH > height - 1) { 73789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validH = height - 1; 73889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 73989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 74089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + validH * width; 741325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy currentPixel = (float) (*i); 74289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 74389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 74489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 74589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 746325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy *output = (uint8_t) blurredPixel; 7479b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy output++; 74889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 74989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 75089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 75189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 75289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 75389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::blurImage(uint8_t *image, int32_t width, int32_t height, int32_t radius) { 75489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float *gaussian = new float[2 * radius + 1]; 75589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk computeGaussianWeights(gaussian, radius); 756d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy 75789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* scratch = new uint8_t[width * height]; 758d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy 75989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk horizontalBlur(gaussian, radius, image, scratch, width, height); 76089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk verticalBlur(gaussian, radius, scratch, image, width, height); 761d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy 76289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk delete[] gaussian; 76389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk delete[] scratch; 76489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 76589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 766694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace uirenderer 767694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace android 768