1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/base/favicons/cache/FaviconsForURL.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,164 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +package org.mozilla.gecko.favicons.cache; 1.9 + 1.10 +import android.graphics.Bitmap; 1.11 +import android.util.Log; 1.12 +import org.mozilla.gecko.gfx.BitmapUtils; 1.13 + 1.14 +import java.util.ArrayList; 1.15 +import java.util.Collections; 1.16 + 1.17 +public class FaviconsForURL { 1.18 + private static final String LOGTAG = "FaviconForURL"; 1.19 + 1.20 + private volatile int dominantColor = -1; 1.21 + 1.22 + final long downloadTimestamp; 1.23 + final ArrayList<FaviconCacheElement> favicons; 1.24 + 1.25 + public final boolean hasFailed; 1.26 + 1.27 + public FaviconsForURL(int size) { 1.28 + this(size, false); 1.29 + } 1.30 + 1.31 + public FaviconsForURL(int size, boolean failed) { 1.32 + hasFailed = failed; 1.33 + downloadTimestamp = System.currentTimeMillis(); 1.34 + favicons = new ArrayList<FaviconCacheElement>(size); 1.35 + } 1.36 + 1.37 + public FaviconCacheElement addSecondary(Bitmap favicon, int imageSize) { 1.38 + return addInternal(favicon, false, imageSize); 1.39 + } 1.40 + 1.41 + public FaviconCacheElement addPrimary(Bitmap favicon) { 1.42 + return addInternal(favicon, true, favicon.getWidth()); 1.43 + } 1.44 + 1.45 + private FaviconCacheElement addInternal(Bitmap favicon, boolean isPrimary, int imageSize) { 1.46 + FaviconCacheElement c = new FaviconCacheElement(favicon, isPrimary, imageSize, this); 1.47 + 1.48 + int index = Collections.binarySearch(favicons, c); 1.49 + 1.50 + // We've already got an equivalent one. We don't care about this new one. This only occurs in certain obscure 1.51 + // case conditions. 1.52 + if (index >= 0) { 1.53 + return favicons.get(index); 1.54 + } 1.55 + 1.56 + // binarySearch returns -x - 1 where x is the insertion point of the element. Convert 1.57 + // this to the actual insertion point.. 1.58 + index++; 1.59 + index = -index; 1.60 + favicons.add(index, c); 1.61 + 1.62 + return c; 1.63 + } 1.64 + 1.65 + /** 1.66 + * Get the index of the smallest image in this collection larger than or equal to 1.67 + * the given target size. 1.68 + * 1.69 + * @param targetSize Minimum size for the desired result. 1.70 + * @return The index of the smallest image larger than the target size, or -1 if none exists. 1.71 + */ 1.72 + public int getNextHighestIndex(int targetSize) { 1.73 + // Create a dummy object to hold the target value for comparable. 1.74 + FaviconCacheElement dummy = new FaviconCacheElement(null, false, targetSize, null); 1.75 + 1.76 + int index = Collections.binarySearch(favicons, dummy); 1.77 + 1.78 + // The search routine returns the index of an element equal to dummy, if present. 1.79 + // Otherwise, it returns -x - 1, where x is the index in the ArrayList where dummy would be 1.80 + // inserted if the list were to remain sorted. 1.81 + if (index < 0) { 1.82 + index++; 1.83 + index = -index; 1.84 + } 1.85 + 1.86 + // index is now 'x', as described above. 1.87 + 1.88 + // The routine will return favicons.size() as the index iff dummy is larger than all elements 1.89 + // present (So the "index at which it should be inserted" is the index after the end. 1.90 + // In this case, we set the sentinel value -1 to indicate that we just requested something 1.91 + // larger than all primaries. 1.92 + if (index == favicons.size()) { 1.93 + index = -1; 1.94 + } 1.95 + 1.96 + return index; 1.97 + } 1.98 + 1.99 + /** 1.100 + * Get the next valid primary icon from this collection, starting at the given index. 1.101 + * If the appropriate icon is found, but is invalid, we return null - the proper response is to 1.102 + * reacquire the primary from the database. 1.103 + * If no icon is found, the search is repeated going backwards from the start index to find any 1.104 + * primary at all (The input index may be a secondary which is larger than the actual available 1.105 + * primary.) 1.106 + * 1.107 + * @param fromIndex The index into favicons from which to start the search. 1.108 + * @return The FaviconCacheElement of the next valid primary from the given index. If none exists, 1.109 + * then returns the previous valid primary. If none exists, returns null (Insanity.). 1.110 + */ 1.111 + public FaviconCacheElement getNextPrimary(final int fromIndex) { 1.112 + final int numIcons = favicons.size(); 1.113 + 1.114 + int searchIndex = fromIndex; 1.115 + while (searchIndex < numIcons) { 1.116 + FaviconCacheElement element = favicons.get(searchIndex); 1.117 + 1.118 + if (element.isPrimary) { 1.119 + if (element.invalidated) { 1.120 + // We return null here, despite the possible existence of other primaries, 1.121 + // because we know the most suitable primary for this request exists, but is 1.122 + // no longer in the cache. By returning null, we cause the caller to load the 1.123 + // missing primary from the database and call again. 1.124 + return null; 1.125 + } 1.126 + return element; 1.127 + } 1.128 + searchIndex++; 1.129 + } 1.130 + 1.131 + // No larger primary available. Let's look for smaller ones... 1.132 + searchIndex = fromIndex - 1; 1.133 + while (searchIndex >= 0) { 1.134 + FaviconCacheElement element = favicons.get(searchIndex); 1.135 + 1.136 + if (element.isPrimary) { 1.137 + if (element.invalidated) { 1.138 + return null; 1.139 + } 1.140 + return element; 1.141 + } 1.142 + searchIndex--; 1.143 + } 1.144 + 1.145 + Log.e(LOGTAG, "No primaries found in Favicon cache structure. This is madness!"); 1.146 + 1.147 + return null; 1.148 + } 1.149 + 1.150 + /** 1.151 + * Ensure the dominant colour field is populated for this favicon. 1.152 + */ 1.153 + public int ensureDominantColor() { 1.154 + if (dominantColor == -1) { 1.155 + // Find a payload, any payload, that is not invalidated. 1.156 + for (FaviconCacheElement element : favicons) { 1.157 + if (!element.invalidated) { 1.158 + dominantColor = BitmapUtils.getDominantColor(element.faviconPayload); 1.159 + return dominantColor; 1.160 + } 1.161 + } 1.162 + dominantColor = 0xFFFFFF; 1.163 + } 1.164 + 1.165 + return dominantColor; 1.166 + } 1.167 +}