19f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy/*
29f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * Copyright (C) 2012 The Android Open Source Project
39f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy *
49f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * Licensed under the Apache License, Version 2.0 (the "License");
59f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * you may not use this file except in compliance with the License.
69f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * You may obtain a copy of the License at
79f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy *
89f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy *      http://www.apache.org/licenses/LICENSE-2.0
99f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy *
109f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * Unless required by applicable law or agreed to in writing, software
119f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * distributed under the License is distributed on an "AS IS" BASIS,
129f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * See the License for the specific language governing permissions and
149f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * limitations under the License.
159f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy */
169f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
17ca79cf69d09efa0c327e9b1237d86a119aea5da7Derek Sollenberger#include <SkGlyph.h>
189f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
199f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#include "CacheTexture.h"
202dc236b2bae13b9a0ed9b3f7320502aecd7983b3Tom Hudson#include "FontUtil.h"
218aa195d7081b889f3a7b1f426cbd8556377aae5eRomain Guy#include "../Caches.h"
220908764b2b3cf5075df4178a5f0a8547dcb7b317Romain Guy#include "../Debug.h"
23cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy#include "../Extensions.h"
24cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy#include "../PixelBuffer.h"
259f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
269f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guynamespace android {
279f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guynamespace uirenderer {
289f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
299f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy///////////////////////////////////////////////////////////////////////////////
309f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy// CacheBlock
319f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy///////////////////////////////////////////////////////////////////////////////
329f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
339f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy/**
349f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * Insert new block into existing linked list of blocks. Blocks are sorted in increasing-width
359f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * order, except for the final block (the remainder space at the right, since we fill from the
369f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * left).
379f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy */
38e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain GuyCacheBlock* CacheBlock::insertBlock(CacheBlock* head, CacheBlock* newBlock) {
399f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#if DEBUG_FONT_RENDERER
409f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    ALOGD("insertBlock: this, x, y, w, h = %p, %d, %d, %d, %d",
419f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            newBlock, newBlock->mX, newBlock->mY,
429f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            newBlock->mWidth, newBlock->mHeight);
439f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif
449b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
45e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy    CacheBlock* currBlock = head;
46d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    CacheBlock* prevBlock = nullptr;
479b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
489f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    while (currBlock && currBlock->mY != TEXTURE_BORDER_SIZE) {
499f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        if (newBlock->mWidth < currBlock->mWidth) {
509f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            newBlock->mNext = currBlock;
519f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            newBlock->mPrev = prevBlock;
529f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            currBlock->mPrev = newBlock;
539b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
549f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            if (prevBlock) {
559f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                prevBlock->mNext = newBlock;
569f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                return head;
579f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            } else {
589f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                return newBlock;
599f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            }
609f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        }
619b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
629f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        prevBlock = currBlock;
639f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        currBlock = currBlock->mNext;
649f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
659b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
669f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    // new block larger than all others - insert at end (but before the remainder space, if there)
679f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    newBlock->mNext = currBlock;
689f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    newBlock->mPrev = prevBlock;
699b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
709f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (currBlock) {
719f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        currBlock->mPrev = newBlock;
729f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
739b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
749f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (prevBlock) {
759f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        prevBlock->mNext = newBlock;
769f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        return head;
779f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    } else {
789f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        return newBlock;
799f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
809f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
819f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
82e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain GuyCacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock* blockToRemove) {
839f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#if DEBUG_FONT_RENDERER
849f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    ALOGD("removeBlock: this, x, y, w, h = %p, %d, %d, %d, %d",
859f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            blockToRemove, blockToRemove->mX, blockToRemove->mY,
869f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            blockToRemove->mWidth, blockToRemove->mHeight);
879f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif
889b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
899f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    CacheBlock* newHead = head;
909f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    CacheBlock* nextBlock = blockToRemove->mNext;
919f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    CacheBlock* prevBlock = blockToRemove->mPrev;
929b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
939f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (prevBlock) {
949f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        prevBlock->mNext = nextBlock;
959f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    } else {
969f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        newHead = nextBlock;
979f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
989b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
999f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (nextBlock) {
1009f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        nextBlock->mPrev = prevBlock;
1019f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
1029b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
1039f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    delete blockToRemove;
1049b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
1059f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    return newHead;
1069f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
1079f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1089f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy///////////////////////////////////////////////////////////////////////////////
1099f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy// CacheTexture
1109f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy///////////////////////////////////////////////////////////////////////////////
1119f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
112e2bb380bc26749782c873e5488cfdf4e42b27346Chris CraikCacheTexture::CacheTexture(uint16_t width, uint16_t height, GLenum format, uint32_t maxQuadCount)
113e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        : mTexture(Caches::getInstance())
11438e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        , mWidth(width)
11538e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck        , mHeight(height)
116e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        , mFormat(format)
117e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        , mMaxQuadCount(maxQuadCount)
118e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        , mCaches(Caches::getInstance()) {
119e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik    mTexture.blend = true;
120e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik
121661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
122e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik            getWidth() - TEXTURE_BORDER_SIZE, getHeight() - TEXTURE_BORDER_SIZE);
123cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
124cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    // OpenGL ES 3.0+ lets us specify the row length for unpack operations such
125cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    // as glTexSubImage2D(). This allows us to upload a sub-rectangle of a texture.
126cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    // With OpenGL ES 2.0 we have to upload entire stripes instead.
127117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    mHasUnpackRowLength = mCaches.extensions().hasUnpackRowLength();
128661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
129661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
130661a87ec28a49458f1faf533783abf2ab9927cabRomain GuyCacheTexture::~CacheTexture() {
131661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    releaseMesh();
132e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik    releasePixelBuffer();
133661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    reset();
134661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
135661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
136661a87ec28a49458f1faf533783abf2ab9927cabRomain Guyvoid CacheTexture::reset() {
137661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    // Delete existing cache blocks
138d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik    while (mCacheBlocks != nullptr) {
139661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        CacheBlock* tmpBlock = mCacheBlocks;
140661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        mCacheBlocks = mCacheBlocks->mNext;
141661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        delete tmpBlock;
142661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    }
143661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    mNumGlyphs = 0;
144661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    mCurrentQuad = 0;
145661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
146661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
147661a87ec28a49458f1faf533783abf2ab9927cabRomain Guyvoid CacheTexture::init() {
148661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    // reset, then create a new remainder space to start again
149661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    reset();
150661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
151e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik            getWidth() - TEXTURE_BORDER_SIZE, getHeight() - TEXTURE_BORDER_SIZE);
152661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
153661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
154661a87ec28a49458f1faf533783abf2ab9927cabRomain Guyvoid CacheTexture::releaseMesh() {
155661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    delete[] mMesh;
156661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
157661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
158e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craikvoid CacheTexture::releasePixelBuffer() {
159e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik    if (mPixelBuffer) {
160e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        delete mPixelBuffer;
161e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        mPixelBuffer = nullptr;
162661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    }
16338e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    mTexture.deleteTexture();
164661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    mDirty = false;
165661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    mCurrentQuad = 0;
166661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
167661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
168e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craikvoid CacheTexture::setLinearFiltering(bool linearFiltering) {
169e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik    mTexture.setFilter(linearFiltering ? GL_LINEAR : GL_NEAREST);
170cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy}
171cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
172661a87ec28a49458f1faf533783abf2ab9927cabRomain Guyvoid CacheTexture::allocateMesh() {
173661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    if (!mMesh) {
174661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        mMesh = new TextureVertex[mMaxQuadCount * 4];
175661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    }
176661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
177661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
178e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craikvoid CacheTexture::allocatePixelBuffer() {
179e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik    if (!mPixelBuffer) {
180e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        mPixelBuffer = PixelBuffer::create(mFormat, getWidth(), getHeight());
181661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    }
182661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
18338e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    mTexture.resize(mWidth, mHeight, mFormat);
18438e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    mTexture.setFilter(getLinearFiltering() ? GL_LINEAR : GL_NEAREST);
18538e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck    mTexture.setWrap(GL_CLAMP_TO_EDGE);
186661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
187661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
188cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guybool CacheTexture::upload() {
189cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    const Rect& dirtyRect = mDirtyRect;
190cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
191318ae7bb92869d99a05388c598ad105e7aa4cdbdRomain Guy    uint32_t x = mHasUnpackRowLength ? dirtyRect.left : 0;
192cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    uint32_t y = dirtyRect.top;
193e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik    uint32_t width = mHasUnpackRowLength ? dirtyRect.getWidth() : getWidth();
194cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    uint32_t height = dirtyRect.getHeight();
195cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
196cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    // The unpack row length only needs to be specified when a new
197cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    // texture is bound
198318ae7bb92869d99a05388c598ad105e7aa4cdbdRomain Guy    if (mHasUnpackRowLength) {
199e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik        glPixelStorei(GL_UNPACK_ROW_LENGTH, getWidth());
200cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    }
201cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
202e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik    mPixelBuffer->upload(x, y, width, height);
203cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    setDirty(false);
204cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
205318ae7bb92869d99a05388c598ad105e7aa4cdbdRomain Guy    return mHasUnpackRowLength;
206cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy}
207cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
208cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guyvoid CacheTexture::setDirty(bool dirty) {
209cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    mDirty = dirty;
210cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    if (!dirty) {
211cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy        mDirtyRect.setEmpty();
212cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    }
213cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy}
214cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
215e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guybool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) {
2161e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    switch (glyph.fMaskFormat) {
2171e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        case SkMask::kA8_Format:
218723b2feb929b96b1dde40a865c49ea18bc42f055Victoria Lease        case SkMask::kBW_Format:
2191e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            if (mFormat != GL_ALPHA) {
2201e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease#if DEBUG_FONT_RENDERER
221723b2feb929b96b1dde40a865c49ea18bc42f055Victoria Lease                ALOGD("fitBitmap: texture format %x is inappropriate for monochromatic glyphs",
222723b2feb929b96b1dde40a865c49ea18bc42f055Victoria Lease                        mFormat);
2231e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease#endif
2241e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease                return false;
2251e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            }
2261e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            break;
2271e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        case SkMask::kARGB32_Format:
2281e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            if (mFormat != GL_RGBA) {
2291e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease#if DEBUG_FONT_RENDERER
230723b2feb929b96b1dde40a865c49ea18bc42f055Victoria Lease                ALOGD("fitBitmap: texture format %x is inappropriate for colour glyphs", mFormat);
2311e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease#endif
2321e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease                return false;
2331e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            }
2341e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            break;
2351e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        default:
2361e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease#if DEBUG_FONT_RENDERER
2371e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            ALOGD("fitBitmap: unknown glyph format %x encountered", glyph.fMaskFormat);
2381e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease#endif
2391e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            return false;
2401e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    }
2411e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease
242e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik    if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > getHeight()) {
2439f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        return false;
2449f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
2459f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2469f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint16_t glyphW = glyph.fWidth + TEXTURE_BORDER_SIZE;
2479f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint16_t glyphH = glyph.fHeight + TEXTURE_BORDER_SIZE;
2489b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
2499f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    // roundedUpW equals glyphW to the next multiple of CACHE_BLOCK_ROUNDING_SIZE.
2509f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    // This columns for glyphs that are close but not necessarily exactly the same size. It trades
2519f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    // off the loss of a few pixels for some glyphs against the ability to store more glyphs
2529f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    // of varying sizes in one block.
253e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy    uint16_t roundedUpW = (glyphW + CACHE_BLOCK_ROUNDING_SIZE - 1) & -CACHE_BLOCK_ROUNDING_SIZE;
2549b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
255e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy    CacheBlock* cacheBlock = mCacheBlocks;
2569f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    while (cacheBlock) {
2579f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        // Store glyph in this block iff: it fits the block's remaining space and:
2589f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        // it's the remainder space (mY == 0) or there's only enough height for this one glyph
2599f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        // or it's within ROUNDING_SIZE of the block width
2609f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        if (roundedUpW <= cacheBlock->mWidth && glyphH <= cacheBlock->mHeight &&
2619f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                (cacheBlock->mY == TEXTURE_BORDER_SIZE ||
2629f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                        (cacheBlock->mWidth - roundedUpW < CACHE_BLOCK_ROUNDING_SIZE))) {
2639f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            if (cacheBlock->mHeight - glyphH < glyphH) {
2649f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                // Only enough space for this glyph - don't bother rounding up the width
2659f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                roundedUpW = glyphW;
2669f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            }
2679b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
2689f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            *retOriginX = cacheBlock->mX;
2699f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            *retOriginY = cacheBlock->mY;
2709b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
2719f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            // If this is the remainder space, create a new cache block for this column. Otherwise,
2729f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            // adjust the info about this column.
2739f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            if (cacheBlock->mY == TEXTURE_BORDER_SIZE) {
2749f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                uint16_t oldX = cacheBlock->mX;
2759f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                // Adjust remainder space dimensions
2769f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                cacheBlock->mWidth -= roundedUpW;
2779f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                cacheBlock->mX += roundedUpW;
2789b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
279e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik                if (getHeight() - glyphH >= glyphH) {
2809f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                    // There's enough height left over to create a new CacheBlock
281e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy                    CacheBlock* newBlock = new CacheBlock(oldX, glyphH + TEXTURE_BORDER_SIZE,
282e2bb380bc26749782c873e5488cfdf4e42b27346Chris Craik                            roundedUpW, getHeight() - glyphH - TEXTURE_BORDER_SIZE);
2839f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#if DEBUG_FONT_RENDERER
2849f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                    ALOGD("fitBitmap: Created new block: this, x, y, w, h = %p, %d, %d, %d, %d",
2859f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                            newBlock, newBlock->mX, newBlock->mY,
2869f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                            newBlock->mWidth, newBlock->mHeight);
2879f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif
2889f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                    mCacheBlocks = CacheBlock::insertBlock(mCacheBlocks, newBlock);
2899f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                }
2909f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            } else {
2919f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                // Insert into current column and adjust column dimensions
2929f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                cacheBlock->mY += glyphH;
2939f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                cacheBlock->mHeight -= glyphH;
2949f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#if DEBUG_FONT_RENDERER
2959f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                ALOGD("fitBitmap: Added to existing block: this, x, y, w, h = %p, %d, %d, %d, %d",
2969f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                        cacheBlock, cacheBlock->mX, cacheBlock->mY,
2979f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                        cacheBlock->mWidth, cacheBlock->mHeight);
2989f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif
2999f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            }
3009b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
301e6a15ee3d0c78eb3f2551d73a7d238c3d8d2f075Chris Craik            if (cacheBlock->mHeight < std::min(glyphH, glyphW)) {
3029f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                // If remaining space in this block is too small to be useful, remove it
3039f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                mCacheBlocks = CacheBlock::removeBlock(mCacheBlocks, cacheBlock);
3049f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            }
3059b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
3069f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            mDirty = true;
307b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase            const Rect r(*retOriginX - TEXTURE_BORDER_SIZE, *retOriginY - TEXTURE_BORDER_SIZE,
308b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase                    *retOriginX + glyphW, *retOriginY + glyphH);
309b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase            mDirtyRect.unionWith(r);
3109b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy            mNumGlyphs++;
3119b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
3129f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#if DEBUG_FONT_RENDERER
3139f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            ALOGD("fitBitmap: current block list:");
3149f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            mCacheBlocks->output();
3159f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif
3169b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
3179f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            return true;
3189f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        }
3199f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        cacheBlock = cacheBlock->mNext;
3209f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
3219f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#if DEBUG_FONT_RENDERER
3229f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    ALOGD("fitBitmap: returning false for glyph of size %d, %d", glyphW, glyphH);
3239f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif
3249f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    return false;
3259f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
3269f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
327baf29e7cf433624687c9d6b3bac180d33add8e0fsergeyvuint32_t CacheTexture::calculateFreeMemory() const {
328baf29e7cf433624687c9d6b3bac180d33add8e0fsergeyv    CacheBlock* cacheBlock = mCacheBlocks;
329baf29e7cf433624687c9d6b3bac180d33add8e0fsergeyv    uint32_t free = 0;
330baf29e7cf433624687c9d6b3bac180d33add8e0fsergeyv    // currently only two formats are supported: GL_ALPHA or GL_RGBA;
331baf29e7cf433624687c9d6b3bac180d33add8e0fsergeyv    uint32_t bpp = mFormat == GL_RGBA ? 4 : 1;
332baf29e7cf433624687c9d6b3bac180d33add8e0fsergeyv    while (cacheBlock) {
333baf29e7cf433624687c9d6b3bac180d33add8e0fsergeyv        free += bpp * cacheBlock->mWidth * cacheBlock->mHeight;
334baf29e7cf433624687c9d6b3bac180d33add8e0fsergeyv        cacheBlock = cacheBlock->mNext;
335baf29e7cf433624687c9d6b3bac180d33add8e0fsergeyv    }
336baf29e7cf433624687c9d6b3bac180d33add8e0fsergeyv    return free;
337baf29e7cf433624687c9d6b3bac180d33add8e0fsergeyv}
338baf29e7cf433624687c9d6b3bac180d33add8e0fsergeyv
3399f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}; // namespace uirenderer
3409f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}; // namespace android
341