Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | package org.mozilla.gecko.favicons.cache; |
michael@0 | 6 | |
michael@0 | 7 | import android.graphics.Bitmap; |
michael@0 | 8 | |
michael@0 | 9 | /** |
michael@0 | 10 | * Objects stored in the Favicon cache - allow for the bitmap to be tagged to indicate if it has |
michael@0 | 11 | * been scaled. Unscaled bitmaps are not included in the scaled-bitmap cache's size calculation. |
michael@0 | 12 | */ |
michael@0 | 13 | public class FaviconCacheElement implements Comparable<FaviconCacheElement> { |
michael@0 | 14 | // Was this Favicon computed via scaling another primary Favicon, or is this a primary Favicon? |
michael@0 | 15 | final boolean isPrimary; |
michael@0 | 16 | |
michael@0 | 17 | // The Favicon bitmap. |
michael@0 | 18 | Bitmap faviconPayload; |
michael@0 | 19 | |
michael@0 | 20 | // If set, faviconPayload is absent. Since the underlying ICO may contain multiple primary |
michael@0 | 21 | // payloads, primary payloads are never truly deleted from the cache, but instead have their |
michael@0 | 22 | // payload deleted and this flag set on their FaviconCacheElement. That way, the cache always |
michael@0 | 23 | // has a record of the existence of a primary payload, even if it is no longer in the cache. |
michael@0 | 24 | // This means that when a request comes in that will be best served using a primary that is in |
michael@0 | 25 | // the database but no longer cached, we know that it exists and can go get it (Useful when ICO |
michael@0 | 26 | // support is added). |
michael@0 | 27 | volatile boolean invalidated; |
michael@0 | 28 | |
michael@0 | 29 | final int imageSize; |
michael@0 | 30 | |
michael@0 | 31 | // Used for LRU pruning. |
michael@0 | 32 | final FaviconsForURL backpointer; |
michael@0 | 33 | |
michael@0 | 34 | public FaviconCacheElement(Bitmap payload, boolean primary, int size, FaviconsForURL backpointer) { |
michael@0 | 35 | this.faviconPayload = payload; |
michael@0 | 36 | this.isPrimary = primary; |
michael@0 | 37 | this.imageSize = size; |
michael@0 | 38 | this.backpointer = backpointer; |
michael@0 | 39 | } |
michael@0 | 40 | |
michael@0 | 41 | public FaviconCacheElement(Bitmap faviconPayload, boolean isPrimary, FaviconsForURL backpointer) { |
michael@0 | 42 | this.faviconPayload = faviconPayload; |
michael@0 | 43 | this.isPrimary = isPrimary; |
michael@0 | 44 | this.backpointer = backpointer; |
michael@0 | 45 | |
michael@0 | 46 | if (faviconPayload != null) { |
michael@0 | 47 | imageSize = faviconPayload.getWidth(); |
michael@0 | 48 | } else { |
michael@0 | 49 | imageSize = 0; |
michael@0 | 50 | } |
michael@0 | 51 | } |
michael@0 | 52 | |
michael@0 | 53 | public int sizeOf() { |
michael@0 | 54 | if (invalidated) { |
michael@0 | 55 | return 0; |
michael@0 | 56 | } |
michael@0 | 57 | return faviconPayload.getRowBytes() * faviconPayload.getHeight(); |
michael@0 | 58 | } |
michael@0 | 59 | |
michael@0 | 60 | /** |
michael@0 | 61 | * Establish an ordering on FaviconCacheElements based on size and validity. An element is |
michael@0 | 62 | * considered "greater than" another if it is valid and the other is not, or if it contains a |
michael@0 | 63 | * larger payload. |
michael@0 | 64 | * |
michael@0 | 65 | * @param another The FaviconCacheElement to compare to this one. |
michael@0 | 66 | * @return -1 if this element is less than the given one, 1 if the other one is larger than this |
michael@0 | 67 | * and 0 if both are of equal value. |
michael@0 | 68 | */ |
michael@0 | 69 | @Override |
michael@0 | 70 | public int compareTo(FaviconCacheElement another) { |
michael@0 | 71 | if (invalidated && !another.invalidated) { |
michael@0 | 72 | return -1; |
michael@0 | 73 | } |
michael@0 | 74 | |
michael@0 | 75 | if (!invalidated && another.invalidated) { |
michael@0 | 76 | return 1; |
michael@0 | 77 | } |
michael@0 | 78 | |
michael@0 | 79 | if (invalidated) { |
michael@0 | 80 | return 0; |
michael@0 | 81 | } |
michael@0 | 82 | |
michael@0 | 83 | final int w1 = imageSize; |
michael@0 | 84 | final int w2 = another.imageSize; |
michael@0 | 85 | if (w1 > w2) { |
michael@0 | 86 | return 1; |
michael@0 | 87 | } else if (w2 > w1) { |
michael@0 | 88 | return -1; |
michael@0 | 89 | } |
michael@0 | 90 | return 0; |
michael@0 | 91 | } |
michael@0 | 92 | |
michael@0 | 93 | /** |
michael@0 | 94 | * Called when this element is evicted from the cache. |
michael@0 | 95 | * |
michael@0 | 96 | * If primary, drop the payload and set invalid. If secondary, just unlink from parent node. |
michael@0 | 97 | */ |
michael@0 | 98 | public void onEvictedFromCache() { |
michael@0 | 99 | if (isPrimary) { |
michael@0 | 100 | // So we keep a record of which primaries exist in the database for this URL, we |
michael@0 | 101 | // don't actually delete the entry for primaries. Instead, we delete their payload |
michael@0 | 102 | // and flag them as invalid. This way, we can later figure out that what a request |
michael@0 | 103 | // really want is one of the primaries that have been dropped from the cache, and we |
michael@0 | 104 | // can go get it. |
michael@0 | 105 | invalidated = true; |
michael@0 | 106 | faviconPayload = null; |
michael@0 | 107 | } else { |
michael@0 | 108 | // Secondaries don't matter - just delete them. |
michael@0 | 109 | if (backpointer == null) { |
michael@0 | 110 | return; |
michael@0 | 111 | } |
michael@0 | 112 | backpointer.favicons.remove(this); |
michael@0 | 113 | } |
michael@0 | 114 | } |
michael@0 | 115 | } |