11e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy/* 21e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * Copyright (C) 2010 The Android Open Source Project 31e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * 41e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * Licensed under the Apache License, Version 2.0 (the "License"); 51e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * you may not use this file except in compliance with the License. 61e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * You may obtain a copy of the License at 71e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * 81e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * http://www.apache.org/licenses/LICENSE-2.0 91e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * 101e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * Unless required by applicable law or agreed to in writing, software 111e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * distributed under the License is distributed on an "AS IS" BASIS, 121e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * See the License for the specific language governing permissions and 141e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy * limitations under the License. 151e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy */ 161e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 17059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy#include <utils/JenkinsHash.h> 18059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy 198aa195d7081b889f3a7b1f426cbd8556377aae5eRomain Guy#include "Caches.h" 20c9855a53edfac818dc68714557185977556f849dRomain Guy#include "Debug.h" 212dc236b2bae13b9a0ed9b3f7320502aecd7983b3Tom Hudson#include "FontRenderer.h" 221e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy#include "TextDropShadowCache.h" 23b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy#include "Properties.h" 241e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 251e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guynamespace android { 261e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guynamespace uirenderer { 271e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 281e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy/////////////////////////////////////////////////////////////////////////////// 29059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy// Cache support 30059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy/////////////////////////////////////////////////////////////////////////////// 31059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy 32059e12ccd20f5c249724a8362d6bac325334ea76Romain Guyhash_t ShadowText::hash() const { 33a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik uint32_t hash = JenkinsHashMix(0, glyphCount); 34059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy hash = JenkinsHashMix(hash, android::hash_type(radius)); 35059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy hash = JenkinsHashMix(hash, android::hash_type(textSize)); 36059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy hash = JenkinsHashMix(hash, android::hash_type(typeface)); 37059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy hash = JenkinsHashMix(hash, flags); 38059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy hash = JenkinsHashMix(hash, android::hash_type(italicStyle)); 39059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy hash = JenkinsHashMix(hash, android::hash_type(scaleX)); 40e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik if (glyphs) { 416698749dd4d4d6513b26aa9071af290b956b68a7Dan Albert hash = JenkinsHashMixShorts( 42e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik hash, reinterpret_cast<const uint16_t*>(glyphs), glyphCount); 4369fcbccf476ffc55af4da4dfedc72c3de8f91ce8Romain Guy } 4469fcbccf476ffc55af4da4dfedc72c3de8f91ce8Romain Guy if (positions) { 45a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik for (uint32_t i = 0; i < glyphCount * 2; i++) { 4669fcbccf476ffc55af4da4dfedc72c3de8f91ce8Romain Guy hash = JenkinsHashMix(hash, android::hash_type(positions[i])); 4769fcbccf476ffc55af4da4dfedc72c3de8f91ce8Romain Guy } 48059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy } 49059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy return JenkinsHashWhiten(hash); 50059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy} 51059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy 52059e12ccd20f5c249724a8362d6bac325334ea76Romain Guyint ShadowText::compare(const ShadowText& lhs, const ShadowText& rhs) { 53a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik int deltaInt = int(lhs.glyphCount) - int(rhs.glyphCount); 54059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy if (deltaInt != 0) return deltaInt; 55059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy 56059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy deltaInt = lhs.flags - rhs.flags; 57059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy if (deltaInt != 0) return deltaInt; 58059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy 59059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy if (lhs.radius < rhs.radius) return -1; 60059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy if (lhs.radius > rhs.radius) return +1; 61059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy 62059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy if (lhs.typeface < rhs.typeface) return -1; 63059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy if (lhs.typeface > rhs.typeface) return +1; 64059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy 65059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy if (lhs.textSize < rhs.textSize) return -1; 66059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy if (lhs.textSize > rhs.textSize) return +1; 67059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy 68059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy if (lhs.italicStyle < rhs.italicStyle) return -1; 69059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy if (lhs.italicStyle > rhs.italicStyle) return +1; 70059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy 71059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy if (lhs.scaleX < rhs.scaleX) return -1; 72059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy if (lhs.scaleX > rhs.scaleX) return +1; 73059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy 74e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik if (lhs.glyphs != rhs.glyphs) { 75e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik if (!lhs.glyphs) return -1; 76e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik if (!rhs.glyphs) return +1; 77059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy 78e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris Craik deltaInt = memcmp(lhs.glyphs, rhs.glyphs, lhs.glyphCount * sizeof(glyph_t)); 79059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy if (deltaInt != 0) return deltaInt; 80059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy } 81059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy 82059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy if (lhs.positions != rhs.positions) { 83059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy if (!lhs.positions) return -1; 84059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy if (!rhs.positions) return +1; 85059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy 86086847797142a25e9e21611e9864c53abfca174fChris Craik return memcmp(lhs.positions, rhs.positions, lhs.glyphCount * sizeof(float) * 2); 87059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy } 88059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy 89059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy return 0; 90059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy} 91059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy 92059e12ccd20f5c249724a8362d6bac325334ea76Romain Guy/////////////////////////////////////////////////////////////////////////////// 931e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy// Constructors/destructor 941e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy/////////////////////////////////////////////////////////////////////////////// 951e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 9648a8f431fa52ae2ee25ffba9d20676f03bb710ffChris CraikTextDropShadowCache::TextDropShadowCache() 9748a8f431fa52ae2ee25ffba9d20676f03bb710ffChris Craik : TextDropShadowCache(Properties::textDropShadowCacheSize) {} 98fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy 9948a8f431fa52ae2ee25ffba9d20676f03bb710ffChris CraikTextDropShadowCache::TextDropShadowCache(uint32_t maxByteSize) 10048a8f431fa52ae2ee25ffba9d20676f03bb710ffChris Craik : mCache(LruCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity) 10148a8f431fa52ae2ee25ffba9d20676f03bb710ffChris Craik , mSize(0) 10248a8f431fa52ae2ee25ffba9d20676f03bb710ffChris Craik , mMaxSize(maxByteSize) { 10348a8f431fa52ae2ee25ffba9d20676f03bb710ffChris Craik mCache.setOnEntryRemovedListener(this); 10448a8f431fa52ae2ee25ffba9d20676f03bb710ffChris Craik mDebugEnabled = Properties::debugLevel & kDebugMoreCaches; 1051e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy} 1061e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1071e45aae5de003657e5d18f74d34998f5de5db5b7Romain GuyTextDropShadowCache::~TextDropShadowCache() { 1081e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy mCache.clear(); 1091e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy} 1101e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1111e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy/////////////////////////////////////////////////////////////////////////////// 1121e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy// Size management 1131e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy/////////////////////////////////////////////////////////////////////////////// 1141e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1151e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guyuint32_t TextDropShadowCache::getSize() { 1161e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy return mSize; 1171e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy} 1181e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1191e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guyuint32_t TextDropShadowCache::getMaxSize() { 1201e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy return mMaxSize; 1211e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy} 1221e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1231e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy/////////////////////////////////////////////////////////////////////////////// 1241e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy// Callbacks 1251e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy/////////////////////////////////////////////////////////////////////////////// 1261e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 127e63f7c622a2086aefa80983c6f41b74fb166bb42Chris Craikvoid TextDropShadowCache::operator()(ShadowText&, ShadowTexture*& texture) { 1281e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (texture) { 129c3127a78b996a540cd002e5a87861e8a2adeb336John Reck mSize -= texture->objectSize(); 13025dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guy 13125dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guy if (mDebugEnabled) { 1325baa3a62a97544669fba6d65a11c07f252e654ddSteve Block ALOGD("Shadow texture deleted, size = %d", texture->bitmapSize); 13325dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guy } 134f70a7e34953438dd70573dbb6fd3dd34a1bce831Romain Guy 135be1b127c7bec252e0c6ab0e06ed6babed07d496fRomain Guy texture->deleteTexture(); 1361e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy delete texture; 1371e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } 1381e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy} 1391e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1401e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy/////////////////////////////////////////////////////////////////////////////// 1411e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy// Caching 1421e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy/////////////////////////////////////////////////////////////////////////////// 1431e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1441e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guyvoid TextDropShadowCache::clear() { 1451e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy mCache.clear(); 1461e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy} 1471e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 148e8c3c813b0e3ac98304b17a751ce6e436e252bd9Chris CraikShadowTexture* TextDropShadowCache::get(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, 149a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik float radius, const float* positions) { 150086847797142a25e9e21611e9864c53abfca174fChris Craik ShadowText entry(paint, radius, numGlyphs, glyphs, positions); 1511e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy ShadowTexture* texture = mCache.get(entry); 1521e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1531e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (!texture) { 1548b4072d3fb9bb49d774d97689a065204beca1752Raph Levien SkPaint paintCopy(*paint); 1558b4072d3fb9bb49d774d97689a065204beca1752Raph Levien paintCopy.setTextAlign(SkPaint::kLeft_Align); 156a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik FontRenderer::DropShadow shadow = mRenderer->renderDropShadow(&paintCopy, glyphs, numGlyphs, 157a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik radius, positions); 1581e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 159cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy if (!shadow.image) { 160d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik return nullptr; 161cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy } 162cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy 1638aa195d7081b889f3a7b1f426cbd8556377aae5eRomain Guy Caches& caches = Caches::getInstance(); 1648aa195d7081b889f3a7b1f426cbd8556377aae5eRomain Guy 1658aa195d7081b889f3a7b1f426cbd8556377aae5eRomain Guy texture = new ShadowTexture(caches); 1661e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy texture->left = shadow.penX; 1671e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy texture->top = shadow.penY; 1681e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy texture->generation = 0; 1691e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy texture->blend = true; 1701e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1711e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy const uint32_t size = shadow.width * shadow.height; 17225dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guy 1731e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy // Don't even try to cache a bitmap that's bigger than the cache 1741e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (size < mMaxSize) { 1751e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy while (mSize + size > mMaxSize) { 176c3127a78b996a540cd002e5a87861e8a2adeb336John Reck LOG_ALWAYS_FATAL_IF(!mCache.removeOldest(), 177c3127a78b996a540cd002e5a87861e8a2adeb336John Reck "Failed to remove oldest from cache. mSize = %" 178c3127a78b996a540cd002e5a87861e8a2adeb336John Reck PRIu32 ", mCache.size() = %zu", mSize, mCache.size()); 1791e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } 1801e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } 1811e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1821e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy // Textures are Alpha8 18338e0c32852e3b9d8ca4a9d3791577f52536419cbJohn Reck texture->upload(GL_ALPHA, shadow.width, shadow.height, 1841e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy GL_ALPHA, GL_UNSIGNED_BYTE, shadow.image); 18539d252a6632d057d5077f7eaf1b8ed7a142f3397Romain Guy texture->setFilter(GL_LINEAR); 18639d252a6632d057d5077f7eaf1b8ed7a142f3397Romain Guy texture->setWrap(GL_CLAMP_TO_EDGE); 1871e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 1881e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy if (size < mMaxSize) { 18925dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guy if (mDebugEnabled) { 1905baa3a62a97544669fba6d65a11c07f252e654ddSteve Block ALOGD("Shadow texture created, size = %d", texture->bitmapSize); 19125dc3a7dbac2f90f5144035e9c8ed99c09cc3132Romain Guy } 192321dce646dc3c2ecfbd72a693d8d9294a6119736Romain Guy 193321dce646dc3c2ecfbd72a693d8d9294a6119736Romain Guy entry.copyTextLocally(); 194321dce646dc3c2ecfbd72a693d8d9294a6119736Romain Guy 195c3127a78b996a540cd002e5a87861e8a2adeb336John Reck mSize += texture->objectSize(); 1961e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy mCache.put(entry, texture); 1971e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } else { 1981e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy texture->cleanup = true; 1991e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } 2001e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 2011e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy // Cleanup shadow 20215641a6181cdaac2aadf07585de66483b4b7ae6bBen Cheng free(shadow.image); 2031e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy } 2041e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 2051e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy return texture; 2061e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy} 2071e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy 2081e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy}; // namespace uirenderer 2091e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy}; // namespace android 210