FontRenderer.cpp revision e816baea651476aca4407200d4a5e629b9ab8dfa
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/////////////////////////////////////////////////////////////////////////////// 1127de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase// CacheTextureLine 1137de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase/////////////////////////////////////////////////////////////////////////////// 1147de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 1157de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasebool CacheTextureLine::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) { 1167de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (glyph.fHeight + TEXTURE_BORDER_SIZE > mMaxHeight) { 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; 141e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase *retOriginY = mCurrentRow + 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; 149e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (mMaxHeight - glyphH >= glyphH) { 150e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase // There's enough height left over to create a new CacheBlock 151e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase CacheBlock *newBlock = new CacheBlock(oldX, glyphH, roundedUpW, 152e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase mMaxHeight - 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 2169a8245629d69d81e0b62e52970feaf9c02580e75Chet Haasevoid Font::invalidateTextureCache(CacheTextureLine *cacheLine) { 217694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) { 2189a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueAt(i); 2199a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase if (cacheLine == NULL || cachedGlyph->mCachedTextureLine == cacheLine) { 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, 2637de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase nPenX, nPenY - height, u1, v1, glyph->mCachedTextureLine->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 2747de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase CacheTexture *cacheTexture = glyph->mCachedTextureLine->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, 3289777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy glyph->mCachedTextureLine->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 5597de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint32_t cacheWidth = glyph->mCachedTextureLine->mCacheTexture->mWidth; 5607de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint32_t cacheHeight = glyph->mCachedTextureLine->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; 6237de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTextureSmall = NULL; 6247de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTexture128 = NULL; 6257de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTexture256 = NULL; 6267de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTexture512 = NULL; 6279cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy 6282a47c14e2a6f152496b43104bc785c488583fd59Chet Haase mLinearFiltering = false; 6292a47c14e2a6f152496b43104bc785c488583fd59Chet Haase 630694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mIndexBufferID = 0; 631694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 6327de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mSmallCacheWidth = DEFAULT_TEXT_CACHE_WIDTH; 6337de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mSmallCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT; 63451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 63551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy char property[PROPERTY_VALUE_MAX]; 63651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) { 637c9855a53edfac818dc68714557185977556f849dRomain Guy if (sLogFontRendererCreate) { 638c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD(" Setting text cache width to %s pixels", property); 639c9855a53edfac818dc68714557185977556f849dRomain Guy } 6407de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mSmallCacheWidth = atoi(property); 64151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } else { 642514fb18827186591d66973c2362c859b64b63556Romain Guy if (sLogFontRendererCreate) { 6437de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase INIT_LOGD(" Using default text cache width of %i pixels", mSmallCacheWidth); 644514fb18827186591d66973c2362c859b64b63556Romain Guy } 64551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } 64651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 64751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy if (property_get(PROPERTY_TEXT_CACHE_HEIGHT, property, NULL) > 0) { 648c9855a53edfac818dc68714557185977556f849dRomain Guy if (sLogFontRendererCreate) { 649c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD(" Setting text cache width to %s pixels", property); 650c9855a53edfac818dc68714557185977556f849dRomain Guy } 6517de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mSmallCacheHeight = atoi(property); 65251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } else { 653514fb18827186591d66973c2362c859b64b63556Romain Guy if (sLogFontRendererCreate) { 6547de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase INIT_LOGD(" Using default text cache height of %i pixels", mSmallCacheHeight); 655514fb18827186591d66973c2362c859b64b63556Romain Guy } 65651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } 657514fb18827186591d66973c2362c859b64b63556Romain Guy 658514fb18827186591d66973c2362c859b64b63556Romain Guy sLogFontRendererCreate = false; 659694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 660694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 661694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::~FontRenderer() { 662694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 663694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy delete mCacheLines[i]; 664694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 665694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCacheLines.clear(); 666694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 6679cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy if (mInitialized) { 668a9dd820184ee4d083bd9b2af735dcf50b78fc6cdRomain Guy // Unbinding the buffer shouldn't be necessary but it crashes with some drivers 669a9dd820184ee4d083bd9b2af735dcf50b78fc6cdRomain Guy Caches::getInstance().unbindIndicesBuffer(); 670b0317984d34da99b614597ad0a8b39268eacb783Romain Guy glDeleteBuffers(1, &mIndexBufferID); 671b0317984d34da99b614597ad0a8b39268eacb783Romain Guy 6729cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy delete[] mTextMeshPtr; 6737de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase delete mCacheTextureSmall; 6747de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase delete mCacheTexture128; 6757de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase delete mCacheTexture256; 6767de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase delete mCacheTexture512; 6779b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 678694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 679694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy Vector<Font*> fontsToDereference = mActiveFonts; 680694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < fontsToDereference.size(); i++) { 681694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy delete fontsToDereference[i]; 682694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 683694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 684694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 685694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::flushAllAndInvalidate() { 686694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex != 0) { 687694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 688694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 689694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 6909d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 691694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mActiveFonts.size(); i++) { 692694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mActiveFonts[i]->invalidateTextureCache(); 693694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 6949d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 695e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase uint16_t totalGlyphs = 0; 696694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 697e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase totalGlyphs += mCacheLines[i]->mNumGlyphs; 698e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase mCacheLines[i]->init(); 699e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 700e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase 701e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#if DEBUG_FONT_RENDERER 702e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase ALOGD("FontRenderer: flushAllAndInvalidatel"); 703e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase // Erase caches, just as a debugging facility 704e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (mCacheTextureSmall && mCacheTextureSmall->mTexture) { 705e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase memset(mCacheTextureSmall->mTexture, 0, 706e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase mCacheTextureSmall->mWidth * mCacheTextureSmall->mHeight); 707e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 708e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (mCacheTexture128 && mCacheTexture128->mTexture) { 709e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase memset(mCacheTexture128->mTexture, 0, 710e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase mCacheTexture128->mWidth * mCacheTexture128->mHeight); 711694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 712e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (mCacheTexture256 && mCacheTexture256->mTexture) { 713e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase memset(mCacheTexture256->mTexture, 0, 714e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase mCacheTexture256->mWidth * mCacheTexture256->mHeight); 715e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 716e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (mCacheTexture512 && mCacheTexture512->mTexture) { 717e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase memset(mCacheTexture512->mTexture, 0, 718e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase mCacheTexture512->mWidth * mCacheTexture512->mHeight); 719e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 720e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase ALOGD("Flushing caches: glyphs cached = %d", totalGlyphs); 721e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif 722694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 723694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 7249a8245629d69d81e0b62e52970feaf9c02580e75Chet Haasevoid FontRenderer::deallocateTextureMemory(CacheTexture *cacheTexture) { 7259a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase if (cacheTexture && cacheTexture->mTexture) { 7269a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase glDeleteTextures(1, &cacheTexture->mTextureId); 7279d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy delete[] cacheTexture->mTexture; 7289a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase cacheTexture->mTexture = NULL; 72999a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy cacheTexture->mTextureId = 0; 7309a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase } 7319a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase} 7329a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase 7339a8245629d69d81e0b62e52970feaf9c02580e75Chet Haasevoid FontRenderer::flushLargeCaches() { 7349a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase if ((!mCacheTexture128 || !mCacheTexture128->mTexture) && 7359a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase (!mCacheTexture256 || !mCacheTexture256->mTexture) && 7369a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase (!mCacheTexture512 || !mCacheTexture512->mTexture)) { 7379a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase // Typical case; no large glyph caches allocated 7389a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase return; 7399a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase } 7409a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase 7419a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase for (uint32_t i = 0; i < mCacheLines.size(); i++) { 7429a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase CacheTextureLine* cacheLine = mCacheLines[i]; 7439a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase if ((cacheLine->mCacheTexture == mCacheTexture128 || 7449a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase cacheLine->mCacheTexture == mCacheTexture256 || 7459a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase cacheLine->mCacheTexture == mCacheTexture512) && 7469a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase cacheLine->mCacheTexture->mTexture != NULL) { 747e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#if DEBUG_FONT_RENDERER 748e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (cacheLine->mCacheTexture == mCacheTexture128) { 749e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase ALOGD("flushing cacheTexture128"); 750e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } else if (cacheLine->mCacheTexture == mCacheTexture256) { 751e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase ALOGD("flushing cacheTexture256"); 752e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } else { 753e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase ALOGD("flushing cacheTexture512"); 754e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 755e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif 756e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase cacheLine->init(); 7579a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase for (uint32_t i = 0; i < mActiveFonts.size(); i++) { 7589a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase mActiveFonts[i]->invalidateTextureCache(cacheLine); 7599a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase } 7609a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase } 7619a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase } 7629a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase 7639a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase deallocateTextureMemory(mCacheTexture128); 7649a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase deallocateTextureMemory(mCacheTexture256); 7659a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase deallocateTextureMemory(mCacheTexture512); 7669a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase} 7679a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase 7689d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guyvoid FontRenderer::allocateTextureMemory(CacheTexture* cacheTexture) { 7692a47c14e2a6f152496b43104bc785c488583fd59Chet Haase int width = cacheTexture->mWidth; 7702a47c14e2a6f152496b43104bc785c488583fd59Chet Haase int height = cacheTexture->mHeight; 7719d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 7722a47c14e2a6f152496b43104bc785c488583fd59Chet Haase cacheTexture->mTexture = new uint8_t[width * height]; 77399a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy 77499a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy if (!cacheTexture->mTextureId) { 77599a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy glGenTextures(1, &cacheTexture->mTextureId); 77699a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy } 7779d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 77816c88085255c71a1a8fc034129aa2dcc61e1ddd0Romain Guy Caches::getInstance().activeTexture(0); 7792a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId); 7802a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 7812a47c14e2a6f152496b43104bc785c488583fd59Chet Haase // Initialize texture dimensions 7822a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, 7832a47c14e2a6f152496b43104bc785c488583fd59Chet Haase GL_ALPHA, GL_UNSIGNED_BYTE, 0); 7842a47c14e2a6f152496b43104bc785c488583fd59Chet Haase 7852a47c14e2a6f152496b43104bc785c488583fd59Chet Haase const GLenum filtering = cacheTexture->mLinearFiltering ? GL_LINEAR : GL_NEAREST; 7862a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); 7872a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); 7887de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 7892a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 7902a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 7917de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase} 7927de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 7937de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasevoid FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph, 7947de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint32_t* retOriginX, uint32_t* retOriginY) { 7957de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase cachedGlyph->mIsValid = false; 796694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If the glyph is too tall, don't cache it 797e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (mCacheLines.size() == 0 || 798e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) { 799e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (mCacheLines.size() != 0) { 800e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase ALOGE("Font size too large to fit in cache. width, height = %i, %i", 801e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase (int) glyph.fWidth, (int) glyph.fHeight); 802e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 8037de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase return; 804694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 805694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 806694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Now copy the bitmap into the cache texture 807694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startX = 0; 808694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startY = 0; 809694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 810694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bool bitmapFit = false; 8117de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase CacheTextureLine *cacheLine; 812694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 813694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY); 814694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (bitmapFit) { 8157de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase cacheLine = mCacheLines[i]; 816694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 817694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 818694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 819694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 820694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If the new glyph didn't fit, flush the state so far and invalidate everything 821694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!bitmapFit) { 822694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy flushAllAndInvalidate(); 823694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 824694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Try to fit it again 825694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 826694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY); 827694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (bitmapFit) { 8287de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase cacheLine = mCacheLines[i]; 829694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 830694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 831694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 832694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 833694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // if we still don't fit, something is wrong and we shouldn't draw 834694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!bitmapFit) { 8357de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase return; 836694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 837694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 838694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 8397de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase cachedGlyph->mCachedTextureLine = cacheLine; 8407de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 841694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *retOriginX = startX; 842694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *retOriginY = startY; 843694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 844694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endX = startX + glyph.fWidth; 845694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endY = startY + glyph.fHeight; 846694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 8477de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint32_t cacheWidth = cacheLine->mMaxWidth; 848694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 8499d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy CacheTexture* cacheTexture = cacheLine->mCacheTexture; 8509d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy if (!cacheTexture->mTexture) { 8517de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // Large-glyph texture memory is allocated only as needed 8522a47c14e2a6f152496b43104bc785c488583fd59Chet Haase allocateTextureMemory(cacheTexture); 8537de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 8549d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 8557de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint8_t* cacheBuffer = cacheTexture->mTexture; 85689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage; 857694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy unsigned int stride = glyph.rowBytes(); 858694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 859694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; 86033fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy 86133fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy for (cacheX = startX - TEXTURE_BORDER_SIZE; cacheX < endX + TEXTURE_BORDER_SIZE; cacheX++) { 86233fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy cacheBuffer[(startY - TEXTURE_BORDER_SIZE) * cacheWidth + cacheX] = 0; 86333fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy cacheBuffer[(endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + cacheX] = 0; 86433fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy } 86533fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy 86633fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy for (cacheY = startY - TEXTURE_BORDER_SIZE + 1; 86733fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy cacheY < endY + TEXTURE_BORDER_SIZE - 1; cacheY++) { 86833fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy cacheBuffer[cacheY * cacheWidth + startX - TEXTURE_BORDER_SIZE] = 0; 86933fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy cacheBuffer[cacheY * cacheWidth + endX + TEXTURE_BORDER_SIZE - 1] = 0; 87033fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy } 87133fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy 872b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy if (mGammaTable) { 873b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) { 874b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) { 875b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy uint8_t tempCol = bitmapBuffer[bY * stride + bX]; 876b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol]; 877b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy } 878b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy } 879b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy } else { 880b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) { 881b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) { 882b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy uint8_t tempCol = bitmapBuffer[bY * stride + bX]; 883b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy cacheBuffer[cacheY * cacheWidth + cacheX] = tempCol; 884b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy } 885694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 886694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 8879777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 8887de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase cachedGlyph->mIsValid = true; 889694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 890694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 8917de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet HaaseCacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) { 8920aa87bbfc41e8b5f52de701ac17b4e66a7a7b609Romain Guy CacheTexture* cacheTexture = new CacheTexture(width, height); 8939d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 8942a47c14e2a6f152496b43104bc785c488583fd59Chet Haase if (allocate) { 8952a47c14e2a6f152496b43104bc785c488583fd59Chet Haase allocateTextureMemory(cacheTexture); 8962a47c14e2a6f152496b43104bc785c488583fd59Chet Haase } 8979d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 8982a47c14e2a6f152496b43104bc785c488583fd59Chet Haase return cacheTexture; 8997de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase} 9007de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 9017de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasevoid FontRenderer::initTextTexture() { 9029d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 9039d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy delete mCacheLines[i]; 9049d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy } 9057de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.clear(); 9067de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 9079d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy if (mCacheTextureSmall) { 9089d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy delete mCacheTextureSmall; 9099d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy delete mCacheTexture128; 9109d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy delete mCacheTexture256; 9119d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy delete mCacheTexture512; 9129d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy } 9139d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 9147de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // Next, use other, separate caches for large glyphs. 9157de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint16_t maxWidth = 0; 9167de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (Caches::hasInstance()) { 9177de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase maxWidth = Caches::getInstance().maxTextureSize; 9187de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 9199d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 9207de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (maxWidth > MAX_TEXT_CACHE_WIDTH || maxWidth == 0) { 9217de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase maxWidth = MAX_TEXT_CACHE_WIDTH; 9227de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 9239d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 9247de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTextureSmall = createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true); 9257de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTexture128 = createCacheTexture(maxWidth, 256, false); 9267de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTexture256 = createCacheTexture(maxWidth, 256, false); 9277de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTexture512 = createCacheTexture(maxWidth, 512, false); 9287de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCurrentCacheTexture = mCacheTextureSmall; 9297de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 9307de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mUploadTexture = false; 9317de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // Split up our default cache texture into lines of certain widths 932694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int nextLine = 0; 933e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 18, nextLine, mCacheTextureSmall)); 934694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 935e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, mCacheTextureSmall)); 936694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 937e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, mCacheTextureSmall)); 93865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk nextLine += mCacheLines.top()->mMaxHeight; 939e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, mCacheTextureSmall)); 940694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 941e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, mCacheTextureSmall)); 942694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 943e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 42, nextLine, mCacheTextureSmall)); 944694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 9457de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, mSmallCacheHeight - nextLine, 946e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase nextLine, mCacheTextureSmall)); 9477de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 9487de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // The first cache is split into 2 lines of height 128, the rest have just one cache line. 949e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase mCacheLines.push(new CacheTextureLine(maxWidth, 128, 0, mCacheTexture128)); 950e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase mCacheLines.push(new CacheTextureLine(maxWidth, 128, 128, mCacheTexture128)); 951e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase mCacheLines.push(new CacheTextureLine(maxWidth, 256, 0, mCacheTexture256)); 952e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase mCacheLines.push(new CacheTextureLine(maxWidth, 512, 0, mCacheTexture512)); 953694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 954694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 955694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Avoid having to reallocate memory and render quad by quad 956694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::initVertexArrayBuffers() { 957d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy uint32_t numIndices = mMaxNumberOfQuads * 6; 958d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy uint32_t indexBufferSizeBytes = numIndices * sizeof(uint16_t); 95951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes); 960694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 961694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Four verts, two triangles , six indices per quad 962694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mMaxNumberOfQuads; i++) { 963694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int i6 = i * 6; 964694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int i4 = i * 4; 965694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 966694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 0] = i4 + 0; 967694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 1] = i4 + 1; 968694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 2] = i4 + 2; 969694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 970694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 3] = i4 + 0; 971694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 4] = i4 + 2; 972694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 5] = i4 + 3; 973694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 974694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 975694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glGenBuffers(1, &mIndexBufferID); 97615bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy Caches::getInstance().bindIndicesBuffer(mIndexBufferID); 9775d794412e3e429e47404395badcd11b0b8639e8bRomain Guy glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_STATIC_DRAW); 978694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 979694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy free(indexBufferData); 980694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 981d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy uint32_t coordSize = 2; 982694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t uvSize = 2; 983694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t vertsPerQuad = 4; 9849b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize; 9859b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mTextMeshPtr = new float[vertexBufferSize]; 986694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 987694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 988694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// We don't want to allocate anything unless we actually draw text 989694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::checkInit() { 990694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mInitialized) { 991694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 992694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 993694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 994694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy initTextTexture(); 995694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy initVertexArrayBuffers(); 996694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 997694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mInitialized = true; 998694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 999694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 10009b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::checkTextureUpdate() { 10017de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (!mUploadTexture && mLastCacheTexture == mCurrentCacheTexture) { 10029b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk return; 10039b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 10049b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 10052d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy Caches& caches = Caches::getInstance(); 10062d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy GLuint lastTextureId = 0; 10079b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk // Iterate over all the cache lines and see which ones need to be updated 10089b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk for (uint32_t i = 0; i < mCacheLines.size(); i++) { 10099b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk CacheTextureLine* cl = mCacheLines[i]; 10107de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (cl->mDirty && cl->mCacheTexture->mTexture != NULL) { 10117de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase CacheTexture* cacheTexture = cl->mCacheTexture; 10129b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t xOffset = 0; 10139b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t yOffset = cl->mCurrentRow; 10147de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint32_t width = cl->mMaxWidth; 10159b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t height = cl->mMaxHeight; 10167de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase void* textureData = cacheTexture->mTexture + (yOffset * width); 10179b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 10182d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy if (cacheTexture->mTextureId != lastTextureId) { 10192d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy caches.activeTexture(0); 10202d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId); 10212d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy lastTextureId = cacheTexture->mTextureId; 10222d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy } 1023e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#if DEBUG_FONT_RENDERER 1024e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase ALOGD("glTextSubimage for cacheLine %d: xOff, yOff, width height = %d, %d, %d, %d", i, 1025e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase xOffset, yOffset, width, height); 1026e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase#endif 10279b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height, 10281e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy GL_ALPHA, GL_UNSIGNED_BYTE, textureData); 10299b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 10309b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk cl->mDirty = false; 10319b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 1032694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 1033694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 103416c88085255c71a1a8fc034129aa2dcc61e1ddd0Romain Guy caches.activeTexture(0); 10357de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase glBindTexture(GL_TEXTURE_2D, mCurrentCacheTexture->mTextureId); 10362a47c14e2a6f152496b43104bc785c488583fd59Chet Haase if (mLinearFiltering != mCurrentCacheTexture->mLinearFiltering) { 10372a47c14e2a6f152496b43104bc785c488583fd59Chet Haase const GLenum filtering = mLinearFiltering ? GL_LINEAR : GL_NEAREST; 10382a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); 10392a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); 10402a47c14e2a6f152496b43104bc785c488583fd59Chet Haase mCurrentCacheTexture->mLinearFiltering = mLinearFiltering; 10412a47c14e2a6f152496b43104bc785c488583fd59Chet Haase } 10427de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mLastCacheTexture = mCurrentCacheTexture; 10437de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 10449b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mUploadTexture = false; 10459b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk} 10469b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 10479b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::issueDrawCommand() { 10489b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk checkTextureUpdate(); 10499b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 105015bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy Caches& caches = Caches::getInstance(); 10512d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy caches.bindIndicesBuffer(mIndexBufferID); 105215bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy if (!mDrawn) { 105315bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy float* buffer = mTextMeshPtr; 105415bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy int offset = 2; 105515bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy 105615bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy bool force = caches.unbindMeshBuffer(); 105715bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy caches.bindPositionVertexPointer(force, caches.currentProgram->position, buffer); 105815bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy caches.bindTexCoordsVertexPointer(force, caches.currentProgram->texCoords, 105915bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy buffer + offset); 106015bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy } 106115bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy 1062694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL); 10635b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 10645b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mDrawn = true; 1065694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 1066694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 10679777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1, 10689777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3, 10697de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase float x4, float y4, float u4, float v4, CacheTexture* texture) { 10707de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (texture != mCurrentCacheTexture) { 10717de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (mCurrentQuadIndex != 0) { 10727de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // First, draw everything stored already which uses the previous texture 10737de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase issueDrawCommand(); 10747de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCurrentQuadIndex = 0; 10757de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 10767de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // Now use the new texture id 10777de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCurrentCacheTexture = texture; 10787de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 107909147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy 1080694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy const uint32_t vertsPerQuad = 4; 1081d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy const uint32_t floatsPerVert = 4; 108251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float* currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert; 1083694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1084694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x1; 1085694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y1; 1086694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u1; 1087694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v1; 1088694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1089694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x2; 1090694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y2; 1091694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u2; 1092694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v2; 1093694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1094694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x3; 1095694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y3; 1096694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u3; 1097694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v3; 1098694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1099694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x4; 1100694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y4; 1101694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u4; 1102694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v4; 1103694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1104694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex++; 11059777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy} 11069777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 11079777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1, 11089777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3, 11099777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float x4, float y4, float u4, float v4, CacheTexture* texture) { 11109777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 11119777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (mClip && 11129777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) { 11139777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy return; 11149777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 11159777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 11169777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture); 1117694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 11185b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy if (mBounds) { 11195b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->left = fmin(mBounds->left, x1); 11205b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->top = fmin(mBounds->top, y3); 11215b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->right = fmax(mBounds->right, x3); 11225b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->bottom = fmax(mBounds->bottom, y1); 11235b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy } 11245b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 1125694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex == mMaxNumberOfQuads) { 1126694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 1127694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 1128694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 1129694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 1130694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 11319777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1, 11329777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3, 11339777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float x4, float y4, float u4, float v4, CacheTexture* texture) { 11349777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 11359777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture); 11369777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 11379777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (mBounds) { 11389777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mBounds->left = fmin(mBounds->left, fmin(x1, fmin(x2, fmin(x3, x4)))); 11399777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mBounds->top = fmin(mBounds->top, fmin(y1, fmin(y2, fmin(y3, y4)))); 11409777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mBounds->right = fmax(mBounds->right, fmax(x1, fmax(x2, fmax(x3, x4)))); 11419777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mBounds->bottom = fmax(mBounds->bottom, fmax(y1, fmax(y2, fmax(y3, y4)))); 11429777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 11439777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 11449777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (mCurrentQuadIndex == mMaxNumberOfQuads) { 11459777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy issueDrawCommand(); 11469777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mCurrentQuadIndex = 0; 11479777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 11489777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy} 11499777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 115065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) { 1151325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy int flags = 0; 1152325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (paint->isFakeBoldText()) { 1153325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy flags |= Font::kFakeBold; 1154325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy } 11552577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy 11562577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy const float skewX = paint->getTextSkewX(); 11572577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy uint32_t italicStyle = *(uint32_t*) &skewX; 11588668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase const float scaleXFloat = paint->getTextScaleX(); 11598668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase uint32_t scaleX = *(uint32_t*) &scaleXFloat; 1160bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy SkPaint::Style style = paint->getStyle(); 1161bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy const float strokeWidthFloat = paint->getStrokeWidth(); 1162bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy uint32_t strokeWidth = *(uint32_t*) &strokeWidthFloat; 1163bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle, 1164bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy scaleX, style, strokeWidth); 116565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 1166694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 11677975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy 1168f18136cb3c881a9d16c1a4f0f341732c276936bfAlex SakhartchoukFontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text, 1169416a847633680d94efb926837efdc18726d54918Raph Levien uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius, const float* positions) { 11701e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy checkInit(); 11711e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 11721e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (!mCurrentFont) { 11731e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy DropShadow image; 11741e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.width = 0; 11751e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.height = 0; 11761e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.image = NULL; 11771e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.penX = 0; 11781e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.penY = 0; 11791e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy return image; 11801e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } 1181f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 11822d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy mDrawn = false; 1183ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy mClip = NULL; 1184ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy mBounds = NULL; 1185ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 1186f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk Rect bounds; 1187416a847633680d94efb926837efdc18726d54918Raph Levien mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions); 1188ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 11891e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius; 11901e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius; 1191f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight]; 1192ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 11931e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy for (uint32_t i = 0; i < paddedWidth * paddedHeight; i++) { 1194f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk dataBuffer[i] = 0; 1195f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 11961e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1197f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int penX = radius - bounds.left; 1198f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int penY = radius - bounds.bottom; 1199f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 1200726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY, 1201416a847633680d94efb926837efdc18726d54918Raph Levien Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions); 1202f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk blurImage(dataBuffer, paddedWidth, paddedHeight, radius); 1203f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 1204f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk DropShadow image; 1205f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.width = paddedWidth; 1206f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.height = paddedHeight; 1207f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.image = dataBuffer; 1208f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.penX = penX; 1209f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.penY = penY; 12102d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy 1211f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk return image; 1212f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 1213694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1214671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid FontRenderer::initRender(const Rect* clip, Rect* bounds) { 1215694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy checkInit(); 1216694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 12175b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mDrawn = false; 12185b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds = bounds; 121909147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy mClip = clip; 1220671d6cf460531825a321edb200523d0faa7792c9Romain Guy} 1221ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 1222671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid FontRenderer::finishRender() { 12235b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds = NULL; 1224ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy mClip = NULL; 1225694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1226694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex != 0) { 1227694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 1228694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 1229694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 1230671d6cf460531825a321edb200523d0faa7792c9Romain Guy} 1231671d6cf460531825a321edb200523d0faa7792c9Romain Guy 1232e816baea651476aca4407200d4a5e629b9ab8dfaChet Haasevoid FontRenderer::precache(SkPaint* paint, const char* text, int numGlyphs) { 1233e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase int flags = 0; 1234e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase if (paint->isFakeBoldText()) { 1235e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase flags |= Font::kFakeBold; 1236e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase } 1237e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase const float skewX = paint->getTextSkewX(); 1238e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase uint32_t italicStyle = *(uint32_t*) &skewX; 1239e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase const float scaleXFloat = paint->getTextScaleX(); 1240e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase uint32_t scaleX = *(uint32_t*) &scaleXFloat; 1241e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase SkPaint::Style style = paint->getStyle(); 1242e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase const float strokeWidthFloat = paint->getStrokeWidth(); 1243e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase uint32_t strokeWidth = *(uint32_t*) &strokeWidthFloat; 1244e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase float fontSize = paint->getTextSize(); 1245e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase Font* font = Font::create(this, SkTypeface::UniqueID(paint->getTypeface()), 1246e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase fontSize, flags, italicStyle, scaleX, style, strokeWidth); 1247e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase 1248e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase font->precache(paint, text, numGlyphs); 1249e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase} 1250e816baea651476aca4407200d4a5e629b9ab8dfaChet Haase 1251671d6cf460531825a321edb200523d0faa7792c9Romain Guybool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text, 1252671d6cf460531825a321edb200523d0faa7792c9Romain Guy uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, Rect* bounds) { 1253671d6cf460531825a321edb200523d0faa7792c9Romain Guy if (!mCurrentFont) { 1254671d6cf460531825a321edb200523d0faa7792c9Romain Guy ALOGE("No font set"); 1255671d6cf460531825a321edb200523d0faa7792c9Romain Guy return false; 1256671d6cf460531825a321edb200523d0faa7792c9Romain Guy } 1257671d6cf460531825a321edb200523d0faa7792c9Romain Guy 1258671d6cf460531825a321edb200523d0faa7792c9Romain Guy initRender(clip, bounds); 1259671d6cf460531825a321edb200523d0faa7792c9Romain Guy mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y); 1260671d6cf460531825a321edb200523d0faa7792c9Romain Guy finishRender(); 1261671d6cf460531825a321edb200523d0faa7792c9Romain Guy 1262671d6cf460531825a321edb200523d0faa7792c9Romain Guy return mDrawn; 1263671d6cf460531825a321edb200523d0faa7792c9Romain Guy} 1264671d6cf460531825a321edb200523d0faa7792c9Romain Guy 1265671d6cf460531825a321edb200523d0faa7792c9Romain Guybool FontRenderer::renderPosText(SkPaint* paint, const Rect* clip, const char *text, 1266671d6cf460531825a321edb200523d0faa7792c9Romain Guy uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, 1267671d6cf460531825a321edb200523d0faa7792c9Romain Guy const float* positions, Rect* bounds) { 1268671d6cf460531825a321edb200523d0faa7792c9Romain Guy if (!mCurrentFont) { 1269671d6cf460531825a321edb200523d0faa7792c9Romain Guy ALOGE("No font set"); 1270671d6cf460531825a321edb200523d0faa7792c9Romain Guy return false; 1271671d6cf460531825a321edb200523d0faa7792c9Romain Guy } 1272671d6cf460531825a321edb200523d0faa7792c9Romain Guy 1273671d6cf460531825a321edb200523d0faa7792c9Romain Guy initRender(clip, bounds); 1274671d6cf460531825a321edb200523d0faa7792c9Romain Guy mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions); 1275671d6cf460531825a321edb200523d0faa7792c9Romain Guy finishRender(); 12765b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 12775b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy return mDrawn; 12789777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy} 12799777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 12809777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guybool FontRenderer::renderTextOnPath(SkPaint* paint, const Rect* clip, const char *text, 12819777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy uint32_t startIndex, uint32_t len, int numGlyphs, SkPath* path, 12829777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float hOffset, float vOffset, Rect* bounds) { 12839777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (!mCurrentFont) { 12849777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy ALOGE("No font set"); 12859777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy return false; 12869777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 12879777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 12889777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy initRender(clip, bounds); 12899777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset); 12909777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy finishRender(); 12919777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 12929777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy return mDrawn; 1293694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 1294694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 129589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::computeGaussianWeights(float* weights, int32_t radius) { 129689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Compute gaussian weights for the blur 129789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // e is the euler's number 129889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float e = 2.718281828459045f; 129989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float pi = 3.1415926535897932f; 130089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 ) 130189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // x is of the form [-radius .. 0 .. radius] 130289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // and sigma varies with radius. 130389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Based on some experimental radius values and sigma's 130489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // we approximately fit sigma = f(radius) as 1305f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk // sigma = radius * 0.3 + 0.6 130689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // The larger the radius gets, the more our gaussian blur 130789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // will resemble a box blur since with large sigma 130889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // the gaussian curve begins to lose its shape 1309325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy float sigma = 0.3f * (float) radius + 0.6f; 131089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 131189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Now compute the coefficints 131289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // We will store some redundant values to save some math during 131389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // the blur calculations 131489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // precompute some values 131589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma); 131689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float coeff2 = - 1.0f / (2.0f * sigma * sigma); 131789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 131889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float normalizeFactor = 0.0f; 1319325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 13207975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy float floatR = (float) r; 132189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2); 132289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk normalizeFactor += weights[r + radius]; 132389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 132489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 132589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk //Now we need to normalize the weights because all our coefficients need to add up to one 132689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk normalizeFactor = 1.0f / normalizeFactor; 1327325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 132889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk weights[r + radius] *= normalizeFactor; 132989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 133089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 133189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 133289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::horizontalBlur(float* weights, int32_t radius, 13331e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) { 133489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float blurredPixel = 0.0f; 133589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float currentPixel = 0.0f; 133689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1337325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t y = 0; y < height; y ++) { 133889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 133989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* input = source + y * width; 134089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* output = dest + y * width; 134189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1342325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t x = 0; x < width; x ++) { 134389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel = 0.0f; 134489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const float* gPtr = weights; 134589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Optimization for non-border pixels 1346325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (x > radius && x < (width - radius)) { 134789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + (x - radius); 1348325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int r = -radius; r <= radius; r ++) { 13497975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy currentPixel = (float) (*i); 135089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 135189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 135289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk i++; 135389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 135489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } else { 1355325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 135689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Stepping left and right away from the pixel 135789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int validW = x + r; 1358325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validW < 0) { 135989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validW = 0; 136089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 1361325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validW > width - 1) { 136289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validW = width - 1; 136389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 136489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1365325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy currentPixel = (float) input[validW]; 136689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 136789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 136889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 136989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 137089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk *output = (uint8_t)blurredPixel; 137189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk output ++; 137289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 137389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 137489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 137589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 137689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::verticalBlur(float* weights, int32_t radius, 13771e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) { 137889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float blurredPixel = 0.0f; 137989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float currentPixel = 0.0f; 138089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1381325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t y = 0; y < height; y ++) { 138289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 138389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* output = dest + y * width; 138489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1385325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t x = 0; x < width; x ++) { 138689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel = 0.0f; 138789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const float* gPtr = weights; 138889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* input = source + x; 138989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Optimization for non-border pixels 1390325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (y > radius && y < (height - radius)) { 139189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + ((y - radius) * width); 1392325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 139389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk currentPixel = (float)(*i); 139489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 139589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 139689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk i += width; 139789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 139889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } else { 1399325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 140089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int validH = y + r; 140189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Clamp to zero and width 1402325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validH < 0) { 140389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validH = 0; 140489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 1405325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validH > height - 1) { 140689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validH = height - 1; 140789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 140889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 140989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + validH * width; 1410325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy currentPixel = (float) (*i); 141189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 141289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 141389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 141489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 1415325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy *output = (uint8_t) blurredPixel; 141689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk output ++; 141789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 141889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 141989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 142089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 142189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 142289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::blurImage(uint8_t *image, int32_t width, int32_t height, int32_t radius) { 142389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float *gaussian = new float[2 * radius + 1]; 142489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk computeGaussianWeights(gaussian, radius); 1425d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy 142689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* scratch = new uint8_t[width * height]; 1427d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy 142889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk horizontalBlur(gaussian, radius, image, scratch, width, height); 142989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk verticalBlur(gaussian, radius, scratch, image, width, height); 1430d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy 143189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk delete[] gaussian; 143289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk delete[] scratch; 143389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 143489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1435694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace uirenderer 1436694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace android 1437