mobile/android/base/widget/FaviconView.java

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:108448422386
1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 package org.mozilla.gecko.widget;
7
8 import org.mozilla.gecko.R;
9 import org.mozilla.gecko.favicons.Favicons;
10
11 import android.content.Context;
12 import android.graphics.Bitmap;
13 import android.graphics.Canvas;
14 import android.graphics.Paint;
15 import android.graphics.RectF;
16 import android.util.AttributeSet;
17 import android.widget.ImageView;
18 /**
19 * Special version of ImageView for favicons.
20 * Displays solid colour background around Favicon to fill space not occupied by the icon. Colour
21 * selected is the dominant colour of the provided Favicon.
22 */
23 public class FaviconView extends ImageView {
24 private Bitmap mIconBitmap;
25
26 // Reference to the unscaled bitmap, if any, to prevent repeated assignments of the same bitmap
27 // to the view from causing repeated rescalings (Some of the callers do this)
28 private Bitmap mUnscaledBitmap;
29
30 // Key into the Favicon dominant colour cache. Should be the Favicon URL if the image displayed
31 // here is a Favicon managed by the caching system. If not, any appropriately unique-to-this-image
32 // string is acceptable.
33 private String mIconKey;
34
35 private int mActualWidth;
36 private int mActualHeight;
37
38 // Flag indicating if the most recently assigned image is considered likely to need scaling.
39 private boolean mScalingExpected;
40
41 // Dominant color of the favicon.
42 private int mDominantColor;
43
44 // Stroke width for the border.
45 private static float sStrokeWidth;
46
47 // Paint for drawing the stroke.
48 private static Paint sStrokePaint;
49
50 // Paint for drawing the background.
51 private static Paint sBackgroundPaint;
52
53 // Size of the stroke rectangle.
54 private final RectF mStrokeRect;
55
56 // Size of the background rectangle.
57 private final RectF mBackgroundRect;
58
59 // Initializing the static paints.
60 static {
61 sStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
62 sStrokePaint.setStyle(Paint.Style.STROKE);
63
64 sBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
65 sBackgroundPaint.setStyle(Paint.Style.FILL);
66 }
67
68 public FaviconView(Context context, AttributeSet attrs) {
69 super(context, attrs);
70 setScaleType(ImageView.ScaleType.CENTER);
71
72 mStrokeRect = new RectF();
73 mBackgroundRect = new RectF();
74
75 if (sStrokeWidth == 0) {
76 sStrokeWidth = getResources().getDisplayMetrics().density;
77 sStrokePaint.setStrokeWidth(sStrokeWidth);
78 }
79
80 mStrokeRect.left = mStrokeRect.top = sStrokeWidth;
81 mBackgroundRect.left = mBackgroundRect.top = sStrokeWidth * 2.0f;
82 }
83
84 @Override
85 protected void onSizeChanged(int w, int h, int oldw, int oldh){
86 super.onSizeChanged(w, h, oldw, oldh);
87
88 // No point rechecking the image if there hasn't really been any change.
89 if (w == mActualWidth && h == mActualHeight) {
90 return;
91 }
92
93 mActualWidth = w;
94 mActualHeight = h;
95
96 mStrokeRect.right = w - sStrokeWidth;
97 mStrokeRect.bottom = h - sStrokeWidth;
98 mBackgroundRect.right = mStrokeRect.right - sStrokeWidth;
99 mBackgroundRect.bottom = mStrokeRect.bottom - sStrokeWidth;
100
101 formatImage();
102 }
103
104 @Override
105 public void onDraw(Canvas canvas) {
106 super.onDraw(canvas);
107
108 // 27.5% transparent dominant color.
109 sBackgroundPaint.setColor(mDominantColor & 0x46FFFFFF);
110 canvas.drawRect(mStrokeRect, sBackgroundPaint);
111
112 sStrokePaint.setColor(mDominantColor);
113 canvas.drawRoundRect(mStrokeRect, sStrokeWidth, sStrokeWidth, sStrokePaint);
114 }
115
116 /**
117 * Formats the image for display, if the prerequisite data are available. Upscales tiny Favicons to
118 * normal sized ones, replaces null bitmaps with the default Favicon, and fills all remaining space
119 * in this view with the coloured background.
120 */
121 private void formatImage() {
122 // If we're called before bitmap is set, or before size is set, show blank.
123 if (mIconBitmap == null || mActualWidth == 0 || mActualHeight == 0) {
124 showNoImage();
125 return;
126 }
127
128 if (mScalingExpected && mActualWidth != mIconBitmap.getWidth()) {
129 scaleBitmap();
130 // Don't scale the image every time something changes.
131 mScalingExpected = false;
132 }
133
134 setImageBitmap(mIconBitmap);
135
136 // After scaling, determine if we have empty space around the scaled image which we need to
137 // fill with the coloured background. If applicable, show it.
138 // We assume Favicons are still squares and only bother with the background if more than 3px
139 // of it would be displayed.
140 if (Math.abs(mIconBitmap.getWidth() - mActualWidth) > 3) {
141 mDominantColor = Favicons.getFaviconColor(mIconKey);
142 if (mDominantColor == -1) {
143 mDominantColor = 0;
144 }
145 } else {
146 mDominantColor = 0;
147 }
148 }
149
150 private void scaleBitmap() {
151 // If the Favicon can be resized to fill the view exactly without an enlargment of more than
152 // a factor of two, do so.
153 int doubledSize = mIconBitmap.getWidth()*2;
154 if (mActualWidth > doubledSize) {
155 // If the view is more than twice the size of the image, just double the image size
156 // and do the rest with padding.
157 mIconBitmap = Bitmap.createScaledBitmap(mIconBitmap, doubledSize, doubledSize, true);
158 } else {
159 // Otherwise, scale the image to fill the view.
160 mIconBitmap = Bitmap.createScaledBitmap(mIconBitmap, mActualWidth, mActualWidth, true);
161 }
162 }
163
164 /**
165 * Sets the icon displayed in this Favicon view to the bitmap provided. If the size of the view
166 * has been set, the display will be updated right away, otherwise the update will be deferred
167 * until then. The key provided is used to cache the result of the calculation of the dominant
168 * colour of the provided image - this value is used to draw the coloured background in this view
169 * if the icon is not large enough to fill it.
170 *
171 * @param bitmap favicon image
172 * @param key string used as a key to cache the dominant color of this image
173 * @param allowScaling If true, allows the provided bitmap to be scaled by this FaviconView.
174 * Typically, you should prefer using Favicons obtained via the caching system
175 * (Favicons class), so as to exploit caching.
176 */
177 private void updateImageInternal(Bitmap bitmap, String key, boolean allowScaling) {
178 if (bitmap == null) {
179 showDefaultFavicon();
180 return;
181 }
182
183 // Reassigning the same bitmap? Don't bother.
184 if (mUnscaledBitmap == bitmap) {
185 return;
186 }
187 mUnscaledBitmap = bitmap;
188 mIconBitmap = bitmap;
189 mIconKey = key;
190 mScalingExpected = allowScaling;
191
192 // Possibly update the display.
193 formatImage();
194 }
195
196 public void showDefaultFavicon() {
197 setImageResource(R.drawable.favicon);
198 mDominantColor = 0;
199 }
200
201 private void showNoImage() {
202 setImageDrawable(null);
203 mDominantColor = 0;
204 }
205
206 /**
207 * Clear image and background shown by this view.
208 */
209 public void clearImage() {
210 showNoImage();
211 mUnscaledBitmap = null;
212 mIconBitmap = null;
213 mIconKey = null;
214 mScalingExpected = false;
215 }
216
217 /**
218 * Update the displayed image and apply the scaling logic.
219 * The scaling logic will attempt to resize the image to fit correctly inside the view in a way
220 * that avoids unreasonable levels of loss of quality.
221 * Scaling is necessary only when the icon being provided is not drawn from the Favicon cache
222 * introduced in Bug 914296.
223 *
224 * Due to Bug 913746, icons bundled for search engines are not available to the cache, so must
225 * always have the scaling logic applied here. At the time of writing, this is the only case in
226 * which the scaling logic here is applied.
227 *
228 * @param bitmap The bitmap to display in this favicon view.
229 * @param key The key to use into the dominant colours cache when selecting a background colour.
230 */
231 public void updateAndScaleImage(Bitmap bitmap, String key) {
232 updateImageInternal(bitmap, key, true);
233 }
234
235 /**
236 * Update the image displayed in the Favicon view without scaling. Images larger than the view
237 * will be centrally cropped. Images smaller than the view will be placed centrally and the
238 * extra space filled with the dominant colour of the provided image.
239 *
240 * @param bitmap The bitmap to display in this favicon view.
241 * @param key The key to use into the dominant colours cache when selecting a background colour.
242 */
243 public void updateImage(Bitmap bitmap, String key) {
244 updateImageInternal(bitmap, key, false);
245 }
246
247 public Bitmap getBitmap() {
248 return mIconBitmap;
249 }
250 }

mercurial