FontRenderer.cpp revision 378e919ccb75efe24d5a5aa75ac2c6ef255dcb48
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 40e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#define CACHE_BLOCK_ROUNDING_SIZE 4 417de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 429777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy#define AUTO_KERN(prev, next) (((next) - (prev) + 32) >> 6 << 16) 439777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 447de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase/////////////////////////////////////////////////////////////////////////////// 45e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase// CacheBlock 46e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase/////////////////////////////////////////////////////////////////////////////// 47e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase 48e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase/** 49e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase * Insert new block into existing linked list of blocks. Blocks are sorted in increasing-width 50e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase * order, except for the final block (the remainder space at the right, since we fill from the 51e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase * left). 52e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase */ 53e816baea651476aca4407200d4a5e629b9ab8dfaChet HaaseCacheBlock* CacheBlock::insertBlock(CacheBlock* head, CacheBlock *newBlock) { 54e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#if DEBUG_FONT_RENDERER 55e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase ALOGD("insertBlock: this, x, y, w, h = %p, %d, %d, %d, %d", 56e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase newBlock, newBlock->mX, newBlock->mY, 57e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase newBlock->mWidth, newBlock->mHeight); 58e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif 59e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase CacheBlock *currBlock = head; 60e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase CacheBlock *prevBlock = NULL; 61e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase while (currBlock && currBlock->mY != TEXTURE_BORDER_SIZE) { 62e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (newBlock->mWidth < currBlock->mWidth) { 63e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase newBlock->mNext = currBlock; 64e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase newBlock->mPrev = prevBlock; 65e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase currBlock->mPrev = newBlock; 66e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (prevBlock) { 67e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase prevBlock->mNext = newBlock; 68e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase return head; 69e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } else { 70e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase return newBlock; 71e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 72e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 73e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase prevBlock = currBlock; 74e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase currBlock = currBlock->mNext; 75e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 76e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase // new block larger than all others - insert at end (but before the remainder space, if there) 77e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase newBlock->mNext = currBlock; 78e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase newBlock->mPrev = prevBlock; 79e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (currBlock) { 80e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase currBlock->mPrev = newBlock; 81e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 82e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (prevBlock) { 83e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase prevBlock->mNext = newBlock; 84e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase return head; 85e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } else { 86e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase return newBlock; 87e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 88e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase} 89e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase 90e816baea651476aca4407200d4a5e629b9ab8dfaChet HaaseCacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock *blockToRemove) { 91e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#if DEBUG_FONT_RENDERER 92e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase ALOGD("removeBlock: this, x, y, w, h = %p, %d, %d, %d, %d", 93e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase blockToRemove, blockToRemove->mX, blockToRemove->mY, 94e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase blockToRemove->mWidth, blockToRemove->mHeight); 95e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif 96e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase CacheBlock* newHead = head; 97e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase CacheBlock* nextBlock = blockToRemove->mNext; 98e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase CacheBlock* prevBlock = blockToRemove->mPrev; 99e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (prevBlock) { 100e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase prevBlock->mNext = nextBlock; 101e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } else { 102e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase newHead = nextBlock; 103e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 104e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (nextBlock) { 105e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase nextBlock->mPrev = prevBlock; 106e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 107e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase delete blockToRemove; 108e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase return newHead; 109e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase} 110e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase 111e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase/////////////////////////////////////////////////////////////////////////////// 112378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase// CacheTexture 1137de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase/////////////////////////////////////////////////////////////////////////////// 1147de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 115378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haasebool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) { 116378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase if (glyph.fHeight + TEXTURE_BORDER_SIZE > mHeight) { 1177de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase return false; 1187de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 1197de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 120e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase uint16_t glyphW = glyph.fWidth + TEXTURE_BORDER_SIZE; 121e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase uint16_t glyphH = glyph.fHeight + TEXTURE_BORDER_SIZE; 122e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase // roundedUpW equals glyphW to the next multiple of CACHE_BLOCK_ROUNDING_SIZE. 123e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase // This columns for glyphs that are close but not necessarily exactly the same size. It trades 124e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase // off the loss of a few pixels for some glyphs against the ability to store more glyphs 125e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase // of varying sizes in one block. 126e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase uint16_t roundedUpW = 127e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase (glyphW + CACHE_BLOCK_ROUNDING_SIZE - 1) & -CACHE_BLOCK_ROUNDING_SIZE; 128e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase CacheBlock *cacheBlock = mCacheBlocks; 129e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase while (cacheBlock) { 130e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase // Store glyph in this block iff: it fits the block's remaining space and: 131e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase // it's the remainder space (mY == 0) or there's only enough height for this one glyph 132e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase // or it's within ROUNDING_SIZE of the block width 133e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (roundedUpW <= cacheBlock->mWidth && glyphH <= cacheBlock->mHeight && 134e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase (cacheBlock->mY == TEXTURE_BORDER_SIZE || 135e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase (cacheBlock->mWidth - roundedUpW < CACHE_BLOCK_ROUNDING_SIZE))) { 136e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (cacheBlock->mHeight - glyphH < glyphH) { 137e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase // Only enough space for this glyph - don't bother rounding up the width 138e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase roundedUpW = glyphW; 139e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 140e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase *retOriginX = cacheBlock->mX; 141378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase *retOriginY = cacheBlock->mY; 142e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase // If this is the remainder space, create a new cache block for this column. Otherwise, 143e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase // adjust the info about this column. 144e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (cacheBlock->mY == TEXTURE_BORDER_SIZE) { 145e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase uint16_t oldX = cacheBlock->mX; 146e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase // Adjust remainder space dimensions 147e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase cacheBlock->mWidth -= roundedUpW; 148e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase cacheBlock->mX += roundedUpW; 149378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase if (mHeight - glyphH >= glyphH) { 150e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase // There's enough height left over to create a new CacheBlock 151e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase CacheBlock *newBlock = new CacheBlock(oldX, glyphH, roundedUpW, 152378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase mHeight - glyphH); 153e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#if DEBUG_FONT_RENDERER 154e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase ALOGD("fitBitmap: Created new block: this, x, y, w, h = %p, %d, %d, %d, %d", 155e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase newBlock, newBlock->mX, newBlock->mY, 156e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase newBlock->mWidth, newBlock->mHeight); 157e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif 158e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase mCacheBlocks = CacheBlock::insertBlock(mCacheBlocks, newBlock); 159e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 160e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } else { 161e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase // Insert into current column and adjust column dimensions 162e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase cacheBlock->mY += glyphH; 163e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase cacheBlock->mHeight -= glyphH; 164e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#if DEBUG_FONT_RENDERER 165e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase ALOGD("fitBitmap: Added to existing block: this, x, y, w, h = %p, %d, %d, %d, %d", 166e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase cacheBlock, cacheBlock->mX, cacheBlock->mY, 167e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase cacheBlock->mWidth, cacheBlock->mHeight); 168e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif 169e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 170e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (cacheBlock->mHeight < fmin(glyphH, glyphW)) { 171e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase // If remaining space in this block is too small to be useful, remove it 172e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase mCacheBlocks = CacheBlock::removeBlock(mCacheBlocks, cacheBlock); 173e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 174e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase mDirty = true; 175e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#if DEBUG_FONT_RENDERER 176e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase ALOGD("fitBitmap: current block list:"); 177e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase mCacheBlocks->output(); 178e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif 179e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase ++mNumGlyphs; 180e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase return true; 181e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 182e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase cacheBlock = cacheBlock->mNext; 1837de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 184e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#if DEBUG_FONT_RENDERER 185e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase ALOGD("fitBitmap: returning false for glyph of size %d, %d", glyphW, glyphH); 186e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif 1877de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase return false; 1887de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase} 18944984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase 19051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy/////////////////////////////////////////////////////////////////////////////// 191694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Font 192694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 193694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1942577db1ec135a1470a2c42139772ec97a6c30e78Romain GuyFont::Font(FontRenderer* state, uint32_t fontId, float fontSize, 195bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy int flags, uint32_t italicStyle, uint32_t scaleX, 196bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy SkPaint::Style style, uint32_t strokeWidth) : 1972577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy mState(state), mFontId(fontId), mFontSize(fontSize), 198bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy mFlags(flags), mItalicStyle(italicStyle), mScaleX(scaleX), 199bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy mStyle(style), mStrokeWidth(mStrokeWidth) { 200694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 201694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 202694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 203694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFont::~Font() { 204694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t ct = 0; ct < mState->mActiveFonts.size(); ct++) { 205694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mState->mActiveFonts[ct] == this) { 206694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mState->mActiveFonts.removeAt(ct); 207694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 208694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 209694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 210694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 211694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) { 212726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy delete mCachedGlyphs.valueAt(i); 213694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 214694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 215694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 216378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haasevoid Font::invalidateTextureCache(CacheTexture *cacheTexture) { 217694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) { 2189a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueAt(i); 219378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase if (cacheTexture == NULL || cachedGlyph->mCacheTexture == cacheTexture) { 2209a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase cachedGlyph->mIsValid = false; 2219a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase } 222694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 223694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 224694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 225671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y, 226671d6cf460531825a321edb200523d0faa7792c9Romain Guy uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) { 227f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int nPenX = x + glyph->mBitmapLeft; 228f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int nPenY = y + glyph->mBitmapTop; 229f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 230f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int width = (int) glyph->mBitmapWidth; 231f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int height = (int) glyph->mBitmapHeight; 232f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 23361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->bottom > nPenY) { 234f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->bottom = nPenY; 235f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 23661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->left > nPenX) { 237f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->left = nPenX; 238f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 23961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->right < nPenX + width) { 240f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->right = nPenX + width; 241f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 24261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->top < nPenY + height) { 243f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->top = nPenY + height; 244f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 245f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 246f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 247671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, 248671d6cf460531825a321edb200523d0faa7792c9Romain Guy uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) { 249694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int nPenX = x + glyph->mBitmapLeft; 250694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight; 251694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 25251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float u1 = glyph->mBitmapMinU; 25351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float u2 = glyph->mBitmapMaxU; 25451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float v1 = glyph->mBitmapMinV; 25551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float v2 = glyph->mBitmapMaxV; 25651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 25751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy int width = (int) glyph->mBitmapWidth; 25851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy int height = (int) glyph->mBitmapHeight; 25951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 260d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy mState->appendMeshQuad(nPenX, nPenY, u1, v2, 261d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy nPenX + width, nPenY, u2, v2, 262d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy nPenX + width, nPenY - height, u2, v1, 263378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase nPenX, nPenY - height, u1, v1, glyph->mCacheTexture); 264694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 265694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 266671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, 267671d6cf460531825a321edb200523d0faa7792c9Romain Guy uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) { 26889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int nPenX = x + glyph->mBitmapLeft; 26989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int nPenY = y + glyph->mBitmapTop; 27089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 27189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint32_t endX = glyph->mStartX + glyph->mBitmapWidth; 27289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint32_t endY = glyph->mStartY + glyph->mBitmapHeight; 27389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 274378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase CacheTexture *cacheTexture = glyph->mCacheTexture; 2757de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint32_t cacheWidth = cacheTexture->mWidth; 2767de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase const uint8_t* cacheBuffer = cacheTexture->mTexture; 27789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 278f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk uint32_t cacheX = 0, cacheY = 0; 279f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int32_t bX = 0, bY = 0; 28089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) { 28189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) { 282b629490ffb21752750cc081827ca4c1eae1eb015Romain Guy#if DEBUG_FONT_RENDERER 283b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) { 2843762c311729fe9f3af085c14c5c1fb471d994c03Steve Block ALOGE("Skipping invalid index"); 285f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk continue; 286f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 287b629490ffb21752750cc081827ca4c1eae1eb015Romain Guy#endif 28889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX]; 28989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk bitmap[bY * bitmapW + bX] = tempCol; 29089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 29189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 29289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 29389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 2949777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset, 2959777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy SkPathMeasure& measure, SkPoint* position, SkVector* tangent) { 2969777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy const float halfWidth = glyph->mBitmapWidth * 0.5f; 2979777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy const float height = glyph->mBitmapHeight; 2989777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 2999777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy vOffset += glyph->mBitmapTop + height; 3009777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 3019777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy SkPoint destination[4]; 302dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy measure.getPosTan(x + hOffset + glyph->mBitmapLeft + halfWidth, position, tangent); 3039777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 3049777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy // Move along the tangent and offset by the normal 3059777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy destination[0].set(-tangent->fX * halfWidth - tangent->fY * vOffset, 3069777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy -tangent->fY * halfWidth + tangent->fX * vOffset); 3079777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy destination[1].set(tangent->fX * halfWidth - tangent->fY * vOffset, 3089777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy tangent->fY * halfWidth + tangent->fX * vOffset); 3099777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy destination[2].set(destination[1].fX + tangent->fY * height, 3109777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy destination[1].fY - tangent->fX * height); 3119777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy destination[3].set(destination[0].fX + tangent->fY * height, 3129777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy destination[0].fY - tangent->fX * height); 3139777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 314dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy const float u1 = glyph->mBitmapMinU; 315dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy const float u2 = glyph->mBitmapMaxU; 316dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy const float v1 = glyph->mBitmapMinV; 317dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy const float v2 = glyph->mBitmapMaxV; 318dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy 3199777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mState->appendRotatedMeshQuad( 3209777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy position->fX + destination[0].fX, 3219777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy position->fY + destination[0].fY, u1, v2, 3229777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy position->fX + destination[1].fX, 3239777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy position->fY + destination[1].fY, u2, v2, 3249777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy position->fX + destination[2].fX, 3259777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy position->fY + destination[2].fY, u2, v1, 3269777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy position->fX + destination[3].fX, 3279777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy position->fY + destination[3].fY, u1, v1, 328378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase glyph->mCacheTexture); 3299777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy} 3309777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 3317de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet HaaseCachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) { 3321e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy CachedGlyphInfo* cachedGlyph = NULL; 333726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy ssize_t index = mCachedGlyphs.indexOfKey(textUnit); 3341e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (index >= 0) { 3351e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy cachedGlyph = mCachedGlyphs.valueAt(index); 3361e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } else { 337726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy cachedGlyph = cacheGlyph(paint, textUnit); 33865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 33965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 34065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk // Is the glyph still in texture cache? 34165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk if (!cachedGlyph->mIsValid) { 342726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit); 34365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk updateGlyphCache(paint, skiaGlyph, cachedGlyph); 34465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 34565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 34665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk return cachedGlyph; 34765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk} 34865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 349726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guyvoid Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 35061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy int numGlyphs, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) { 35161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bitmap != NULL && bitmapW > 0 && bitmapH > 0) { 352726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy render(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap, 353671d6cf460531825a321edb200523d0faa7792c9Romain Guy bitmapW, bitmapH, NULL, NULL); 35461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy } else { 355726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL, 356671d6cf460531825a321edb200523d0faa7792c9Romain Guy 0, 0, NULL, NULL); 357f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 358f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 359f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 360671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len, 361671d6cf460531825a321edb200523d0faa7792c9Romain Guy int numGlyphs, int x, int y, const float* positions) { 362671d6cf460531825a321edb200523d0faa7792c9Romain Guy render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL, 363671d6cf460531825a321edb200523d0faa7792c9Romain Guy 0, 0, NULL, positions); 364671d6cf460531825a321edb200523d0faa7792c9Romain Guy} 365671d6cf460531825a321edb200523d0faa7792c9Romain Guy 3669777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len, 3679777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy int numGlyphs, SkPath* path, float hOffset, float vOffset) { 3689777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (numGlyphs == 0 || text == NULL || len == 0) { 3699777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy return; 3709777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 3719777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 3729777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy text += start; 3739777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 3749777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy int glyphsCount = 0; 3759777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy SkFixed prevRsbDelta = 0; 3769777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 3779777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float penX = 0.0f; 3789777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 3799777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy SkPoint position; 3809777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy SkVector tangent; 3819777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 3829777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy SkPathMeasure measure(*path, false); 3839777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float pathLength = SkScalarToFloat(measure.getLength()); 3849777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 3859777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (paint->getTextAlign() != SkPaint::kLeft_Align) { 3869777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float textWidth = SkScalarToFloat(paint->measureText(text, len)); 3879777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float pathOffset = pathLength; 3889777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (paint->getTextAlign() == SkPaint::kCenter_Align) { 3899777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy textWidth *= 0.5f; 3909777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy pathOffset *= 0.5f; 3919777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 3929777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy penX += pathOffset - textWidth; 3939777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 3949777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 395dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy while (glyphsCount < numGlyphs && penX < pathLength) { 3969777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy glyph_t glyph = GET_GLYPH(text); 3979777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 3989777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (IS_END_OF_STRING(glyph)) { 3999777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy break; 4009777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 4019777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 4029777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph); 4039777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta)); 4049777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy prevRsbDelta = cachedGlyph->mRsbDelta; 4059777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 4069777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (cachedGlyph->mIsValid) { 407dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy drawCachedGlyph(cachedGlyph, penX, hOffset, vOffset, measure, &position, &tangent); 4089777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 4099777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 4109777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy penX += SkFixedToFloat(cachedGlyph->mAdvanceX); 4119777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 4129777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy glyphsCount++; 4139777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 4149777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy} 4159777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 416726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guyvoid Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 417416a847633680d94efb926837efdc18726d54918Raph Levien int numGlyphs, Rect *bounds, const float* positions) { 41861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds == NULL) { 4193762c311729fe9f3af085c14c5c1fb471d994c03Steve Block ALOGE("No return rectangle provided to measure text"); 420f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk return; 421f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 422f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->set(1e6, -1e6, -1e6, 1e6); 423416a847633680d94efb926837efdc18726d54918Raph Levien render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds, positions); 424f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 425f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 426e816baea651476aca4407200d4a5e629b9ab8dfaChet Haasevoid Font::precache(SkPaint* paint, const char* text, int numGlyphs) { 427e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase 428e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (numGlyphs == 0 || text == NULL) { 429e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase return; 430e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 431e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase int glyphsCount = 0; 432e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase 433e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase while (glyphsCount < numGlyphs) { 434e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase glyph_t glyph = GET_GLYPH(text); 435e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase 436e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase // Reached the end of the string 437e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (IS_END_OF_STRING(glyph)) { 438e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase break; 439e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 440e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase 441e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph); 442e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase 443e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase glyphsCount++; 444e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 445e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase} 446e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase 447726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guyvoid Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 44861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap, 4499777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* positions) { 450694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (numGlyphs == 0 || text == NULL || len == 0) { 451694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 452694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 453694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 454671d6cf460531825a321edb200523d0faa7792c9Romain Guy static RenderGlyph gRenderGlyph[] = { 455671d6cf460531825a321edb200523d0faa7792c9Romain Guy &android::uirenderer::Font::drawCachedGlyph, 456671d6cf460531825a321edb200523d0faa7792c9Romain Guy &android::uirenderer::Font::drawCachedGlyphBitmap, 457671d6cf460531825a321edb200523d0faa7792c9Romain Guy &android::uirenderer::Font::measureCachedGlyph 458671d6cf460531825a321edb200523d0faa7792c9Romain Guy }; 459671d6cf460531825a321edb200523d0faa7792c9Romain Guy RenderGlyph render = gRenderGlyph[mode]; 460694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 4619777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy text += start; 4629777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy int glyphsCount = 0; 4639777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 464b629490ffb21752750cc081827ca4c1eae1eb015Romain Guy if (CC_LIKELY(positions == NULL)) { 465671d6cf460531825a321edb200523d0faa7792c9Romain Guy SkFixed prevRsbDelta = 0; 466694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 4679777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float penX = x + 0.5f; 468671d6cf460531825a321edb200523d0faa7792c9Romain Guy int penY = y; 469694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 470671d6cf460531825a321edb200523d0faa7792c9Romain Guy while (glyphsCount < numGlyphs) { 471671d6cf460531825a321edb200523d0faa7792c9Romain Guy glyph_t glyph = GET_GLYPH(text); 472671d6cf460531825a321edb200523d0faa7792c9Romain Guy 473671d6cf460531825a321edb200523d0faa7792c9Romain Guy // Reached the end of the string 474671d6cf460531825a321edb200523d0faa7792c9Romain Guy if (IS_END_OF_STRING(glyph)) { 475f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk break; 47689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 477671d6cf460531825a321edb200523d0faa7792c9Romain Guy 478671d6cf460531825a321edb200523d0faa7792c9Romain Guy CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph); 4799777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta)); 480671d6cf460531825a321edb200523d0faa7792c9Romain Guy prevRsbDelta = cachedGlyph->mRsbDelta; 481671d6cf460531825a321edb200523d0faa7792c9Romain Guy 482671d6cf460531825a321edb200523d0faa7792c9Romain Guy // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage 483671d6cf460531825a321edb200523d0faa7792c9Romain Guy if (cachedGlyph->mIsValid) { 484671d6cf460531825a321edb200523d0faa7792c9Romain Guy (*this.*render)(cachedGlyph, (int) floorf(penX), penY, 485671d6cf460531825a321edb200523d0faa7792c9Romain Guy bitmap, bitmapW, bitmapH, bounds, positions); 486671d6cf460531825a321edb200523d0faa7792c9Romain Guy } 487671d6cf460531825a321edb200523d0faa7792c9Romain Guy 488671d6cf460531825a321edb200523d0faa7792c9Romain Guy penX += SkFixedToFloat(cachedGlyph->mAdvanceX); 489671d6cf460531825a321edb200523d0faa7792c9Romain Guy 490671d6cf460531825a321edb200523d0faa7792c9Romain Guy glyphsCount++; 491694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 492671d6cf460531825a321edb200523d0faa7792c9Romain Guy } else { 493671d6cf460531825a321edb200523d0faa7792c9Romain Guy const SkPaint::Align align = paint->getTextAlign(); 494694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 495671d6cf460531825a321edb200523d0faa7792c9Romain Guy // This is for renderPosText() 496671d6cf460531825a321edb200523d0faa7792c9Romain Guy while (glyphsCount < numGlyphs) { 497671d6cf460531825a321edb200523d0faa7792c9Romain Guy glyph_t glyph = GET_GLYPH(text); 498694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 499671d6cf460531825a321edb200523d0faa7792c9Romain Guy // Reached the end of the string 500671d6cf460531825a321edb200523d0faa7792c9Romain Guy if (IS_END_OF_STRING(glyph)) { 501671d6cf460531825a321edb200523d0faa7792c9Romain Guy break; 502671d6cf460531825a321edb200523d0faa7792c9Romain Guy } 503671d6cf460531825a321edb200523d0faa7792c9Romain Guy 504671d6cf460531825a321edb200523d0faa7792c9Romain Guy CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph); 505671d6cf460531825a321edb200523d0faa7792c9Romain Guy 506671d6cf460531825a321edb200523d0faa7792c9Romain Guy // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage 507671d6cf460531825a321edb200523d0faa7792c9Romain Guy if (cachedGlyph->mIsValid) { 508671d6cf460531825a321edb200523d0faa7792c9Romain Guy int penX = x + positions[(glyphsCount << 1)]; 509671d6cf460531825a321edb200523d0faa7792c9Romain Guy int penY = y + positions[(glyphsCount << 1) + 1]; 510671d6cf460531825a321edb200523d0faa7792c9Romain Guy 511671d6cf460531825a321edb200523d0faa7792c9Romain Guy switch (align) { 512671d6cf460531825a321edb200523d0faa7792c9Romain Guy case SkPaint::kRight_Align: 513671d6cf460531825a321edb200523d0faa7792c9Romain Guy penX -= SkFixedToFloat(cachedGlyph->mAdvanceX); 514671d6cf460531825a321edb200523d0faa7792c9Romain Guy penY -= SkFixedToFloat(cachedGlyph->mAdvanceY); 515671d6cf460531825a321edb200523d0faa7792c9Romain Guy break; 516671d6cf460531825a321edb200523d0faa7792c9Romain Guy case SkPaint::kCenter_Align: 517671d6cf460531825a321edb200523d0faa7792c9Romain Guy penX -= SkFixedToFloat(cachedGlyph->mAdvanceX >> 1); 518671d6cf460531825a321edb200523d0faa7792c9Romain Guy penY -= SkFixedToFloat(cachedGlyph->mAdvanceY >> 1); 519671d6cf460531825a321edb200523d0faa7792c9Romain Guy default: 520671d6cf460531825a321edb200523d0faa7792c9Romain Guy break; 521671d6cf460531825a321edb200523d0faa7792c9Romain Guy } 522671d6cf460531825a321edb200523d0faa7792c9Romain Guy 523671d6cf460531825a321edb200523d0faa7792c9Romain Guy (*this.*render)(cachedGlyph, penX, penY, 524671d6cf460531825a321edb200523d0faa7792c9Romain Guy bitmap, bitmapW, bitmapH, bounds, positions); 525671d6cf460531825a321edb200523d0faa7792c9Romain Guy } 526671d6cf460531825a321edb200523d0faa7792c9Romain Guy 527671d6cf460531825a321edb200523d0faa7792c9Romain Guy glyphsCount++; 528694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 529694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 530694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 531694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 53251769a68a5cb34e9564740c6a854fcb93018789dRomain Guyvoid Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph) { 533694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mAdvanceX = skiaGlyph.fAdvanceX; 534694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mAdvanceY = skiaGlyph.fAdvanceY; 535694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapLeft = skiaGlyph.fLeft; 536694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapTop = skiaGlyph.fTop; 5372bffd268f135df8308c9e67af110525a5c463424Romain Guy glyph->mLsbDelta = skiaGlyph.fLsbDelta; 5382bffd268f135df8308c9e67af110525a5c463424Romain Guy glyph->mRsbDelta = skiaGlyph.fRsbDelta; 539694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 540694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startX = 0; 541694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startY = 0; 542694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 543694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Get the bitmap for the glyph 544694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy paint->findImage(skiaGlyph); 5457de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY); 546694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 547694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!glyph->mIsValid) { 548694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 549694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 550694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 551694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endX = startX + skiaGlyph.fWidth; 552694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endY = startY + skiaGlyph.fHeight; 553694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 55489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk glyph->mStartX = startX; 55589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk glyph->mStartY = startY; 556694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapWidth = skiaGlyph.fWidth; 557694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapHeight = skiaGlyph.fHeight; 558694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 559378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase uint32_t cacheWidth = glyph->mCacheTexture->mWidth; 560378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase uint32_t cacheHeight = glyph->mCacheTexture->mHeight; 561694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 56233fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy glyph->mBitmapMinU = startX / (float) cacheWidth; 56333fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy glyph->mBitmapMinV = startY / (float) cacheHeight; 56433fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy glyph->mBitmapMaxU = endX / (float) cacheWidth; 56533fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy glyph->mBitmapMaxV = endY / (float) cacheHeight; 566694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 56751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mState->mUploadTexture = true; 568694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 569694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 5707de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet HaaseCachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph) { 57151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy CachedGlyphInfo* newGlyph = new CachedGlyphInfo(); 572694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCachedGlyphs.add(glyph, newGlyph); 573694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 574726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph); 575694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy newGlyph->mGlyphIndex = skiaGlyph.fID; 576694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy newGlyph->mIsValid = false; 577694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 578694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy updateGlyphCache(paint, skiaGlyph, newGlyph); 579694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 580694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return newGlyph; 581694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 582694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 5832577db1ec135a1470a2c42139772ec97a6c30e78Romain GuyFont* Font::create(FontRenderer* state, uint32_t fontId, float fontSize, 584bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy int flags, uint32_t italicStyle, uint32_t scaleX, 585bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy SkPaint::Style style, uint32_t strokeWidth) { 586694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy Vector<Font*> &activeFonts = state->mActiveFonts; 587694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 588694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < activeFonts.size(); i++) { 58951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy Font* font = activeFonts[i]; 5902577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy if (font->mFontId == fontId && font->mFontSize == fontSize && 5918668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase font->mFlags == flags && font->mItalicStyle == italicStyle && 592bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy font->mScaleX == scaleX && font->mStyle == style && 593bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy (style == SkPaint::kFill_Style || font->mStrokeWidth == strokeWidth)) { 59451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy return font; 595694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 596694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 597694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 598bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle, 599bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy scaleX, style, strokeWidth); 600694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy activeFonts.push(newFont); 601694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return newFont; 602694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 603694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 604694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 605694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// FontRenderer 606694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 607694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 608514fb18827186591d66973c2362c859b64b63556Romain Guystatic bool sLogFontRendererCreate = true; 609514fb18827186591d66973c2362c859b64b63556Romain Guy 610694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::FontRenderer() { 611c9855a53edfac818dc68714557185977556f849dRomain Guy if (sLogFontRendererCreate) { 612c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD("Creating FontRenderer"); 613c9855a53edfac818dc68714557185977556f849dRomain Guy } 61451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 615b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy mGammaTable = NULL; 616694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mInitialized = false; 617694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mMaxNumberOfQuads = 1024; 618694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 619694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 6209cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy mTextMeshPtr = NULL; 6217de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCurrentCacheTexture = NULL; 6227de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mLastCacheTexture = NULL; 6239cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy 6242a47c14e2a6f152496b43104bc785c488583fd59Chet Haase mLinearFiltering = false; 6252a47c14e2a6f152496b43104bc785c488583fd59Chet Haase 626694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mIndexBufferID = 0; 627694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 6287de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mSmallCacheWidth = DEFAULT_TEXT_CACHE_WIDTH; 6297de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mSmallCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT; 63051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 63151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy char property[PROPERTY_VALUE_MAX]; 63251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) { 633c9855a53edfac818dc68714557185977556f849dRomain Guy if (sLogFontRendererCreate) { 634c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD(" Setting text cache width to %s pixels", property); 635c9855a53edfac818dc68714557185977556f849dRomain Guy } 6367de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mSmallCacheWidth = atoi(property); 63751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } else { 638514fb18827186591d66973c2362c859b64b63556Romain Guy if (sLogFontRendererCreate) { 6397de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase INIT_LOGD(" Using default text cache width of %i pixels", mSmallCacheWidth); 640514fb18827186591d66973c2362c859b64b63556Romain Guy } 64151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } 64251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 64351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy if (property_get(PROPERTY_TEXT_CACHE_HEIGHT, property, NULL) > 0) { 644c9855a53edfac818dc68714557185977556f849dRomain Guy if (sLogFontRendererCreate) { 645c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD(" Setting text cache width to %s pixels", property); 646c9855a53edfac818dc68714557185977556f849dRomain Guy } 6477de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mSmallCacheHeight = atoi(property); 64851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } else { 649514fb18827186591d66973c2362c859b64b63556Romain Guy if (sLogFontRendererCreate) { 6507de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase INIT_LOGD(" Using default text cache height of %i pixels", mSmallCacheHeight); 651514fb18827186591d66973c2362c859b64b63556Romain Guy } 65251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } 653514fb18827186591d66973c2362c859b64b63556Romain Guy 654514fb18827186591d66973c2362c859b64b63556Romain Guy sLogFontRendererCreate = false; 655694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 656694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 657694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::~FontRenderer() { 658378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase for (uint32_t i = 0; i < mCacheTextures.size(); i++) { 659378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase delete mCacheTextures[i]; 660694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 661378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase mCacheTextures.clear(); 662694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 6639cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy if (mInitialized) { 664a9dd820184ee4d083bd9b2af735dcf50b78fc6cdRomain Guy // Unbinding the buffer shouldn't be necessary but it crashes with some drivers 665a9dd820184ee4d083bd9b2af735dcf50b78fc6cdRomain Guy Caches::getInstance().unbindIndicesBuffer(); 666b0317984d34da99b614597ad0a8b39268eacb783Romain Guy glDeleteBuffers(1, &mIndexBufferID); 667b0317984d34da99b614597ad0a8b39268eacb783Romain Guy 6689cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy delete[] mTextMeshPtr; 6699b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 670694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 671694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy Vector<Font*> fontsToDereference = mActiveFonts; 672694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < fontsToDereference.size(); i++) { 673694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy delete fontsToDereference[i]; 674694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 675694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 676694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 677694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::flushAllAndInvalidate() { 678694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex != 0) { 679694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 680694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 681694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 6829d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 683694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mActiveFonts.size(); i++) { 684694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mActiveFonts[i]->invalidateTextureCache(); 685694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 6869d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 687378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase for (uint32_t i = 0; i < mCacheTextures.size(); i++) { 688378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase mCacheTextures[i]->init(); 689e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 690e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase 691378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase #if DEBUG_FONT_RENDERER 692378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase uint16_t totalGlyphs = 0; 693378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase for (uint32_t i = 0; i < mCacheTextures.size(); i++) { 694378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase totalGlyphs += mCacheTextures[i]->mNumGlyphs; 695378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase // Erase caches, just as a debugging facility 696378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase if (mCacheTextures[i]->mTexture) { 697378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase memset(mCacheTextures[i]->mTexture, 0, 698378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase mCacheTextures[i]->mWidth * mCacheTextures[i]->mHeight); 699378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase } 700e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 701e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase ALOGD("Flushing caches: glyphs cached = %d", totalGlyphs); 702e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif 703694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 704694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 7059a8245629d69d81e0b62e52970feaf9c02580e75Chet Haasevoid FontRenderer::deallocateTextureMemory(CacheTexture *cacheTexture) { 7069a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase if (cacheTexture && cacheTexture->mTexture) { 7079a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase glDeleteTextures(1, &cacheTexture->mTextureId); 7089d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy delete[] cacheTexture->mTexture; 7099a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase cacheTexture->mTexture = NULL; 71099a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy cacheTexture->mTextureId = 0; 7119a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase } 7129a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase} 7139a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase 7149a8245629d69d81e0b62e52970feaf9c02580e75Chet Haasevoid FontRenderer::flushLargeCaches() { 715378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase // Start from 1; don't deallocate smallest/default texture 716378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase for (uint32_t i = 1; i < mCacheTextures.size(); i++) { 717378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase CacheTexture* cacheTexture = mCacheTextures[i]; 718378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase if (cacheTexture->mTexture != NULL) { 719378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase cacheTexture->init(); 720378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase for (uint32_t j = 0; j < mActiveFonts.size(); j++) { 721378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase mActiveFonts[j]->invalidateTextureCache(cacheTexture); 7229a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase } 723378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase deallocateTextureMemory(cacheTexture); 7249a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase } 7259a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase } 7269a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase} 7279a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase 7289d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guyvoid FontRenderer::allocateTextureMemory(CacheTexture* cacheTexture) { 7292a47c14e2a6f152496b43104bc785c488583fd59Chet Haase int width = cacheTexture->mWidth; 7302a47c14e2a6f152496b43104bc785c488583fd59Chet Haase int height = cacheTexture->mHeight; 7319d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 7322a47c14e2a6f152496b43104bc785c488583fd59Chet Haase cacheTexture->mTexture = new uint8_t[width * height]; 73399a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy 73499a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy if (!cacheTexture->mTextureId) { 73599a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy glGenTextures(1, &cacheTexture->mTextureId); 73699a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy } 7379d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 73816c88085255c71a1a8fc034129aa2dcc61e1ddd0Romain Guy Caches::getInstance().activeTexture(0); 7392a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId); 7402a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 7412a47c14e2a6f152496b43104bc785c488583fd59Chet Haase // Initialize texture dimensions 7422a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, 7432a47c14e2a6f152496b43104bc785c488583fd59Chet Haase GL_ALPHA, GL_UNSIGNED_BYTE, 0); 7442a47c14e2a6f152496b43104bc785c488583fd59Chet Haase 7452a47c14e2a6f152496b43104bc785c488583fd59Chet Haase const GLenum filtering = cacheTexture->mLinearFiltering ? GL_LINEAR : GL_NEAREST; 7462a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); 7472a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); 7487de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 7492a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 7502a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 7517de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase} 7527de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 753378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet HaaseCacheTexture* FontRenderer::cacheBitmapInTexture(const SkGlyph& glyph, 754378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase uint32_t* startX, uint32_t* startY) { 755378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase for (uint32_t i = 0; i < mCacheTextures.size(); i++) { 756378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase if (mCacheTextures[i]->fitBitmap(glyph, startX, startY)) { 757378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase return mCacheTextures[i]; 758378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase } 759378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase } 760378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase // Could not fit glyph into current cache textures 761378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase return NULL; 762378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase} 763378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase 7647de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasevoid FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph, 7657de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint32_t* retOriginX, uint32_t* retOriginY) { 7662efd5c5886d9acf747bc92f888d731ed558aabccChet Haase checkInit(); 7677de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase cachedGlyph->mIsValid = false; 768694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If the glyph is too tall, don't cache it 769378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > 770378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase mCacheTextures[mCacheTextures.size() - 1]->mHeight) { 7712efd5c5886d9acf747bc92f888d731ed558aabccChet Haase ALOGE("Font size too large to fit in cache. width, height = %i, %i", 7722efd5c5886d9acf747bc92f888d731ed558aabccChet Haase (int) glyph.fWidth, (int) glyph.fHeight); 7737de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase return; 774694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 775694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 776694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Now copy the bitmap into the cache texture 777694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startX = 0; 778694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startY = 0; 779694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 780378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase CacheTexture* cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY); 781694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 782694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If the new glyph didn't fit, flush the state so far and invalidate everything 783378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase if (!cacheTexture) { 784694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy flushAllAndInvalidate(); 785694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 786694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Try to fit it again 787378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY); 788694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 789694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // if we still don't fit, something is wrong and we shouldn't draw 790378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase if (!cacheTexture) { 7917de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase return; 792694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 793694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 794694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 795378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase cachedGlyph->mCacheTexture = cacheTexture; 7967de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 797694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *retOriginX = startX; 798694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *retOriginY = startY; 799694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 800694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endX = startX + glyph.fWidth; 801694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endY = startY + glyph.fHeight; 802694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 803378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase uint32_t cacheWidth = cacheTexture->mWidth; 804694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 8059d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy if (!cacheTexture->mTexture) { 8067de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // Large-glyph texture memory is allocated only as needed 8072a47c14e2a6f152496b43104bc785c488583fd59Chet Haase allocateTextureMemory(cacheTexture); 8087de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 8099d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 8107de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint8_t* cacheBuffer = cacheTexture->mTexture; 81189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage; 812694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy unsigned int stride = glyph.rowBytes(); 813694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 814694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; 81533fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy 81633fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy for (cacheX = startX - TEXTURE_BORDER_SIZE; cacheX < endX + TEXTURE_BORDER_SIZE; cacheX++) { 81733fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy cacheBuffer[(startY - TEXTURE_BORDER_SIZE) * cacheWidth + cacheX] = 0; 81833fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy cacheBuffer[(endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + cacheX] = 0; 81933fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy } 82033fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy 82133fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy for (cacheY = startY - TEXTURE_BORDER_SIZE + 1; 82233fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy cacheY < endY + TEXTURE_BORDER_SIZE - 1; cacheY++) { 82333fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy cacheBuffer[cacheY * cacheWidth + startX - TEXTURE_BORDER_SIZE] = 0; 82433fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy cacheBuffer[cacheY * cacheWidth + endX + TEXTURE_BORDER_SIZE - 1] = 0; 82533fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy } 82633fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy 827b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy if (mGammaTable) { 828b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) { 829b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) { 830b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy uint8_t tempCol = bitmapBuffer[bY * stride + bX]; 831b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol]; 832b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy } 833b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy } 834b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy } else { 835b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) { 836b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) { 837b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy uint8_t tempCol = bitmapBuffer[bY * stride + bX]; 838b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy cacheBuffer[cacheY * cacheWidth + cacheX] = tempCol; 839b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy } 840694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 841694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 8429777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 8437de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase cachedGlyph->mIsValid = true; 844694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 845694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 8467de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet HaaseCacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) { 8470aa87bbfc41e8b5f52de701ac17b4e66a7a7b609Romain Guy CacheTexture* cacheTexture = new CacheTexture(width, height); 8489d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 8492a47c14e2a6f152496b43104bc785c488583fd59Chet Haase if (allocate) { 8502a47c14e2a6f152496b43104bc785c488583fd59Chet Haase allocateTextureMemory(cacheTexture); 8512a47c14e2a6f152496b43104bc785c488583fd59Chet Haase } 8529d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 8532a47c14e2a6f152496b43104bc785c488583fd59Chet Haase return cacheTexture; 8547de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase} 8557de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 8567de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasevoid FontRenderer::initTextTexture() { 857378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase for (uint32_t i = 0; i < mCacheTextures.size(); i++) { 858378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase delete mCacheTextures[i]; 8599d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy } 860378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase mCacheTextures.clear(); 8619d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 8627de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // Next, use other, separate caches for large glyphs. 8637de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint16_t maxWidth = 0; 8647de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (Caches::hasInstance()) { 8657de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase maxWidth = Caches::getInstance().maxTextureSize; 8667de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 8679d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 8687de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (maxWidth > MAX_TEXT_CACHE_WIDTH || maxWidth == 0) { 8697de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase maxWidth = MAX_TEXT_CACHE_WIDTH; 8707de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 8719d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 8727de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mUploadTexture = false; 873378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase mCacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true)); 874378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase mCacheTextures.push(createCacheTexture(maxWidth, 256, false)); 875378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase mCacheTextures.push(createCacheTexture(maxWidth, 256, false)); 876378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase mCacheTextures.push(createCacheTexture(maxWidth, 512, false)); 877378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase mCurrentCacheTexture = mCacheTextures[0]; 878694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 879694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 880694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Avoid having to reallocate memory and render quad by quad 881694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::initVertexArrayBuffers() { 882d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy uint32_t numIndices = mMaxNumberOfQuads * 6; 883d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy uint32_t indexBufferSizeBytes = numIndices * sizeof(uint16_t); 88451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes); 885694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 886694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Four verts, two triangles , six indices per quad 887694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mMaxNumberOfQuads; i++) { 888694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int i6 = i * 6; 889694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int i4 = i * 4; 890694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 891694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 0] = i4 + 0; 892694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 1] = i4 + 1; 893694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 2] = i4 + 2; 894694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 895694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 3] = i4 + 0; 896694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 4] = i4 + 2; 897694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 5] = i4 + 3; 898694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 899694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 900694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glGenBuffers(1, &mIndexBufferID); 90115bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy Caches::getInstance().bindIndicesBuffer(mIndexBufferID); 9025d794412e3e429e47404395badcd11b0b8639e8bRomain Guy glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_STATIC_DRAW); 903694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 904694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy free(indexBufferData); 905694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 906d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy uint32_t coordSize = 2; 907694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t uvSize = 2; 908694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t vertsPerQuad = 4; 9099b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize; 9109b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mTextMeshPtr = new float[vertexBufferSize]; 911694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 912694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 913694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// We don't want to allocate anything unless we actually draw text 914694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::checkInit() { 915694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mInitialized) { 916694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 917694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 918694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 919694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy initTextTexture(); 920694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy initVertexArrayBuffers(); 921694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 922694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mInitialized = true; 923694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 924694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 9259b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::checkTextureUpdate() { 9267de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (!mUploadTexture && mLastCacheTexture == mCurrentCacheTexture) { 9279b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk return; 9289b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 9299b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 9302d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy Caches& caches = Caches::getInstance(); 9312d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy GLuint lastTextureId = 0; 932378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase // Iterate over all the cache textures and see which ones need to be updated 933378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase for (uint32_t i = 0; i < mCacheTextures.size(); i++) { 934378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase CacheTexture* cacheTexture = mCacheTextures[i]; 935378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase if (cacheTexture->mDirty && cacheTexture->mTexture != NULL) { 9369b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t xOffset = 0; 937378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase uint32_t width = cacheTexture->mWidth; 938378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase uint32_t height = cacheTexture->mHeight; 939378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase void* textureData = cacheTexture->mTexture; 9409b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 9412d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy if (cacheTexture->mTextureId != lastTextureId) { 9422d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy caches.activeTexture(0); 9432d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId); 9442d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy lastTextureId = cacheTexture->mTextureId; 9452d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy } 946e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#if DEBUG_FONT_RENDERER 947378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase ALOGD("glTextSubimage for cacheTexture %d: xOff, width height = %d, %d, %d", 948378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase i, xOffset, width, height); 949e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif 950378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, 0, width, height, 9511e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy GL_ALPHA, GL_UNSIGNED_BYTE, textureData); 9529b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 953378e919ccb75efe24d5a5aa75ac2c6ef255dcb48Chet Haase cacheTexture->mDirty = false; 9549b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 955694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 956694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 95716c88085255c71a1a8fc034129aa2dcc61e1ddd0Romain Guy caches.activeTexture(0); 9587de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase glBindTexture(GL_TEXTURE_2D, mCurrentCacheTexture->mTextureId); 9592a47c14e2a6f152496b43104bc785c488583fd59Chet Haase if (mLinearFiltering != mCurrentCacheTexture->mLinearFiltering) { 9602a47c14e2a6f152496b43104bc785c488583fd59Chet Haase const GLenum filtering = mLinearFiltering ? GL_LINEAR : GL_NEAREST; 9612a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); 9622a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); 9632a47c14e2a6f152496b43104bc785c488583fd59Chet Haase mCurrentCacheTexture->mLinearFiltering = mLinearFiltering; 9642a47c14e2a6f152496b43104bc785c488583fd59Chet Haase } 9657de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mLastCacheTexture = mCurrentCacheTexture; 9667de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 9679b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mUploadTexture = false; 9689b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk} 9699b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 9709b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::issueDrawCommand() { 9719b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk checkTextureUpdate(); 9729b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 97315bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy Caches& caches = Caches::getInstance(); 9742d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy caches.bindIndicesBuffer(mIndexBufferID); 97515bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy if (!mDrawn) { 97615bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy float* buffer = mTextMeshPtr; 97715bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy int offset = 2; 97815bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy 97915bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy bool force = caches.unbindMeshBuffer(); 98015bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy caches.bindPositionVertexPointer(force, caches.currentProgram->position, buffer); 98115bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy caches.bindTexCoordsVertexPointer(force, caches.currentProgram->texCoords, 98215bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy buffer + offset); 98315bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy } 98415bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy 985694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL); 9865b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 9875b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mDrawn = true; 988694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 989694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 9909777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1, 9919777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3, 9927de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase float x4, float y4, float u4, float v4, CacheTexture* texture) { 9937de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (texture != mCurrentCacheTexture) { 9947de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (mCurrentQuadIndex != 0) { 9957de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // First, draw everything stored already which uses the previous texture 9967de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase issueDrawCommand(); 9977de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCurrentQuadIndex = 0; 9987de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 9997de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // Now use the new texture id 10007de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCurrentCacheTexture = texture; 10017de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 100209147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy 1003694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy const uint32_t vertsPerQuad = 4; 1004d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy const uint32_t floatsPerVert = 4; 100551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float* currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert; 1006694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1007694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x1; 1008694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y1; 1009694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u1; 1010694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v1; 1011694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1012694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x2; 1013694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y2; 1014694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u2; 1015694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v2; 1016694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1017694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x3; 1018694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y3; 1019694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u3; 1020694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v3; 1021694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1022694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x4; 1023694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y4; 1024694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u4; 1025694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v4; 1026694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1027694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex++; 10289777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy} 10299777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 10309777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1, 10319777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3, 10329777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float x4, float y4, float u4, float v4, CacheTexture* texture) { 10339777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 10349777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (mClip && 10359777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) { 10369777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy return; 10379777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 10389777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 10399777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture); 1040694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 10415b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy if (mBounds) { 10425b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->left = fmin(mBounds->left, x1); 10435b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->top = fmin(mBounds->top, y3); 10445b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->right = fmax(mBounds->right, x3); 10455b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->bottom = fmax(mBounds->bottom, y1); 10465b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy } 10475b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 1048694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex == mMaxNumberOfQuads) { 1049694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 1050694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 1051694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 1052694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 1053694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 10549777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1, 10559777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3, 10569777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float x4, float y4, float u4, float v4, CacheTexture* texture) { 10579777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 10589777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture); 10599777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 10609777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (mBounds) { 10619777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mBounds->left = fmin(mBounds->left, fmin(x1, fmin(x2, fmin(x3, x4)))); 10629777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mBounds->top = fmin(mBounds->top, fmin(y1, fmin(y2, fmin(y3, y4)))); 10639777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mBounds->right = fmax(mBounds->right, fmax(x1, fmax(x2, fmax(x3, x4)))); 10649777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mBounds->bottom = fmax(mBounds->bottom, fmax(y1, fmax(y2, fmax(y3, y4)))); 10659777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 10669777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 10679777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (mCurrentQuadIndex == mMaxNumberOfQuads) { 10689777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy issueDrawCommand(); 10699777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mCurrentQuadIndex = 0; 10709777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 10719777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy} 10729777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 107365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) { 1074325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy int flags = 0; 1075325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (paint->isFakeBoldText()) { 1076325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy flags |= Font::kFakeBold; 1077325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy } 10782577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy 10792577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy const float skewX = paint->getTextSkewX(); 10802577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy uint32_t italicStyle = *(uint32_t*) &skewX; 10818668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase const float scaleXFloat = paint->getTextScaleX(); 10828668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase uint32_t scaleX = *(uint32_t*) &scaleXFloat; 1083bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy SkPaint::Style style = paint->getStyle(); 1084bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy const float strokeWidthFloat = paint->getStrokeWidth(); 1085bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy uint32_t strokeWidth = *(uint32_t*) &strokeWidthFloat; 1086bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle, 1087bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy scaleX, style, strokeWidth); 108865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 1089694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 10907975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy 1091f18136cb3c881a9d16c1a4f0f341732c276936bfAlex SakhartchoukFontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text, 1092416a847633680d94efb926837efdc18726d54918Raph Levien uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius, const float* positions) { 10931e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy checkInit(); 10941e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 10951e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (!mCurrentFont) { 10961e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy DropShadow image; 10971e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.width = 0; 10981e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.height = 0; 10991e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.image = NULL; 11001e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.penX = 0; 11011e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.penY = 0; 11021e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy return image; 11031e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } 1104f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 11052d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy mDrawn = false; 1106ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy mClip = NULL; 1107ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy mBounds = NULL; 1108ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 1109f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk Rect bounds; 1110416a847633680d94efb926837efdc18726d54918Raph Levien mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions); 1111ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 11121e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius; 11131e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius; 1114f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight]; 1115ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 11161e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy for (uint32_t i = 0; i < paddedWidth * paddedHeight; i++) { 1117f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk dataBuffer[i] = 0; 1118f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 11191e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1120f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int penX = radius - bounds.left; 1121f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int penY = radius - bounds.bottom; 1122f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 1123726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY, 1124416a847633680d94efb926837efdc18726d54918Raph Levien Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions); 1125f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk blurImage(dataBuffer, paddedWidth, paddedHeight, radius); 1126f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 1127f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk DropShadow image; 1128f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.width = paddedWidth; 1129f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.height = paddedHeight; 1130f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.image = dataBuffer; 1131f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.penX = penX; 1132f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.penY = penY; 11332d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy 1134f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk return image; 1135f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 1136694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1137671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid FontRenderer::initRender(const Rect* clip, Rect* bounds) { 1138694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy checkInit(); 1139694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 11405b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mDrawn = false; 11415b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds = bounds; 114209147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy mClip = clip; 1143671d6cf460531825a321edb200523d0faa7792c9Romain Guy} 1144ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 1145671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid FontRenderer::finishRender() { 11465b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds = NULL; 1147ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy mClip = NULL; 1148694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1149694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex != 0) { 1150694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 1151694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 1152694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 1153671d6cf460531825a321edb200523d0faa7792c9Romain Guy} 1154671d6cf460531825a321edb200523d0faa7792c9Romain Guy 1155e816baea651476aca4407200d4a5e629b9ab8dfaChet Haasevoid FontRenderer::precache(SkPaint* paint, const char* text, int numGlyphs) { 1156e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase int flags = 0; 1157e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (paint->isFakeBoldText()) { 1158e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase flags |= Font::kFakeBold; 1159e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 1160e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase const float skewX = paint->getTextSkewX(); 1161e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase uint32_t italicStyle = *(uint32_t*) &skewX; 1162e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase const float scaleXFloat = paint->getTextScaleX(); 1163e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase uint32_t scaleX = *(uint32_t*) &scaleXFloat; 1164e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase SkPaint::Style style = paint->getStyle(); 1165e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase const float strokeWidthFloat = paint->getStrokeWidth(); 1166e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase uint32_t strokeWidth = *(uint32_t*) &strokeWidthFloat; 1167e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase float fontSize = paint->getTextSize(); 1168e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase Font* font = Font::create(this, SkTypeface::UniqueID(paint->getTypeface()), 1169e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase fontSize, flags, italicStyle, scaleX, style, strokeWidth); 1170e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase 1171e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase font->precache(paint, text, numGlyphs); 1172e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase} 1173e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase 1174671d6cf460531825a321edb200523d0faa7792c9Romain Guybool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text, 1175671d6cf460531825a321edb200523d0faa7792c9Romain Guy uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, Rect* bounds) { 1176671d6cf460531825a321edb200523d0faa7792c9Romain Guy if (!mCurrentFont) { 1177671d6cf460531825a321edb200523d0faa7792c9Romain Guy ALOGE("No font set"); 1178671d6cf460531825a321edb200523d0faa7792c9Romain Guy return false; 1179671d6cf460531825a321edb200523d0faa7792c9Romain Guy } 1180671d6cf460531825a321edb200523d0faa7792c9Romain Guy 1181671d6cf460531825a321edb200523d0faa7792c9Romain Guy initRender(clip, bounds); 1182671d6cf460531825a321edb200523d0faa7792c9Romain Guy mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y); 1183671d6cf460531825a321edb200523d0faa7792c9Romain Guy finishRender(); 1184671d6cf460531825a321edb200523d0faa7792c9Romain Guy 1185671d6cf460531825a321edb200523d0faa7792c9Romain Guy return mDrawn; 1186671d6cf460531825a321edb200523d0faa7792c9Romain Guy} 1187671d6cf460531825a321edb200523d0faa7792c9Romain Guy 1188671d6cf460531825a321edb200523d0faa7792c9Romain Guybool FontRenderer::renderPosText(SkPaint* paint, const Rect* clip, const char *text, 1189671d6cf460531825a321edb200523d0faa7792c9Romain Guy uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, 1190671d6cf460531825a321edb200523d0faa7792c9Romain Guy const float* positions, Rect* bounds) { 1191671d6cf460531825a321edb200523d0faa7792c9Romain Guy if (!mCurrentFont) { 1192671d6cf460531825a321edb200523d0faa7792c9Romain Guy ALOGE("No font set"); 1193671d6cf460531825a321edb200523d0faa7792c9Romain Guy return false; 1194671d6cf460531825a321edb200523d0faa7792c9Romain Guy } 1195671d6cf460531825a321edb200523d0faa7792c9Romain Guy 1196671d6cf460531825a321edb200523d0faa7792c9Romain Guy initRender(clip, bounds); 1197671d6cf460531825a321edb200523d0faa7792c9Romain Guy mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions); 1198671d6cf460531825a321edb200523d0faa7792c9Romain Guy finishRender(); 11995b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 12005b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy return mDrawn; 12019777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy} 12029777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 12039777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guybool FontRenderer::renderTextOnPath(SkPaint* paint, const Rect* clip, const char *text, 12049777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy uint32_t startIndex, uint32_t len, int numGlyphs, SkPath* path, 12059777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float hOffset, float vOffset, Rect* bounds) { 12069777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (!mCurrentFont) { 12079777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy ALOGE("No font set"); 12089777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy return false; 12099777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 12109777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 12119777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy initRender(clip, bounds); 12129777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset); 12139777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy finishRender(); 12149777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 12159777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy return mDrawn; 1216694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 1217694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 121889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::computeGaussianWeights(float* weights, int32_t radius) { 121989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Compute gaussian weights for the blur 122089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // e is the euler's number 122189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float e = 2.718281828459045f; 122289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float pi = 3.1415926535897932f; 122389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 ) 122489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // x is of the form [-radius .. 0 .. radius] 122589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // and sigma varies with radius. 122689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Based on some experimental radius values and sigma's 122789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // we approximately fit sigma = f(radius) as 1228f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk // sigma = radius * 0.3 + 0.6 122989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // The larger the radius gets, the more our gaussian blur 123089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // will resemble a box blur since with large sigma 123189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // the gaussian curve begins to lose its shape 1232325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy float sigma = 0.3f * (float) radius + 0.6f; 123389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 123489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Now compute the coefficints 123589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // We will store some redundant values to save some math during 123689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // the blur calculations 123789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // precompute some values 123889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma); 123989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float coeff2 = - 1.0f / (2.0f * sigma * sigma); 124089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 124189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float normalizeFactor = 0.0f; 1242325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 12437975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy float floatR = (float) r; 124489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2); 124589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk normalizeFactor += weights[r + radius]; 124689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 124789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 124889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk //Now we need to normalize the weights because all our coefficients need to add up to one 124989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk normalizeFactor = 1.0f / normalizeFactor; 1250325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 125189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk weights[r + radius] *= normalizeFactor; 125289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 125389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 125489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 125589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::horizontalBlur(float* weights, int32_t radius, 12561e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) { 125789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float blurredPixel = 0.0f; 125889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float currentPixel = 0.0f; 125989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1260325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t y = 0; y < height; y ++) { 126189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 126289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* input = source + y * width; 126389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* output = dest + y * width; 126489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1265325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t x = 0; x < width; x ++) { 126689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel = 0.0f; 126789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const float* gPtr = weights; 126889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Optimization for non-border pixels 1269325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (x > radius && x < (width - radius)) { 127089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + (x - radius); 1271325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int r = -radius; r <= radius; r ++) { 12727975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy currentPixel = (float) (*i); 127389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 127489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 127589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk i++; 127689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 127789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } else { 1278325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 127989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Stepping left and right away from the pixel 128089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int validW = x + r; 1281325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validW < 0) { 128289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validW = 0; 128389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 1284325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validW > width - 1) { 128589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validW = width - 1; 128689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 128789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1288325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy currentPixel = (float) input[validW]; 128989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 129089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 129189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 129289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 129389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk *output = (uint8_t)blurredPixel; 129489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk output ++; 129589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 129689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 129789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 129889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 129989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::verticalBlur(float* weights, int32_t radius, 13001e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) { 130189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float blurredPixel = 0.0f; 130289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float currentPixel = 0.0f; 130389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1304325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t y = 0; y < height; y ++) { 130589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 130689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* output = dest + y * width; 130789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1308325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t x = 0; x < width; x ++) { 130989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel = 0.0f; 131089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const float* gPtr = weights; 131189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* input = source + x; 131289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Optimization for non-border pixels 1313325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (y > radius && y < (height - radius)) { 131489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + ((y - radius) * width); 1315325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 131689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk currentPixel = (float)(*i); 131789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 131889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 131989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk i += width; 132089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 132189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } else { 1322325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 132389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int validH = y + r; 132489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Clamp to zero and width 1325325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validH < 0) { 132689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validH = 0; 132789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 1328325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validH > height - 1) { 132989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validH = height - 1; 133089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 133189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 133289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + validH * width; 1333325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy currentPixel = (float) (*i); 133489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 133589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 133689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 133789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 1338325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy *output = (uint8_t) blurredPixel; 133989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk output ++; 134089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 134189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 134289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 134389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 134489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 134589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::blurImage(uint8_t *image, int32_t width, int32_t height, int32_t radius) { 134689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float *gaussian = new float[2 * radius + 1]; 134789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk computeGaussianWeights(gaussian, radius); 1348d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy 134989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* scratch = new uint8_t[width * height]; 1350d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy 135189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk horizontalBlur(gaussian, radius, image, scratch, width, height); 135289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk verticalBlur(gaussian, radius, scratch, image, width, height); 1353d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy 135489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk delete[] gaussian; 135589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk delete[] scratch; 135689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 135789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1358694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace uirenderer 1359694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace android 1360