TextDropShadowCache.cpp revision b45c0c9774bd19a9dbe77d149abae4e124b08bf6
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "OpenGLRenderer"
18
19#include "TextDropShadowCache.h"
20#include "Properties.h"
21
22namespace android {
23namespace uirenderer {
24
25///////////////////////////////////////////////////////////////////////////////
26// Constructors/destructor
27///////////////////////////////////////////////////////////////////////////////
28
29TextDropShadowCache::TextDropShadowCache():
30        mCache(GenerationCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity),
31        mSize(0), mMaxSize(MB(DEFAULT_DROP_SHADOW_CACHE_SIZE)) {
32    char property[PROPERTY_VALUE_MAX];
33    if (property_get(PROPERTY_DROP_SHADOW_CACHE_SIZE, property, NULL) > 0) {
34        LOGD("  Setting drop shadow cache size to %sMB", property);
35        setMaxSize(MB(atof(property)));
36    } else {
37        LOGD("  Using default drop shadow cache size of %.2fMB", DEFAULT_DROP_SHADOW_CACHE_SIZE);
38    }
39
40    mCache.setOnEntryRemovedListener(this);
41}
42
43TextDropShadowCache::TextDropShadowCache(uint32_t maxByteSize):
44        mCache(GenerationCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity),
45        mSize(0), mMaxSize(maxByteSize) {
46    mCache.setOnEntryRemovedListener(this);
47}
48
49TextDropShadowCache::~TextDropShadowCache() {
50    mCache.clear();
51}
52
53///////////////////////////////////////////////////////////////////////////////
54// Size management
55///////////////////////////////////////////////////////////////////////////////
56
57uint32_t TextDropShadowCache::getSize() {
58    return mSize;
59}
60
61uint32_t TextDropShadowCache::getMaxSize() {
62    return mMaxSize;
63}
64
65void TextDropShadowCache::setMaxSize(uint32_t maxSize) {
66    mMaxSize = maxSize;
67    while (mSize > mMaxSize) {
68        mCache.removeOldest();
69    }
70}
71
72///////////////////////////////////////////////////////////////////////////////
73// Callbacks
74///////////////////////////////////////////////////////////////////////////////
75
76void TextDropShadowCache::operator()(ShadowText& text, ShadowTexture*& texture) {
77    const uint32_t size = texture->width * texture->height;
78    mSize -= size;
79
80    if (texture) {
81        glDeleteTextures(1, &texture->id);
82        delete texture;
83    }
84}
85
86///////////////////////////////////////////////////////////////////////////////
87// Caching
88///////////////////////////////////////////////////////////////////////////////
89
90void TextDropShadowCache::clear() {
91    mCache.clear();
92}
93
94ShadowTexture* TextDropShadowCache::get(SkPaint* paint, const char* text, uint32_t len,
95        int numGlyphs, uint32_t radius) {
96    ShadowText entry(paint, radius, len, text);
97    ShadowTexture* texture = mCache.get(entry);
98
99    if (!texture) {
100        FontRenderer::DropShadow shadow = mRenderer->renderDropShadow(paint, text, 0,
101                len, numGlyphs, radius);
102
103        texture = new ShadowTexture;
104        texture->left = shadow.penX;
105        texture->top = shadow.penY;
106        texture->width = shadow.width;
107        texture->height = shadow.height;
108        texture->generation = 0;
109        texture->blend = true;
110
111        const uint32_t size = shadow.width * shadow.height;
112        // Don't even try to cache a bitmap that's bigger than the cache
113        if (size < mMaxSize) {
114            while (mSize + size > mMaxSize) {
115                mCache.removeOldest();
116            }
117        }
118
119        glGenTextures(1, &texture->id);
120
121        glBindTexture(GL_TEXTURE_2D, texture->id);
122        // Textures are Alpha8
123        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
124
125        glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0,
126                GL_ALPHA, GL_UNSIGNED_BYTE, shadow.image);
127
128        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
129        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
130
131        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
132        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
133
134        if (size < mMaxSize) {
135            mSize += size;
136            mCache.put(entry, texture);
137        } else {
138            texture->cleanup = true;
139        }
140
141        // Cleanup shadow
142        delete[] shadow.image;
143    }
144
145    return texture;
146}
147
148}; // namespace uirenderer
149}; // namespace android
150