FontRenderer.cpp revision 33fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4
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 4033fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy#define TEXTURE_BORDER_SIZE 1 417de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 429777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy#define AUTO_KERN(prev, next) (((next) - (prev) + 32) >> 6 << 16) 439777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 447de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase/////////////////////////////////////////////////////////////////////////////// 457de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase// CacheTextureLine 467de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase/////////////////////////////////////////////////////////////////////////////// 477de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 487de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasebool CacheTextureLine::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) { 497de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (glyph.fHeight + TEXTURE_BORDER_SIZE > mMaxHeight) { 507de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase return false; 517de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 527de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 5333fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy if (mCurrentCol + glyph.fWidth + TEXTURE_BORDER_SIZE * 2 < mMaxWidth) { 5433fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy *retOriginX = mCurrentCol + TEXTURE_BORDER_SIZE; 5533fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy *retOriginY = mCurrentRow + TEXTURE_BORDER_SIZE; 5633fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy mCurrentCol += glyph.fWidth + TEXTURE_BORDER_SIZE * 2; 577de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mDirty = true; 587de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase return true; 597de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 607de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 617de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase return false; 627de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase} 6344984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase 6451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy/////////////////////////////////////////////////////////////////////////////// 65694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Font 66694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 67694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 682577db1ec135a1470a2c42139772ec97a6c30e78Romain GuyFont::Font(FontRenderer* state, uint32_t fontId, float fontSize, 69bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy int flags, uint32_t italicStyle, uint32_t scaleX, 70bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy SkPaint::Style style, uint32_t strokeWidth) : 712577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy mState(state), mFontId(fontId), mFontSize(fontSize), 72bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy mFlags(flags), mItalicStyle(italicStyle), mScaleX(scaleX), 73bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy mStyle(style), mStrokeWidth(mStrokeWidth) { 74694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 75694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 76694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 77694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFont::~Font() { 78694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t ct = 0; ct < mState->mActiveFonts.size(); ct++) { 79694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mState->mActiveFonts[ct] == this) { 80694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mState->mActiveFonts.removeAt(ct); 81694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 82694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 83694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 84694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 85694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) { 86726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy delete mCachedGlyphs.valueAt(i); 87694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 88694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 89694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 909a8245629d69d81e0b62e52970feaf9c02580e75Chet Haasevoid Font::invalidateTextureCache(CacheTextureLine *cacheLine) { 91694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) { 929a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueAt(i); 939a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase if (cacheLine == NULL || cachedGlyph->mCachedTextureLine == cacheLine) { 949a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase cachedGlyph->mIsValid = false; 959a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase } 96694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 97694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 98694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 99671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y, 100671d6cf460531825a321edb200523d0faa7792c9Romain Guy uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) { 101f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int nPenX = x + glyph->mBitmapLeft; 102f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int nPenY = y + glyph->mBitmapTop; 103f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 104f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int width = (int) glyph->mBitmapWidth; 105f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int height = (int) glyph->mBitmapHeight; 106f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 10761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->bottom > nPenY) { 108f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->bottom = nPenY; 109f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 11061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->left > nPenX) { 111f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->left = nPenX; 112f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 11361c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->right < nPenX + width) { 114f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->right = nPenX + width; 115f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 11661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds->top < nPenY + height) { 117f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->top = nPenY + height; 118f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 119f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 120f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 121671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, 122671d6cf460531825a321edb200523d0faa7792c9Romain Guy uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) { 123694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int nPenX = x + glyph->mBitmapLeft; 124694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int nPenY = y + glyph->mBitmapTop + glyph->mBitmapHeight; 125694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 12651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float u1 = glyph->mBitmapMinU; 12751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float u2 = glyph->mBitmapMaxU; 12851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float v1 = glyph->mBitmapMinV; 12951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float v2 = glyph->mBitmapMaxV; 13051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 13151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy int width = (int) glyph->mBitmapWidth; 13251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy int height = (int) glyph->mBitmapHeight; 13351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 134d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy mState->appendMeshQuad(nPenX, nPenY, u1, v2, 135d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy nPenX + width, nPenY, u2, v2, 136d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy nPenX + width, nPenY - height, u2, v1, 1377de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase nPenX, nPenY - height, u1, v1, glyph->mCachedTextureLine->mCacheTexture); 138694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 139694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 140671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, 141671d6cf460531825a321edb200523d0faa7792c9Romain Guy uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) { 14289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int nPenX = x + glyph->mBitmapLeft; 14389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int nPenY = y + glyph->mBitmapTop; 14489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 14589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint32_t endX = glyph->mStartX + glyph->mBitmapWidth; 14689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint32_t endY = glyph->mStartY + glyph->mBitmapHeight; 14789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1487de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase CacheTexture *cacheTexture = glyph->mCachedTextureLine->mCacheTexture; 1497de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint32_t cacheWidth = cacheTexture->mWidth; 1507de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase const uint8_t* cacheBuffer = cacheTexture->mTexture; 15189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 152f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk uint32_t cacheX = 0, cacheY = 0; 153f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int32_t bX = 0, bY = 0; 15489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) { 15589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) { 156b629490ffb21752750cc081827ca4c1eae1eb015Romain Guy#if DEBUG_FONT_RENDERER 157b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) { 1583762c311729fe9f3af085c14c5c1fb471d994c03Steve Block ALOGE("Skipping invalid index"); 159f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk continue; 160f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 161b629490ffb21752750cc081827ca4c1eae1eb015Romain Guy#endif 16289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX]; 16389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk bitmap[bY * bitmapW + bX] = tempCol; 16489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 16589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 16689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 16789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1689777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset, 1699777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy SkPathMeasure& measure, SkPoint* position, SkVector* tangent) { 1709777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy const float halfWidth = glyph->mBitmapWidth * 0.5f; 1719777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy const float height = glyph->mBitmapHeight; 1729777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 1739777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy vOffset += glyph->mBitmapTop + height; 1749777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 1759777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy SkPoint destination[4]; 176dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy measure.getPosTan(x + hOffset + glyph->mBitmapLeft + halfWidth, position, tangent); 1779777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 1789777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy // Move along the tangent and offset by the normal 1799777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy destination[0].set(-tangent->fX * halfWidth - tangent->fY * vOffset, 1809777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy -tangent->fY * halfWidth + tangent->fX * vOffset); 1819777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy destination[1].set(tangent->fX * halfWidth - tangent->fY * vOffset, 1829777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy tangent->fY * halfWidth + tangent->fX * vOffset); 1839777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy destination[2].set(destination[1].fX + tangent->fY * height, 1849777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy destination[1].fY - tangent->fX * height); 1859777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy destination[3].set(destination[0].fX + tangent->fY * height, 1869777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy destination[0].fY - tangent->fX * height); 1879777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 188dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy const float u1 = glyph->mBitmapMinU; 189dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy const float u2 = glyph->mBitmapMaxU; 190dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy const float v1 = glyph->mBitmapMinV; 191dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy const float v2 = glyph->mBitmapMaxV; 192dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy 1939777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mState->appendRotatedMeshQuad( 1949777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy position->fX + destination[0].fX, 1959777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy position->fY + destination[0].fY, u1, v2, 1969777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy position->fX + destination[1].fX, 1979777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy position->fY + destination[1].fY, u2, v2, 1989777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy position->fX + destination[2].fX, 1999777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy position->fY + destination[2].fY, u2, v1, 2009777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy position->fX + destination[3].fX, 2019777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy position->fY + destination[3].fY, u1, v1, 2029777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy glyph->mCachedTextureLine->mCacheTexture); 2039777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy} 2049777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 2057de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet HaaseCachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) { 2061e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy CachedGlyphInfo* cachedGlyph = NULL; 207726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy ssize_t index = mCachedGlyphs.indexOfKey(textUnit); 2081e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (index >= 0) { 2091e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy cachedGlyph = mCachedGlyphs.valueAt(index); 2101e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } else { 211726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy cachedGlyph = cacheGlyph(paint, textUnit); 21265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 21365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 21465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk // Is the glyph still in texture cache? 21565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk if (!cachedGlyph->mIsValid) { 216726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit); 21765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk updateGlyphCache(paint, skiaGlyph, cachedGlyph); 21865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 21965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 22065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk return cachedGlyph; 22165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk} 22265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 223726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guyvoid Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 22461c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy int numGlyphs, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH) { 22561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bitmap != NULL && bitmapW > 0 && bitmapH > 0) { 226726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy render(paint, text, start, len, numGlyphs, x, y, BITMAP, bitmap, 227671d6cf460531825a321edb200523d0faa7792c9Romain Guy bitmapW, bitmapH, NULL, NULL); 22861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy } else { 229726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL, 230671d6cf460531825a321edb200523d0faa7792c9Romain Guy 0, 0, NULL, NULL); 231f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 232f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 233f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 234671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len, 235671d6cf460531825a321edb200523d0faa7792c9Romain Guy int numGlyphs, int x, int y, const float* positions) { 236671d6cf460531825a321edb200523d0faa7792c9Romain Guy render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL, 237671d6cf460531825a321edb200523d0faa7792c9Romain Guy 0, 0, NULL, positions); 238671d6cf460531825a321edb200523d0faa7792c9Romain Guy} 239671d6cf460531825a321edb200523d0faa7792c9Romain Guy 2409777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len, 2419777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy int numGlyphs, SkPath* path, float hOffset, float vOffset) { 2429777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (numGlyphs == 0 || text == NULL || len == 0) { 2439777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy return; 2449777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 2459777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 2469777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy text += start; 2479777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 2489777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy int glyphsCount = 0; 2499777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy SkFixed prevRsbDelta = 0; 2509777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 2519777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float penX = 0.0f; 2529777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 2539777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy SkPoint position; 2549777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy SkVector tangent; 2559777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 2569777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy SkPathMeasure measure(*path, false); 2579777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float pathLength = SkScalarToFloat(measure.getLength()); 2589777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 2599777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (paint->getTextAlign() != SkPaint::kLeft_Align) { 2609777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float textWidth = SkScalarToFloat(paint->measureText(text, len)); 2619777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float pathOffset = pathLength; 2629777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (paint->getTextAlign() == SkPaint::kCenter_Align) { 2639777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy textWidth *= 0.5f; 2649777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy pathOffset *= 0.5f; 2659777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 2669777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy penX += pathOffset - textWidth; 2679777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 2689777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 269dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy while (glyphsCount < numGlyphs && penX < pathLength) { 2709777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy glyph_t glyph = GET_GLYPH(text); 2719777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 2729777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (IS_END_OF_STRING(glyph)) { 2739777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy break; 2749777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 2759777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 2769777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph); 2779777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta)); 2789777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy prevRsbDelta = cachedGlyph->mRsbDelta; 2799777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 2809777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (cachedGlyph->mIsValid) { 281dd7c8e4c68205d39109d4317dd0c9b05ed43e8e5Romain Guy drawCachedGlyph(cachedGlyph, penX, hOffset, vOffset, measure, &position, &tangent); 2829777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 2839777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 2849777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy penX += SkFixedToFloat(cachedGlyph->mAdvanceX); 2859777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 2869777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy glyphsCount++; 2879777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 2889777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy} 2899777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 290726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guyvoid Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 291416a847633680d94efb926837efdc18726d54918Raph Levien int numGlyphs, Rect *bounds, const float* positions) { 29261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy if (bounds == NULL) { 2933762c311729fe9f3af085c14c5c1fb471d994c03Steve Block ALOGE("No return rectangle provided to measure text"); 294f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk return; 295f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 296f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk bounds->set(1e6, -1e6, -1e6, 1e6); 297416a847633680d94efb926837efdc18726d54918Raph Levien render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds, positions); 298f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 299f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 300726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guyvoid Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len, 30161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap, 3029777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* positions) { 303694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (numGlyphs == 0 || text == NULL || len == 0) { 304694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 305694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 306694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 307671d6cf460531825a321edb200523d0faa7792c9Romain Guy static RenderGlyph gRenderGlyph[] = { 308671d6cf460531825a321edb200523d0faa7792c9Romain Guy &android::uirenderer::Font::drawCachedGlyph, 309671d6cf460531825a321edb200523d0faa7792c9Romain Guy &android::uirenderer::Font::drawCachedGlyphBitmap, 310671d6cf460531825a321edb200523d0faa7792c9Romain Guy &android::uirenderer::Font::measureCachedGlyph 311671d6cf460531825a321edb200523d0faa7792c9Romain Guy }; 312671d6cf460531825a321edb200523d0faa7792c9Romain Guy RenderGlyph render = gRenderGlyph[mode]; 313694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 3149777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy text += start; 3159777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy int glyphsCount = 0; 3169777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 317b629490ffb21752750cc081827ca4c1eae1eb015Romain Guy if (CC_LIKELY(positions == NULL)) { 318671d6cf460531825a321edb200523d0faa7792c9Romain Guy SkFixed prevRsbDelta = 0; 319694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 3209777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float penX = x + 0.5f; 321671d6cf460531825a321edb200523d0faa7792c9Romain Guy int penY = y; 322694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 323671d6cf460531825a321edb200523d0faa7792c9Romain Guy while (glyphsCount < numGlyphs) { 324671d6cf460531825a321edb200523d0faa7792c9Romain Guy glyph_t glyph = GET_GLYPH(text); 325671d6cf460531825a321edb200523d0faa7792c9Romain Guy 326671d6cf460531825a321edb200523d0faa7792c9Romain Guy // Reached the end of the string 327671d6cf460531825a321edb200523d0faa7792c9Romain Guy if (IS_END_OF_STRING(glyph)) { 328f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk break; 32989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 330671d6cf460531825a321edb200523d0faa7792c9Romain Guy 331671d6cf460531825a321edb200523d0faa7792c9Romain Guy CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph); 3329777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy penX += SkFixedToFloat(AUTO_KERN(prevRsbDelta, cachedGlyph->mLsbDelta)); 333671d6cf460531825a321edb200523d0faa7792c9Romain Guy prevRsbDelta = cachedGlyph->mRsbDelta; 334671d6cf460531825a321edb200523d0faa7792c9Romain Guy 335671d6cf460531825a321edb200523d0faa7792c9Romain Guy // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage 336671d6cf460531825a321edb200523d0faa7792c9Romain Guy if (cachedGlyph->mIsValid) { 337671d6cf460531825a321edb200523d0faa7792c9Romain Guy (*this.*render)(cachedGlyph, (int) floorf(penX), penY, 338671d6cf460531825a321edb200523d0faa7792c9Romain Guy bitmap, bitmapW, bitmapH, bounds, positions); 339671d6cf460531825a321edb200523d0faa7792c9Romain Guy } 340671d6cf460531825a321edb200523d0faa7792c9Romain Guy 341671d6cf460531825a321edb200523d0faa7792c9Romain Guy penX += SkFixedToFloat(cachedGlyph->mAdvanceX); 342671d6cf460531825a321edb200523d0faa7792c9Romain Guy 343671d6cf460531825a321edb200523d0faa7792c9Romain Guy glyphsCount++; 344694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 345671d6cf460531825a321edb200523d0faa7792c9Romain Guy } else { 346671d6cf460531825a321edb200523d0faa7792c9Romain Guy const SkPaint::Align align = paint->getTextAlign(); 347694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 348671d6cf460531825a321edb200523d0faa7792c9Romain Guy // This is for renderPosText() 349671d6cf460531825a321edb200523d0faa7792c9Romain Guy while (glyphsCount < numGlyphs) { 350671d6cf460531825a321edb200523d0faa7792c9Romain Guy glyph_t glyph = GET_GLYPH(text); 351694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 352671d6cf460531825a321edb200523d0faa7792c9Romain Guy // Reached the end of the string 353671d6cf460531825a321edb200523d0faa7792c9Romain Guy if (IS_END_OF_STRING(glyph)) { 354671d6cf460531825a321edb200523d0faa7792c9Romain Guy break; 355671d6cf460531825a321edb200523d0faa7792c9Romain Guy } 356671d6cf460531825a321edb200523d0faa7792c9Romain Guy 357671d6cf460531825a321edb200523d0faa7792c9Romain Guy CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph); 358671d6cf460531825a321edb200523d0faa7792c9Romain Guy 359671d6cf460531825a321edb200523d0faa7792c9Romain Guy // If it's still not valid, we couldn't cache it, so we shouldn't draw garbage 360671d6cf460531825a321edb200523d0faa7792c9Romain Guy if (cachedGlyph->mIsValid) { 361671d6cf460531825a321edb200523d0faa7792c9Romain Guy int penX = x + positions[(glyphsCount << 1)]; 362671d6cf460531825a321edb200523d0faa7792c9Romain Guy int penY = y + positions[(glyphsCount << 1) + 1]; 363671d6cf460531825a321edb200523d0faa7792c9Romain Guy 364671d6cf460531825a321edb200523d0faa7792c9Romain Guy switch (align) { 365671d6cf460531825a321edb200523d0faa7792c9Romain Guy case SkPaint::kRight_Align: 366671d6cf460531825a321edb200523d0faa7792c9Romain Guy penX -= SkFixedToFloat(cachedGlyph->mAdvanceX); 367671d6cf460531825a321edb200523d0faa7792c9Romain Guy penY -= SkFixedToFloat(cachedGlyph->mAdvanceY); 368671d6cf460531825a321edb200523d0faa7792c9Romain Guy break; 369671d6cf460531825a321edb200523d0faa7792c9Romain Guy case SkPaint::kCenter_Align: 370671d6cf460531825a321edb200523d0faa7792c9Romain Guy penX -= SkFixedToFloat(cachedGlyph->mAdvanceX >> 1); 371671d6cf460531825a321edb200523d0faa7792c9Romain Guy penY -= SkFixedToFloat(cachedGlyph->mAdvanceY >> 1); 372671d6cf460531825a321edb200523d0faa7792c9Romain Guy default: 373671d6cf460531825a321edb200523d0faa7792c9Romain Guy break; 374671d6cf460531825a321edb200523d0faa7792c9Romain Guy } 375671d6cf460531825a321edb200523d0faa7792c9Romain Guy 376671d6cf460531825a321edb200523d0faa7792c9Romain Guy (*this.*render)(cachedGlyph, penX, penY, 377671d6cf460531825a321edb200523d0faa7792c9Romain Guy bitmap, bitmapW, bitmapH, bounds, positions); 378671d6cf460531825a321edb200523d0faa7792c9Romain Guy } 379671d6cf460531825a321edb200523d0faa7792c9Romain Guy 380671d6cf460531825a321edb200523d0faa7792c9Romain Guy glyphsCount++; 381694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 382694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 383694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 384694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 38551769a68a5cb34e9564740c6a854fcb93018789dRomain Guyvoid Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph) { 386694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mAdvanceX = skiaGlyph.fAdvanceX; 387694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mAdvanceY = skiaGlyph.fAdvanceY; 388694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapLeft = skiaGlyph.fLeft; 389694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapTop = skiaGlyph.fTop; 3902bffd268f135df8308c9e67af110525a5c463424Romain Guy glyph->mLsbDelta = skiaGlyph.fLsbDelta; 3912bffd268f135df8308c9e67af110525a5c463424Romain Guy glyph->mRsbDelta = skiaGlyph.fRsbDelta; 392694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 393694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startX = 0; 394694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startY = 0; 395694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 396694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Get the bitmap for the glyph 397694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy paint->findImage(skiaGlyph); 3987de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY); 399694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 400694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!glyph->mIsValid) { 401694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 402694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 403694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 404694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endX = startX + skiaGlyph.fWidth; 405694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endY = startY + skiaGlyph.fHeight; 406694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 40789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk glyph->mStartX = startX; 40889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk glyph->mStartY = startY; 409694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapWidth = skiaGlyph.fWidth; 410694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glyph->mBitmapHeight = skiaGlyph.fHeight; 411694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 4127de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint32_t cacheWidth = glyph->mCachedTextureLine->mCacheTexture->mWidth; 4137de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint32_t cacheHeight = glyph->mCachedTextureLine->mCacheTexture->mHeight; 414694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 41533fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy glyph->mBitmapMinU = startX / (float) cacheWidth; 41633fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy glyph->mBitmapMinV = startY / (float) cacheHeight; 41733fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy glyph->mBitmapMaxU = endX / (float) cacheWidth; 41833fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy glyph->mBitmapMaxV = endY / (float) cacheHeight; 419694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 42051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy mState->mUploadTexture = true; 421694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 422694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 4237de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet HaaseCachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph) { 42451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy CachedGlyphInfo* newGlyph = new CachedGlyphInfo(); 425694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCachedGlyphs.add(glyph, newGlyph); 426694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 427726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy const SkGlyph& skiaGlyph = GET_METRICS(paint, glyph); 428694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy newGlyph->mGlyphIndex = skiaGlyph.fID; 429694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy newGlyph->mIsValid = false; 430694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 431694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy updateGlyphCache(paint, skiaGlyph, newGlyph); 432694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 433694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return newGlyph; 434694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 435694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 4362577db1ec135a1470a2c42139772ec97a6c30e78Romain GuyFont* Font::create(FontRenderer* state, uint32_t fontId, float fontSize, 437bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy int flags, uint32_t italicStyle, uint32_t scaleX, 438bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy SkPaint::Style style, uint32_t strokeWidth) { 439694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy Vector<Font*> &activeFonts = state->mActiveFonts; 440694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 441694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < activeFonts.size(); i++) { 44251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy Font* font = activeFonts[i]; 4432577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy if (font->mFontId == fontId && font->mFontSize == fontSize && 4448668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase font->mFlags == flags && font->mItalicStyle == italicStyle && 445bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy font->mScaleX == scaleX && font->mStyle == style && 446bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy (style == SkPaint::kFill_Style || font->mStrokeWidth == strokeWidth)) { 44751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy return font; 448694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 449694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 450694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 451bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle, 452bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy scaleX, style, strokeWidth); 453694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy activeFonts.push(newFont); 454694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return newFont; 455694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 456694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 457694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 458694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// FontRenderer 459694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/////////////////////////////////////////////////////////////////////////////// 460694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 461514fb18827186591d66973c2362c859b64b63556Romain Guystatic bool sLogFontRendererCreate = true; 462514fb18827186591d66973c2362c859b64b63556Romain Guy 463694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::FontRenderer() { 464c9855a53edfac818dc68714557185977556f849dRomain Guy if (sLogFontRendererCreate) { 465c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD("Creating FontRenderer"); 466c9855a53edfac818dc68714557185977556f849dRomain Guy } 46751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 468b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy mGammaTable = NULL; 469694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mInitialized = false; 470694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mMaxNumberOfQuads = 1024; 471694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 472694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 4739cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy mTextMeshPtr = NULL; 4747de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCurrentCacheTexture = NULL; 4757de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mLastCacheTexture = NULL; 4767de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTextureSmall = NULL; 4777de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTexture128 = NULL; 4787de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTexture256 = NULL; 4797de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTexture512 = NULL; 4809cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy 4812a47c14e2a6f152496b43104bc785c488583fd59Chet Haase mLinearFiltering = false; 4822a47c14e2a6f152496b43104bc785c488583fd59Chet Haase 483694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mIndexBufferID = 0; 484694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 4857de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mSmallCacheWidth = DEFAULT_TEXT_CACHE_WIDTH; 4867de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mSmallCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT; 48751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 48851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy char property[PROPERTY_VALUE_MAX]; 48951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) { 490c9855a53edfac818dc68714557185977556f849dRomain Guy if (sLogFontRendererCreate) { 491c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD(" Setting text cache width to %s pixels", property); 492c9855a53edfac818dc68714557185977556f849dRomain Guy } 4937de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mSmallCacheWidth = atoi(property); 49451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } else { 495514fb18827186591d66973c2362c859b64b63556Romain Guy if (sLogFontRendererCreate) { 4967de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase INIT_LOGD(" Using default text cache width of %i pixels", mSmallCacheWidth); 497514fb18827186591d66973c2362c859b64b63556Romain Guy } 49851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } 49951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy 50051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy if (property_get(PROPERTY_TEXT_CACHE_HEIGHT, property, NULL) > 0) { 501c9855a53edfac818dc68714557185977556f849dRomain Guy if (sLogFontRendererCreate) { 502c9855a53edfac818dc68714557185977556f849dRomain Guy INIT_LOGD(" Setting text cache width to %s pixels", property); 503c9855a53edfac818dc68714557185977556f849dRomain Guy } 5047de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mSmallCacheHeight = atoi(property); 50551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } else { 506514fb18827186591d66973c2362c859b64b63556Romain Guy if (sLogFontRendererCreate) { 5077de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase INIT_LOGD(" Using default text cache height of %i pixels", mSmallCacheHeight); 508514fb18827186591d66973c2362c859b64b63556Romain Guy } 50951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy } 510514fb18827186591d66973c2362c859b64b63556Romain Guy 511514fb18827186591d66973c2362c859b64b63556Romain Guy sLogFontRendererCreate = false; 512694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 513694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 514694b519ac647fe998fd396fe0784cc8e179aadc4Romain GuyFontRenderer::~FontRenderer() { 515694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 516694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy delete mCacheLines[i]; 517694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 518694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCacheLines.clear(); 519694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 5209cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy if (mInitialized) { 521a9dd820184ee4d083bd9b2af735dcf50b78fc6cdRomain Guy // Unbinding the buffer shouldn't be necessary but it crashes with some drivers 522a9dd820184ee4d083bd9b2af735dcf50b78fc6cdRomain Guy Caches::getInstance().unbindIndicesBuffer(); 523b0317984d34da99b614597ad0a8b39268eacb783Romain Guy glDeleteBuffers(1, &mIndexBufferID); 524b0317984d34da99b614597ad0a8b39268eacb783Romain Guy 5259cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy delete[] mTextMeshPtr; 5267de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase delete mCacheTextureSmall; 5277de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase delete mCacheTexture128; 5287de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase delete mCacheTexture256; 5297de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase delete mCacheTexture512; 5309b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 531694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 532694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy Vector<Font*> fontsToDereference = mActiveFonts; 533694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < fontsToDereference.size(); i++) { 534694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy delete fontsToDereference[i]; 535694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 536694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 537694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 538694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::flushAllAndInvalidate() { 539694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex != 0) { 540694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 541694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 542694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 5439d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 544694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mActiveFonts.size(); i++) { 545694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mActiveFonts[i]->invalidateTextureCache(); 546694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 5479d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 548694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 549694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCacheLines[i]->mCurrentCol = 0; 550694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 551694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 552694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 5539a8245629d69d81e0b62e52970feaf9c02580e75Chet Haasevoid FontRenderer::deallocateTextureMemory(CacheTexture *cacheTexture) { 5549a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase if (cacheTexture && cacheTexture->mTexture) { 5559a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase glDeleteTextures(1, &cacheTexture->mTextureId); 5569d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy delete[] cacheTexture->mTexture; 5579a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase cacheTexture->mTexture = NULL; 55899a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy cacheTexture->mTextureId = 0; 5599a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase } 5609a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase} 5619a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase 5629a8245629d69d81e0b62e52970feaf9c02580e75Chet Haasevoid FontRenderer::flushLargeCaches() { 5639a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase if ((!mCacheTexture128 || !mCacheTexture128->mTexture) && 5649a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase (!mCacheTexture256 || !mCacheTexture256->mTexture) && 5659a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase (!mCacheTexture512 || !mCacheTexture512->mTexture)) { 5669a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase // Typical case; no large glyph caches allocated 5679a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase return; 5689a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase } 5699a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase 5709a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase for (uint32_t i = 0; i < mCacheLines.size(); i++) { 5719a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase CacheTextureLine* cacheLine = mCacheLines[i]; 5729a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase if ((cacheLine->mCacheTexture == mCacheTexture128 || 5739a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase cacheLine->mCacheTexture == mCacheTexture256 || 5749a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase cacheLine->mCacheTexture == mCacheTexture512) && 5759a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase cacheLine->mCacheTexture->mTexture != NULL) { 5769a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase cacheLine->mCurrentCol = 0; 5779a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase for (uint32_t i = 0; i < mActiveFonts.size(); i++) { 5789a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase mActiveFonts[i]->invalidateTextureCache(cacheLine); 5799a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase } 5809a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase } 5819a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase } 5829a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase 5839a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase deallocateTextureMemory(mCacheTexture128); 5849a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase deallocateTextureMemory(mCacheTexture256); 5859a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase deallocateTextureMemory(mCacheTexture512); 5869a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase} 5879a8245629d69d81e0b62e52970feaf9c02580e75Chet Haase 5889d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guyvoid FontRenderer::allocateTextureMemory(CacheTexture* cacheTexture) { 5892a47c14e2a6f152496b43104bc785c488583fd59Chet Haase int width = cacheTexture->mWidth; 5902a47c14e2a6f152496b43104bc785c488583fd59Chet Haase int height = cacheTexture->mHeight; 5919d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 5922a47c14e2a6f152496b43104bc785c488583fd59Chet Haase cacheTexture->mTexture = new uint8_t[width * height]; 59399a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy 59499a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy if (!cacheTexture->mTextureId) { 59599a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy glGenTextures(1, &cacheTexture->mTextureId); 59699a6ddd4cd8762654a575eb4ac3d0e5431d919b8Romain Guy } 5979d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 59816c88085255c71a1a8fc034129aa2dcc61e1ddd0Romain Guy Caches::getInstance().activeTexture(0); 5992a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId); 6002a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 6012a47c14e2a6f152496b43104bc785c488583fd59Chet Haase // Initialize texture dimensions 6022a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, 6032a47c14e2a6f152496b43104bc785c488583fd59Chet Haase GL_ALPHA, GL_UNSIGNED_BYTE, 0); 6042a47c14e2a6f152496b43104bc785c488583fd59Chet Haase 6052a47c14e2a6f152496b43104bc785c488583fd59Chet Haase const GLenum filtering = cacheTexture->mLinearFiltering ? GL_LINEAR : GL_NEAREST; 6062a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); 6072a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); 6087de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 6092a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 6102a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 6117de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase} 6127de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 6137de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasevoid FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph, 6147de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint32_t* retOriginX, uint32_t* retOriginY) { 6157de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase cachedGlyph->mIsValid = false; 616694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If the glyph is too tall, don't cache it 61733fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) { 6183762c311729fe9f3af085c14c5c1fb471d994c03Steve Block ALOGE("Font size to large to fit in cache. width, height = %i, %i", 6197de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase (int) glyph.fWidth, (int) glyph.fHeight); 6207de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase return; 621694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 622694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 623694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Now copy the bitmap into the cache texture 624694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startX = 0; 625694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t startY = 0; 626694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 627694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bool bitmapFit = false; 6287de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase CacheTextureLine *cacheLine; 629694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 630694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY); 631694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (bitmapFit) { 6327de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase cacheLine = mCacheLines[i]; 633694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 634694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 635694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 636694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 637694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // If the new glyph didn't fit, flush the state so far and invalidate everything 638694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!bitmapFit) { 639694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy flushAllAndInvalidate(); 640694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 641694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Try to fit it again 642694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 643694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY); 644694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (bitmapFit) { 6457de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase cacheLine = mCacheLines[i]; 646694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy break; 647694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 648694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 649694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 650694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // if we still don't fit, something is wrong and we shouldn't draw 651694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (!bitmapFit) { 6527de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase return; 653694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 654694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 655694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 6567de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase cachedGlyph->mCachedTextureLine = cacheLine; 6577de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 658694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *retOriginX = startX; 659694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *retOriginY = startY; 660694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 661694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endX = startX + glyph.fWidth; 662694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t endY = startY + glyph.fHeight; 663694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 6647de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint32_t cacheWidth = cacheLine->mMaxWidth; 665694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 6669d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy CacheTexture* cacheTexture = cacheLine->mCacheTexture; 6679d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy if (!cacheTexture->mTexture) { 6687de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // Large-glyph texture memory is allocated only as needed 6692a47c14e2a6f152496b43104bc785c488583fd59Chet Haase allocateTextureMemory(cacheTexture); 6707de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 6719d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 6727de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint8_t* cacheBuffer = cacheTexture->mTexture; 67389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage; 674694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy unsigned int stride = glyph.rowBytes(); 675694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 676694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0; 67733fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy 67833fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy for (cacheX = startX - TEXTURE_BORDER_SIZE; cacheX < endX + TEXTURE_BORDER_SIZE; cacheX++) { 67933fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy cacheBuffer[(startY - TEXTURE_BORDER_SIZE) * cacheWidth + cacheX] = 0; 68033fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy cacheBuffer[(endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + cacheX] = 0; 68133fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy } 68233fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy 68333fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy for (cacheY = startY - TEXTURE_BORDER_SIZE + 1; 68433fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy cacheY < endY + TEXTURE_BORDER_SIZE - 1; cacheY++) { 68533fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy cacheBuffer[cacheY * cacheWidth + startX - TEXTURE_BORDER_SIZE] = 0; 68633fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy cacheBuffer[cacheY * cacheWidth + endX + TEXTURE_BORDER_SIZE - 1] = 0; 68733fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy } 68833fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy 689b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy if (mGammaTable) { 690b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) { 691b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) { 692b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy uint8_t tempCol = bitmapBuffer[bY * stride + bX]; 693b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol]; 694b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy } 695b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy } 696b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy } else { 697b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) { 698b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) { 699b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy uint8_t tempCol = bitmapBuffer[bY * stride + bX]; 700b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy cacheBuffer[cacheY * cacheWidth + cacheX] = tempCol; 701b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy } 702694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 703694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 7049777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 7057de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase cachedGlyph->mIsValid = true; 706694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 707694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 7087de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet HaaseCacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) { 7090aa87bbfc41e8b5f52de701ac17b4e66a7a7b609Romain Guy CacheTexture* cacheTexture = new CacheTexture(width, height); 7109d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 7112a47c14e2a6f152496b43104bc785c488583fd59Chet Haase if (allocate) { 7122a47c14e2a6f152496b43104bc785c488583fd59Chet Haase allocateTextureMemory(cacheTexture); 7132a47c14e2a6f152496b43104bc785c488583fd59Chet Haase } 7149d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 7152a47c14e2a6f152496b43104bc785c488583fd59Chet Haase return cacheTexture; 7167de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase} 7177de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 7187de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haasevoid FontRenderer::initTextTexture() { 7199d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy for (uint32_t i = 0; i < mCacheLines.size(); i++) { 7209d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy delete mCacheLines[i]; 7219d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy } 7227de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.clear(); 7237de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 7249d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy if (mCacheTextureSmall) { 7259d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy delete mCacheTextureSmall; 7269d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy delete mCacheTexture128; 7279d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy delete mCacheTexture256; 7289d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy delete mCacheTexture512; 7299d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy } 7309d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 7317de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // Next, use other, separate caches for large glyphs. 7327de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint16_t maxWidth = 0; 7337de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (Caches::hasInstance()) { 7347de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase maxWidth = Caches::getInstance().maxTextureSize; 7357de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 7369d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 7377de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (maxWidth > MAX_TEXT_CACHE_WIDTH || maxWidth == 0) { 7387de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase maxWidth = MAX_TEXT_CACHE_WIDTH; 7397de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 7409d9758ae30a59dcf594e0d26ba5d4ee153a3e44aRomain Guy 7417de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTextureSmall = createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true); 7427de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTexture128 = createCacheTexture(maxWidth, 256, false); 7437de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTexture256 = createCacheTexture(maxWidth, 256, false); 7447de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheTexture512 = createCacheTexture(maxWidth, 512, false); 7457de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCurrentCacheTexture = mCacheTextureSmall; 7467de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 7477de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mUploadTexture = false; 7487de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // Split up our default cache texture into lines of certain widths 749694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int nextLine = 0; 7507de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 18, nextLine, 0, mCacheTextureSmall)); 751694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 7527de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, 0, mCacheTextureSmall)); 753694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 7547de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, 0, mCacheTextureSmall)); 75565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk nextLine += mCacheLines.top()->mMaxHeight; 7567de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, 0, mCacheTextureSmall)); 757694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 7587de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, 0, mCacheTextureSmall)); 759694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 7607de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 42, nextLine, 0, mCacheTextureSmall)); 761694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy nextLine += mCacheLines.top()->mMaxHeight; 7627de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, mSmallCacheHeight - nextLine, 7637de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase nextLine, 0, mCacheTextureSmall)); 7647de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 7657de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // The first cache is split into 2 lines of height 128, the rest have just one cache line. 7667de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(maxWidth, 128, 0, 0, mCacheTexture128)); 7677de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(maxWidth, 128, 128, 0, mCacheTexture128)); 7687de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(maxWidth, 256, 0, 0, mCacheTexture256)); 7697de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCacheLines.push(new CacheTextureLine(maxWidth, 512, 0, 0, mCacheTexture512)); 770694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 771694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 772694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// Avoid having to reallocate memory and render quad by quad 773694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::initVertexArrayBuffers() { 774d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy uint32_t numIndices = mMaxNumberOfQuads * 6; 775d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy uint32_t indexBufferSizeBytes = numIndices * sizeof(uint16_t); 77651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes); 777694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 778694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy // Four verts, two triangles , six indices per quad 779694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy for (uint32_t i = 0; i < mMaxNumberOfQuads; i++) { 780694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int i6 = i * 6; 781694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy int i4 = i * 4; 782694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 783694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 0] = i4 + 0; 784694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 1] = i4 + 1; 785694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 2] = i4 + 2; 786694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 787694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 3] = i4 + 0; 788694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 4] = i4 + 2; 789694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy indexBufferData[i6 + 5] = i4 + 3; 790694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 791694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 792694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glGenBuffers(1, &mIndexBufferID); 79315bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy Caches::getInstance().bindIndicesBuffer(mIndexBufferID); 7945d794412e3e429e47404395badcd11b0b8639e8bRomain Guy glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_STATIC_DRAW); 795694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 796694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy free(indexBufferData); 797694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 798d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy uint32_t coordSize = 2; 799694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t uvSize = 2; 800694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy uint32_t vertsPerQuad = 4; 8019b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize; 8029b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mTextMeshPtr = new float[vertexBufferSize]; 803694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 804694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 805694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy// We don't want to allocate anything unless we actually draw text 806694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyvoid FontRenderer::checkInit() { 807694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mInitialized) { 808694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy return; 809694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 810694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 811694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy initTextTexture(); 812694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy initVertexArrayBuffers(); 813694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 814694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mInitialized = true; 815694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 816694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 8179b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::checkTextureUpdate() { 8187de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (!mUploadTexture && mLastCacheTexture == mCurrentCacheTexture) { 8199b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk return; 8209b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 8219b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 8222d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy Caches& caches = Caches::getInstance(); 8232d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy GLuint lastTextureId = 0; 8249b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk // Iterate over all the cache lines and see which ones need to be updated 8259b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk for (uint32_t i = 0; i < mCacheLines.size(); i++) { 8269b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk CacheTextureLine* cl = mCacheLines[i]; 8277de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (cl->mDirty && cl->mCacheTexture->mTexture != NULL) { 8287de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase CacheTexture* cacheTexture = cl->mCacheTexture; 8299b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t xOffset = 0; 8309b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t yOffset = cl->mCurrentRow; 8317de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase uint32_t width = cl->mMaxWidth; 8329b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk uint32_t height = cl->mMaxHeight; 8337de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase void* textureData = cacheTexture->mTexture + (yOffset * width); 8349b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 8352d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy if (cacheTexture->mTextureId != lastTextureId) { 8362d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy caches.activeTexture(0); 8372d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId); 8382d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy lastTextureId = cacheTexture->mTextureId; 8392d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy } 8409b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height, 8411e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy GL_ALPHA, GL_UNSIGNED_BYTE, textureData); 8429b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 8439b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk cl->mDirty = false; 8449b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk } 845694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 846694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 84716c88085255c71a1a8fc034129aa2dcc61e1ddd0Romain Guy caches.activeTexture(0); 8487de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase glBindTexture(GL_TEXTURE_2D, mCurrentCacheTexture->mTextureId); 8492a47c14e2a6f152496b43104bc785c488583fd59Chet Haase if (mLinearFiltering != mCurrentCacheTexture->mLinearFiltering) { 8502a47c14e2a6f152496b43104bc785c488583fd59Chet Haase const GLenum filtering = mLinearFiltering ? GL_LINEAR : GL_NEAREST; 8512a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); 8522a47c14e2a6f152496b43104bc785c488583fd59Chet Haase glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); 8532a47c14e2a6f152496b43104bc785c488583fd59Chet Haase mCurrentCacheTexture->mLinearFiltering = mLinearFiltering; 8542a47c14e2a6f152496b43104bc785c488583fd59Chet Haase } 8557de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mLastCacheTexture = mCurrentCacheTexture; 8567de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase 8579b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk mUploadTexture = false; 8589b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk} 8599b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 8609b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchoukvoid FontRenderer::issueDrawCommand() { 8619b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk checkTextureUpdate(); 8629b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk 86315bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy Caches& caches = Caches::getInstance(); 8642d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy caches.bindIndicesBuffer(mIndexBufferID); 86515bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy if (!mDrawn) { 86615bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy float* buffer = mTextMeshPtr; 86715bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy int offset = 2; 86815bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy 86915bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy bool force = caches.unbindMeshBuffer(); 87015bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy caches.bindPositionVertexPointer(force, caches.currentProgram->position, buffer); 87115bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy caches.bindTexCoordsVertexPointer(force, caches.currentProgram->texCoords, 87215bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy buffer + offset); 87315bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy } 87415bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy 875694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL); 8765b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 8775b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mDrawn = true; 878694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 879694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 8809777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1, 8819777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3, 8827de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase float x4, float y4, float u4, float v4, CacheTexture* texture) { 8837de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (texture != mCurrentCacheTexture) { 8847de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase if (mCurrentQuadIndex != 0) { 8857de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // First, draw everything stored already which uses the previous texture 8867de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase issueDrawCommand(); 8877de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCurrentQuadIndex = 0; 8887de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 8897de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase // Now use the new texture id 8907de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase mCurrentCacheTexture = texture; 8917de0cb12d0e5fd64811da0b5d1ae0c0d58b86f86Chet Haase } 89209147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy 893694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy const uint32_t vertsPerQuad = 4; 894d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy const uint32_t floatsPerVert = 4; 89551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy float* currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert; 896694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 897694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x1; 898694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y1; 899694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u1; 900694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v1; 901694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 902694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x2; 903694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y2; 904694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u2; 905694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v2; 906694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 907694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x3; 908694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y3; 909694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u3; 910694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v3; 911694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 912694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = x4; 913694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = y4; 914694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = u4; 915694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy (*currentPos++) = v4; 916694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 917694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex++; 9189777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy} 9199777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 9209777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1, 9219777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3, 9229777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float x4, float y4, float u4, float v4, CacheTexture* texture) { 9239777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 9249777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (mClip && 9259777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) { 9269777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy return; 9279777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 9289777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 9299777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture); 930694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 9315b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy if (mBounds) { 9325b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->left = fmin(mBounds->left, x1); 9335b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->top = fmin(mBounds->top, y3); 9345b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->right = fmax(mBounds->right, x3); 9355b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds->bottom = fmax(mBounds->bottom, y1); 9365b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy } 9375b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 938694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex == mMaxNumberOfQuads) { 939694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 940694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 941694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 942694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 943694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 9449777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guyvoid FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1, 9459777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3, 9469777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float x4, float y4, float u4, float v4, CacheTexture* texture) { 9479777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 9489777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture); 9499777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 9509777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (mBounds) { 9519777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mBounds->left = fmin(mBounds->left, fmin(x1, fmin(x2, fmin(x3, x4)))); 9529777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mBounds->top = fmin(mBounds->top, fmin(y1, fmin(y2, fmin(y3, y4)))); 9539777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mBounds->right = fmax(mBounds->right, fmax(x1, fmax(x2, fmax(x3, x4)))); 9549777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mBounds->bottom = fmax(mBounds->bottom, fmax(y1, fmax(y2, fmax(y3, y4)))); 9559777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 9569777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 9579777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (mCurrentQuadIndex == mMaxNumberOfQuads) { 9589777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy issueDrawCommand(); 9599777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mCurrentQuadIndex = 0; 9609777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 9619777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy} 9629777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 96365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukuint32_t FontRenderer::getRemainingCacheCapacity() { 96465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t remainingCapacity = 0; 96565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk float totalPixels = 0; 96665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk for(uint32_t i = 0; i < mCacheLines.size(); i ++) { 96765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol); 96865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk totalPixels += mCacheLines[i]->mMaxWidth; 96965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 97065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk remainingCapacity = (remainingCapacity * 100) / totalPixels; 97165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk return remainingCapacity; 97265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk} 97365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 97465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::precacheLatin(SkPaint* paint) { 97565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk // Remaining capacity is measured in % 97665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t remainingCapacity = getRemainingCacheCapacity(); 977ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy uint32_t precacheIndex = 0; 978ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy 979ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy // We store a string with letters in a rough frequency of occurrence 980ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy String16 l("eisarntolcdugpmhbyfvkwzxjq EISARNTOLCDUGPMHBYFVKWZXJQ,.?!()-+@;:'0123456789"); 981ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy 982ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy size_t size = l.size(); 983ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy uint16_t latin[size]; 984ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy paint->utfToGlyphs(l.string(), SkPaint::kUTF16_TextEncoding, size * sizeof(char16_t), latin); 985ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy 986ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy while (remainingCapacity > 25 && precacheIndex < size) { 987ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy mCurrentFont->getCachedGlyph(paint, TO_GLYPH(latin[precacheIndex])); 98865ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk remainingCapacity = getRemainingCacheCapacity(); 989ae91c4cbc79ea910753be65e2f1d7899abcb4da2Romain Guy precacheIndex++; 99065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 99165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk} 99265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 99365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchoukvoid FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) { 99465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk uint32_t currentNumFonts = mActiveFonts.size(); 995325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy int flags = 0; 996325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (paint->isFakeBoldText()) { 997325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy flags |= Font::kFakeBold; 998325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy } 9992577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy 10002577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy const float skewX = paint->getTextSkewX(); 10012577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy uint32_t italicStyle = *(uint32_t*) &skewX; 10028668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase const float scaleXFloat = paint->getTextScaleX(); 10038668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase uint32_t scaleX = *(uint32_t*) &scaleXFloat; 1004bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy SkPaint::Style style = paint->getStyle(); 1005bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy const float strokeWidthFloat = paint->getStrokeWidth(); 1006bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy uint32_t strokeWidth = *(uint32_t*) &strokeWidthFloat; 1007bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle, 1008bd496bc3d481f9cfc39007d22372d3a1a8809f96Romain Guy scaleX, style, strokeWidth); 100965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 101065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk const float maxPrecacheFontSize = 40.0f; 101165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk bool isNewFont = currentNumFonts != mActiveFonts.size(); 101265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk 10132bffd268f135df8308c9e67af110525a5c463424Romain Guy if (isNewFont && fontSize <= maxPrecacheFontSize) { 101465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk precacheLatin(paint); 101565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk } 1016694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 10177975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy 1018f18136cb3c881a9d16c1a4f0f341732c276936bfAlex SakhartchoukFontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text, 1019416a847633680d94efb926837efdc18726d54918Raph Levien uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius, const float* positions) { 10201e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy checkInit(); 10211e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 10221e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (!mCurrentFont) { 10231e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy DropShadow image; 10241e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.width = 0; 10251e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.height = 0; 10261e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.image = NULL; 10271e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.penX = 0; 10281e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy image.penY = 0; 10291e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy return image; 10301e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } 1031f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 10322d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy mDrawn = false; 1033ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy mClip = NULL; 1034ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy mBounds = NULL; 1035ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 1036f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk Rect bounds; 1037416a847633680d94efb926837efdc18726d54918Raph Levien mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions); 1038ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 10391e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius; 10401e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius; 1041f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk uint8_t* dataBuffer = new uint8_t[paddedWidth * paddedHeight]; 1042ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 10431e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy for (uint32_t i = 0; i < paddedWidth * paddedHeight; i++) { 1044f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk dataBuffer[i] = 0; 1045f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk } 10461e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1047f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int penX = radius - bounds.left; 1048f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk int penY = radius - bounds.bottom; 1049f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 1050726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY, 1051416a847633680d94efb926837efdc18726d54918Raph Levien Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions); 1052f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk blurImage(dataBuffer, paddedWidth, paddedHeight, radius); 1053f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk 1054f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk DropShadow image; 1055f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.width = paddedWidth; 1056f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.height = paddedHeight; 1057f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.image = dataBuffer; 1058f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.penX = penX; 1059f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk image.penY = penY; 10602d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy 1061f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk return image; 1062f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk} 1063694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1064671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid FontRenderer::initRender(const Rect* clip, Rect* bounds) { 1065694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy checkInit(); 1066694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 10675b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mDrawn = false; 10685b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds = bounds; 106909147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy mClip = clip; 1070671d6cf460531825a321edb200523d0faa7792c9Romain Guy} 1071ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy 1072671d6cf460531825a321edb200523d0faa7792c9Romain Guyvoid FontRenderer::finishRender() { 10735b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy mBounds = NULL; 1074ff98fa5a847f66e591287154c634ef7895a9549cRomain Guy mClip = NULL; 1075694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 1076694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy if (mCurrentQuadIndex != 0) { 1077694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy issueDrawCommand(); 1078694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy mCurrentQuadIndex = 0; 1079694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy } 1080671d6cf460531825a321edb200523d0faa7792c9Romain Guy} 1081671d6cf460531825a321edb200523d0faa7792c9Romain Guy 1082671d6cf460531825a321edb200523d0faa7792c9Romain Guybool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text, 1083671d6cf460531825a321edb200523d0faa7792c9Romain Guy uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, Rect* bounds) { 1084671d6cf460531825a321edb200523d0faa7792c9Romain Guy if (!mCurrentFont) { 1085671d6cf460531825a321edb200523d0faa7792c9Romain Guy ALOGE("No font set"); 1086671d6cf460531825a321edb200523d0faa7792c9Romain Guy return false; 1087671d6cf460531825a321edb200523d0faa7792c9Romain Guy } 1088671d6cf460531825a321edb200523d0faa7792c9Romain Guy 1089671d6cf460531825a321edb200523d0faa7792c9Romain Guy initRender(clip, bounds); 1090671d6cf460531825a321edb200523d0faa7792c9Romain Guy mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y); 1091671d6cf460531825a321edb200523d0faa7792c9Romain Guy finishRender(); 1092671d6cf460531825a321edb200523d0faa7792c9Romain Guy 1093671d6cf460531825a321edb200523d0faa7792c9Romain Guy return mDrawn; 1094671d6cf460531825a321edb200523d0faa7792c9Romain Guy} 1095671d6cf460531825a321edb200523d0faa7792c9Romain Guy 1096671d6cf460531825a321edb200523d0faa7792c9Romain Guybool FontRenderer::renderPosText(SkPaint* paint, const Rect* clip, const char *text, 1097671d6cf460531825a321edb200523d0faa7792c9Romain Guy uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, 1098671d6cf460531825a321edb200523d0faa7792c9Romain Guy const float* positions, Rect* bounds) { 1099671d6cf460531825a321edb200523d0faa7792c9Romain Guy if (!mCurrentFont) { 1100671d6cf460531825a321edb200523d0faa7792c9Romain Guy ALOGE("No font set"); 1101671d6cf460531825a321edb200523d0faa7792c9Romain Guy return false; 1102671d6cf460531825a321edb200523d0faa7792c9Romain Guy } 1103671d6cf460531825a321edb200523d0faa7792c9Romain Guy 1104671d6cf460531825a321edb200523d0faa7792c9Romain Guy initRender(clip, bounds); 1105671d6cf460531825a321edb200523d0faa7792c9Romain Guy mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions); 1106671d6cf460531825a321edb200523d0faa7792c9Romain Guy finishRender(); 11075b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy 11085b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy return mDrawn; 11099777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy} 11109777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 11119777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guybool FontRenderer::renderTextOnPath(SkPaint* paint, const Rect* clip, const char *text, 11129777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy uint32_t startIndex, uint32_t len, int numGlyphs, SkPath* path, 11139777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy float hOffset, float vOffset, Rect* bounds) { 11149777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy if (!mCurrentFont) { 11159777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy ALOGE("No font set"); 11169777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy return false; 11179777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy } 11189777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 11199777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy initRender(clip, bounds); 11209777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset); 11219777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy finishRender(); 11229777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy 11239777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy return mDrawn; 1124694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy} 1125694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy 112689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::computeGaussianWeights(float* weights, int32_t radius) { 112789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Compute gaussian weights for the blur 112889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // e is the euler's number 112989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float e = 2.718281828459045f; 113089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float pi = 3.1415926535897932f; 113189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 ) 113289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // x is of the form [-radius .. 0 .. radius] 113389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // and sigma varies with radius. 113489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Based on some experimental radius values and sigma's 113589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // we approximately fit sigma = f(radius) as 1136f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk // sigma = radius * 0.3 + 0.6 113789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // The larger the radius gets, the more our gaussian blur 113889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // will resemble a box blur since with large sigma 113989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // the gaussian curve begins to lose its shape 1140325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy float sigma = 0.3f * (float) radius + 0.6f; 114189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 114289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Now compute the coefficints 114389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // We will store some redundant values to save some math during 114489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // the blur calculations 114589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // precompute some values 114689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma); 114789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float coeff2 = - 1.0f / (2.0f * sigma * sigma); 114889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 114989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float normalizeFactor = 0.0f; 1150325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 11517975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy float floatR = (float) r; 115289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2); 115389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk normalizeFactor += weights[r + radius]; 115489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 115589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 115689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk //Now we need to normalize the weights because all our coefficients need to add up to one 115789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk normalizeFactor = 1.0f / normalizeFactor; 1158325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 115989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk weights[r + radius] *= normalizeFactor; 116089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 116189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 116289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 116389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::horizontalBlur(float* weights, int32_t radius, 11641e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) { 116589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float blurredPixel = 0.0f; 116689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float currentPixel = 0.0f; 116789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1168325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t y = 0; y < height; y ++) { 116989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 117089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* input = source + y * width; 117189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* output = dest + y * width; 117289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1173325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t x = 0; x < width; x ++) { 117489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel = 0.0f; 117589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const float* gPtr = weights; 117689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Optimization for non-border pixels 1177325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (x > radius && x < (width - radius)) { 117889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + (x - radius); 1179325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int r = -radius; r <= radius; r ++) { 11807975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy currentPixel = (float) (*i); 118189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 118289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 118389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk i++; 118489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 118589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } else { 1186325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 118789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Stepping left and right away from the pixel 118889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int validW = x + r; 1189325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validW < 0) { 119089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validW = 0; 119189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 1192325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validW > width - 1) { 119389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validW = width - 1; 119489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 119589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1196325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy currentPixel = (float) input[validW]; 119789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 119889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 119989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 120089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 120189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk *output = (uint8_t)blurredPixel; 120289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk output ++; 120389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 120489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 120589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 120689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 120789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::verticalBlur(float* weights, int32_t radius, 12081e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) { 120989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float blurredPixel = 0.0f; 121089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float currentPixel = 0.0f; 121189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1212325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t y = 0; y < height; y ++) { 121389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 121489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* output = dest + y * width; 121589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1216325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t x = 0; x < width; x ++) { 121789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel = 0.0f; 121889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const float* gPtr = weights; 121989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t* input = source + x; 122089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Optimization for non-border pixels 1221325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (y > radius && y < (height - radius)) { 122289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + ((y - radius) * width); 1223325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 122489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk currentPixel = (float)(*i); 122589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 122689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 122789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk i += width; 122889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 122989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } else { 1230325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy for (int32_t r = -radius; r <= radius; r ++) { 123189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk int validH = y + r; 123289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk // Clamp to zero and width 1233325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validH < 0) { 123489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validH = 0; 123589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 1236325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy if (validH > height - 1) { 123789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk validH = height - 1; 123889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 123989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 124089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk const uint8_t *i = input + validH * width; 1241325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy currentPixel = (float) (*i); 124289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk blurredPixel += currentPixel * gPtr[0]; 124389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk gPtr++; 124489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 124589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 1246325a0f969c1d803d7e39a9caee8cc3d400350659Romain Guy *output = (uint8_t) blurredPixel; 124789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk output ++; 124889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 124989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk } 125089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 125189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 125289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 125389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchoukvoid FontRenderer::blurImage(uint8_t *image, int32_t width, int32_t height, int32_t radius) { 125489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk float *gaussian = new float[2 * radius + 1]; 125589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk computeGaussianWeights(gaussian, radius); 1256d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy 125789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk uint8_t* scratch = new uint8_t[width * height]; 1258d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy 125989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk horizontalBlur(gaussian, radius, image, scratch, width, height); 126089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk verticalBlur(gaussian, radius, scratch, image, width, height); 1261d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy 126289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk delete[] gaussian; 126389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk delete[] scratch; 126489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk} 126589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk 1266694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace uirenderer 1267694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}; // namespace android 1268