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"
208aa195d7081b889f3a7b1f426cbd8556377aae5eRomain Guy#include "../Caches.h"
210908764b2b3cf5075df4178a5f0a8547dcb7b317Romain Guy#include "../Debug.h"
22cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy#include "../Extensions.h"
23cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy#include "../PixelBuffer.h"
249f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
259f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guynamespace android {
269f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guynamespace uirenderer {
279f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
289f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy///////////////////////////////////////////////////////////////////////////////
299f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy// CacheBlock
309f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy///////////////////////////////////////////////////////////////////////////////
319f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
329f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy/**
339f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * Insert new block into existing linked list of blocks. Blocks are sorted in increasing-width
349f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * order, except for the final block (the remainder space at the right, since we fill from the
359f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy * left).
369f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy */
37e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain GuyCacheBlock* CacheBlock::insertBlock(CacheBlock* head, CacheBlock* newBlock) {
389f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#if DEBUG_FONT_RENDERER
399f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    ALOGD("insertBlock: this, x, y, w, h = %p, %d, %d, %d, %d",
409f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            newBlock, newBlock->mX, newBlock->mY,
419f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            newBlock->mWidth, newBlock->mHeight);
429f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif
439b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
44e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy    CacheBlock* currBlock = head;
45e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy    CacheBlock* prevBlock = NULL;
469b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
479f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    while (currBlock && currBlock->mY != TEXTURE_BORDER_SIZE) {
489f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        if (newBlock->mWidth < currBlock->mWidth) {
499f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            newBlock->mNext = currBlock;
509f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            newBlock->mPrev = prevBlock;
519f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            currBlock->mPrev = newBlock;
529b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
539f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            if (prevBlock) {
549f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                prevBlock->mNext = newBlock;
559f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                return head;
569f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            } else {
579f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                return newBlock;
589f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            }
599f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        }
609b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
619f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        prevBlock = currBlock;
629f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        currBlock = currBlock->mNext;
639f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
649b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
659f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    // new block larger than all others - insert at end (but before the remainder space, if there)
669f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    newBlock->mNext = currBlock;
679f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    newBlock->mPrev = prevBlock;
689b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
699f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (currBlock) {
709f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        currBlock->mPrev = newBlock;
719f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
729b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
739f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (prevBlock) {
749f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        prevBlock->mNext = newBlock;
759f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        return head;
769f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    } else {
779f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        return newBlock;
789f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
799f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
809f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
81e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain GuyCacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock* blockToRemove) {
829f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#if DEBUG_FONT_RENDERER
839f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    ALOGD("removeBlock: this, x, y, w, h = %p, %d, %d, %d, %d",
849f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            blockToRemove, blockToRemove->mX, blockToRemove->mY,
859f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            blockToRemove->mWidth, blockToRemove->mHeight);
869f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif
879b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
889f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    CacheBlock* newHead = head;
899f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    CacheBlock* nextBlock = blockToRemove->mNext;
909f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    CacheBlock* prevBlock = blockToRemove->mPrev;
919b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
929f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (prevBlock) {
939f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        prevBlock->mNext = nextBlock;
949f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    } else {
959f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        newHead = nextBlock;
969f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
979b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
989f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    if (nextBlock) {
999f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        nextBlock->mPrev = prevBlock;
1009f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
1019b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
1029f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    delete blockToRemove;
1039b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
1049f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    return newHead;
1059f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
1069f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1079f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy///////////////////////////////////////////////////////////////////////////////
1089f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy// CacheTexture
1099f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy///////////////////////////////////////////////////////////////////////////////
1109f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
1111e546815bbb736c50679a8aefc25f48561026fc5Victoria LeaseCacheTexture::CacheTexture(uint16_t width, uint16_t height, GLenum format, uint32_t maxQuadCount) :
1121e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height), mFormat(format),
113661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy            mLinearFiltering(false), mDirty(false), mNumGlyphs(0),
1148aa195d7081b889f3a7b1f426cbd8556377aae5eRomain Guy            mMesh(NULL), mCurrentQuad(0), mMaxQuadCount(maxQuadCount),
1158aa195d7081b889f3a7b1f426cbd8556377aae5eRomain Guy            mCaches(Caches::getInstance()) {
116661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
117e63f7c622a2086aefa80983c6f41b74fb166bb42Chris Craik            mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE);
118cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
119cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    // OpenGL ES 3.0+ lets us specify the row length for unpack operations such
120cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    // as glTexSubImage2D(). This allows us to upload a sub-rectangle of a texture.
121cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    // With OpenGL ES 2.0 we have to upload entire stripes instead.
122318ae7bb92869d99a05388c598ad105e7aa4cdbdRomain Guy    mHasUnpackRowLength = Extensions::getInstance().hasUnpackRowLength();
123661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
124661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
125661a87ec28a49458f1faf533783abf2ab9927cabRomain GuyCacheTexture::~CacheTexture() {
126661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    releaseMesh();
127661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    releaseTexture();
128661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    reset();
129661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
130661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
131661a87ec28a49458f1faf533783abf2ab9927cabRomain Guyvoid CacheTexture::reset() {
132661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    // Delete existing cache blocks
133661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    while (mCacheBlocks != NULL) {
134661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        CacheBlock* tmpBlock = mCacheBlocks;
135661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        mCacheBlocks = mCacheBlocks->mNext;
136661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        delete tmpBlock;
137661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    }
138661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    mNumGlyphs = 0;
139661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    mCurrentQuad = 0;
140661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
141661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
142661a87ec28a49458f1faf533783abf2ab9927cabRomain Guyvoid CacheTexture::init() {
143661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    // reset, then create a new remainder space to start again
144661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    reset();
145661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
146e63f7c622a2086aefa80983c6f41b74fb166bb42Chris Craik            mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE);
147661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
148661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
149661a87ec28a49458f1faf533783abf2ab9927cabRomain Guyvoid CacheTexture::releaseMesh() {
150661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    delete[] mMesh;
151661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
152661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
153661a87ec28a49458f1faf533783abf2ab9927cabRomain Guyvoid CacheTexture::releaseTexture() {
154661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    if (mTexture) {
155cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy        delete mTexture;
156661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        mTexture = NULL;
157661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    }
158661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    if (mTextureId) {
159be1b127c7bec252e0c6ab0e06ed6babed07d496fRomain Guy        mCaches.deleteTexture(mTextureId);
160661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        mTextureId = 0;
161661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    }
162661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    mDirty = false;
163661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    mCurrentQuad = 0;
164661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
165661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
166cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guyvoid CacheTexture::setLinearFiltering(bool linearFiltering, bool bind) {
167cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy   if (linearFiltering != mLinearFiltering) {
168cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy       mLinearFiltering = linearFiltering;
169cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
170cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy       const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST;
1718aa195d7081b889f3a7b1f426cbd8556377aae5eRomain Guy       if (bind) mCaches.bindTexture(getTextureId());
172cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
173cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
174cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy   }
175cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy}
176cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
177661a87ec28a49458f1faf533783abf2ab9927cabRomain Guyvoid CacheTexture::allocateMesh() {
178661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    if (!mMesh) {
179661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        mMesh = new TextureVertex[mMaxQuadCount * 4];
180661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    }
181661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
182661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
183661a87ec28a49458f1faf533783abf2ab9927cabRomain Guyvoid CacheTexture::allocateTexture() {
184661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    if (!mTexture) {
1851e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        mTexture = PixelBuffer::create(mFormat, mWidth, mHeight);
186661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    }
187661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
188661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    if (!mTextureId) {
189661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        glGenTextures(1, &mTextureId);
190661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
1918aa195d7081b889f3a7b1f426cbd8556377aae5eRomain Guy        mCaches.bindTexture(mTextureId);
192661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
193661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        // Initialize texture dimensions
1941e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        glTexImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0,
1951e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease                mFormat, GL_UNSIGNED_BYTE, 0);
196661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
197661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        const GLenum filtering = getLinearFiltering() ? GL_LINEAR : GL_NEAREST;
198661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
199661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
200661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
201661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
202661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
203661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy    }
204661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy}
205661a87ec28a49458f1faf533783abf2ab9927cabRomain Guy
206cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guybool CacheTexture::upload() {
207cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    const Rect& dirtyRect = mDirtyRect;
208cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
209318ae7bb92869d99a05388c598ad105e7aa4cdbdRomain Guy    uint32_t x = mHasUnpackRowLength ? dirtyRect.left : 0;
210cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    uint32_t y = dirtyRect.top;
211318ae7bb92869d99a05388c598ad105e7aa4cdbdRomain Guy    uint32_t width = mHasUnpackRowLength ? dirtyRect.getWidth() : mWidth;
212cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    uint32_t height = dirtyRect.getHeight();
213cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
214cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    // The unpack row length only needs to be specified when a new
215cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    // texture is bound
216318ae7bb92869d99a05388c598ad105e7aa4cdbdRomain Guy    if (mHasUnpackRowLength) {
217cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy        glPixelStorei(GL_UNPACK_ROW_LENGTH, mWidth);
218cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    }
219cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
2201e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    mTexture->upload(x, y, width, height);
221cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    setDirty(false);
222cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
223318ae7bb92869d99a05388c598ad105e7aa4cdbdRomain Guy    return mHasUnpackRowLength;
224cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy}
225cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
226cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guyvoid CacheTexture::setDirty(bool dirty) {
227cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    mDirty = dirty;
228cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    if (!dirty) {
229cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy        mDirtyRect.setEmpty();
230cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    }
231cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy}
232cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy
233e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guybool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) {
2341e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    switch (glyph.fMaskFormat) {
2351e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        case SkMask::kA8_Format:
236723b2feb929b96b1dde40a865c49ea18bc42f055Victoria Lease        case SkMask::kBW_Format:
2371e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            if (mFormat != GL_ALPHA) {
2381e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease#if DEBUG_FONT_RENDERER
239723b2feb929b96b1dde40a865c49ea18bc42f055Victoria Lease                ALOGD("fitBitmap: texture format %x is inappropriate for monochromatic glyphs",
240723b2feb929b96b1dde40a865c49ea18bc42f055Victoria Lease                        mFormat);
2411e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease#endif
2421e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease                return false;
2431e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            }
2441e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            break;
2451e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        case SkMask::kARGB32_Format:
2461e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            if (mFormat != GL_RGBA) {
2471e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease#if DEBUG_FONT_RENDERER
248723b2feb929b96b1dde40a865c49ea18bc42f055Victoria Lease                ALOGD("fitBitmap: texture format %x is inappropriate for colour glyphs", mFormat);
2491e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease#endif
2501e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease                return false;
2511e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            }
2521e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            break;
2531e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease        default:
2541e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease#if DEBUG_FONT_RENDERER
2551e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            ALOGD("fitBitmap: unknown glyph format %x encountered", glyph.fMaskFormat);
2561e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease#endif
2571e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease            return false;
2581e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    }
2591e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease
260e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy    if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > mHeight) {
2619f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        return false;
2629f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
2639f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
2649f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint16_t glyphW = glyph.fWidth + TEXTURE_BORDER_SIZE;
2659f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    uint16_t glyphH = glyph.fHeight + TEXTURE_BORDER_SIZE;
2669b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
2679f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    // roundedUpW equals glyphW to the next multiple of CACHE_BLOCK_ROUNDING_SIZE.
2689f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    // This columns for glyphs that are close but not necessarily exactly the same size. It trades
2699f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    // off the loss of a few pixels for some glyphs against the ability to store more glyphs
2709f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    // of varying sizes in one block.
271e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy    uint16_t roundedUpW = (glyphW + CACHE_BLOCK_ROUNDING_SIZE - 1) & -CACHE_BLOCK_ROUNDING_SIZE;
2729b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
273e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy    CacheBlock* cacheBlock = mCacheBlocks;
2749f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    while (cacheBlock) {
2759f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        // Store glyph in this block iff: it fits the block's remaining space and:
2769f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        // it's the remainder space (mY == 0) or there's only enough height for this one glyph
2779f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        // or it's within ROUNDING_SIZE of the block width
2789f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        if (roundedUpW <= cacheBlock->mWidth && glyphH <= cacheBlock->mHeight &&
2799f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                (cacheBlock->mY == TEXTURE_BORDER_SIZE ||
2809f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                        (cacheBlock->mWidth - roundedUpW < CACHE_BLOCK_ROUNDING_SIZE))) {
2819f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            if (cacheBlock->mHeight - glyphH < glyphH) {
2829f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                // Only enough space for this glyph - don't bother rounding up the width
2839f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                roundedUpW = glyphW;
2849f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            }
2859b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
2869f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            *retOriginX = cacheBlock->mX;
2879f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            *retOriginY = cacheBlock->mY;
2889b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
2899f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            // If this is the remainder space, create a new cache block for this column. Otherwise,
2909f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            // adjust the info about this column.
2919f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            if (cacheBlock->mY == TEXTURE_BORDER_SIZE) {
2929f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                uint16_t oldX = cacheBlock->mX;
2939f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                // Adjust remainder space dimensions
2949f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                cacheBlock->mWidth -= roundedUpW;
2959f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                cacheBlock->mX += roundedUpW;
2969b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
2979f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                if (mHeight - glyphH >= glyphH) {
2989f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                    // There's enough height left over to create a new CacheBlock
299e43f785b7ff3fdf75f6d1c92282ebca6db191f2fRomain Guy                    CacheBlock* newBlock = new CacheBlock(oldX, glyphH + TEXTURE_BORDER_SIZE,
3009f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                            roundedUpW, mHeight - glyphH - TEXTURE_BORDER_SIZE);
3019f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#if DEBUG_FONT_RENDERER
3029f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                    ALOGD("fitBitmap: Created new block: this, x, y, w, h = %p, %d, %d, %d, %d",
3039f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                            newBlock, newBlock->mX, newBlock->mY,
3049f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                            newBlock->mWidth, newBlock->mHeight);
3059f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif
3069f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                    mCacheBlocks = CacheBlock::insertBlock(mCacheBlocks, newBlock);
3079f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                }
3089f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            } else {
3099f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                // Insert into current column and adjust column dimensions
3109f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                cacheBlock->mY += glyphH;
3119f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                cacheBlock->mHeight -= glyphH;
3129f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#if DEBUG_FONT_RENDERER
3139f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                ALOGD("fitBitmap: Added to existing block: this, x, y, w, h = %p, %d, %d, %d, %d",
3149f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                        cacheBlock, cacheBlock->mX, cacheBlock->mY,
3159f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                        cacheBlock->mWidth, cacheBlock->mHeight);
3169f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif
3179f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            }
3189b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
3199f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            if (cacheBlock->mHeight < fmin(glyphH, glyphW)) {
3209f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                // If remaining space in this block is too small to be useful, remove it
3219f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy                mCacheBlocks = CacheBlock::removeBlock(mCacheBlocks, cacheBlock);
3229f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            }
3239b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
3249f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            mDirty = true;
325b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase            const Rect r(*retOriginX - TEXTURE_BORDER_SIZE, *retOriginY - TEXTURE_BORDER_SIZE,
326b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase                    *retOriginX + glyphW, *retOriginY + glyphH);
327b92d8f7979c29c7c09932578a11b2f8d6eec1d90Chet Haase            mDirtyRect.unionWith(r);
3289b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy            mNumGlyphs++;
3299b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
3309f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#if DEBUG_FONT_RENDERER
3319f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            ALOGD("fitBitmap: current block list:");
3329f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            mCacheBlocks->output();
3339f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif
3349b1204baf4740b4d443e72157dea98571cf84e1fRomain Guy
3359f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy            return true;
3369f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        }
3379f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy        cacheBlock = cacheBlock->mNext;
3389f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    }
3399f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#if DEBUG_FONT_RENDERER
3409f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    ALOGD("fitBitmap: returning false for glyph of size %d, %d", glyphW, glyphH);
3419f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy#endif
3429f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy    return false;
3439f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}
3449f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy
3459f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}; // namespace uirenderer
3469f5dab3fc228fa11c32b483e6101ec086895a32bRomain Guy}; // namespace android
347