mobile/android/base/widget/FaviconView.java

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     6 package org.mozilla.gecko.widget;
     8 import org.mozilla.gecko.R;
     9 import org.mozilla.gecko.favicons.Favicons;
    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;
    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;
    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;
    35     private int mActualWidth;
    36     private int mActualHeight;
    38     // Flag indicating if the most recently assigned image is considered likely to need scaling.
    39     private boolean mScalingExpected;
    41     // Dominant color of the favicon.
    42     private int mDominantColor;
    44     // Stroke width for the border.
    45     private static float sStrokeWidth;
    47     // Paint for drawing the stroke.
    48     private static Paint sStrokePaint;
    50     // Paint for drawing the background.
    51     private static Paint sBackgroundPaint;
    53     // Size of the stroke rectangle.
    54     private final RectF mStrokeRect;
    56     // Size of the background rectangle.
    57     private final RectF mBackgroundRect;
    59     // Initializing the static paints.
    60     static {
    61         sStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    62         sStrokePaint.setStyle(Paint.Style.STROKE);
    64         sBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    65         sBackgroundPaint.setStyle(Paint.Style.FILL);
    66     }
    68     public FaviconView(Context context, AttributeSet attrs) {
    69         super(context, attrs);
    70         setScaleType(ImageView.ScaleType.CENTER);
    72         mStrokeRect = new RectF();
    73         mBackgroundRect = new RectF();
    75         if (sStrokeWidth == 0) {
    76             sStrokeWidth = getResources().getDisplayMetrics().density;
    77             sStrokePaint.setStrokeWidth(sStrokeWidth);
    78         }
    80         mStrokeRect.left = mStrokeRect.top = sStrokeWidth;
    81         mBackgroundRect.left = mBackgroundRect.top = sStrokeWidth * 2.0f;
    82     }
    84     @Override
    85     protected void onSizeChanged(int w, int h, int oldw, int oldh){
    86         super.onSizeChanged(w, h, oldw, oldh);
    88         // No point rechecking the image if there hasn't really been any change.
    89         if (w == mActualWidth && h == mActualHeight) {
    90             return;
    91         }
    93         mActualWidth = w;
    94         mActualHeight = h;
    96         mStrokeRect.right = w - sStrokeWidth;
    97         mStrokeRect.bottom = h - sStrokeWidth;
    98         mBackgroundRect.right = mStrokeRect.right - sStrokeWidth;
    99         mBackgroundRect.bottom = mStrokeRect.bottom - sStrokeWidth;
   101         formatImage();
   102     }
   104     @Override
   105     public void onDraw(Canvas canvas) {
   106         super.onDraw(canvas);
   108         // 27.5% transparent dominant color.
   109         sBackgroundPaint.setColor(mDominantColor & 0x46FFFFFF);
   110         canvas.drawRect(mStrokeRect, sBackgroundPaint);
   112         sStrokePaint.setColor(mDominantColor);
   113         canvas.drawRoundRect(mStrokeRect, sStrokeWidth, sStrokeWidth, sStrokePaint);
   114     }
   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         }
   128         if (mScalingExpected && mActualWidth != mIconBitmap.getWidth()) {
   129             scaleBitmap();
   130             // Don't scale the image every time something changes.
   131             mScalingExpected = false;
   132         }
   134         setImageBitmap(mIconBitmap);
   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     }
   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     }
   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         }
   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;
   192         // Possibly update the display.
   193         formatImage();
   194     }
   196     public void showDefaultFavicon() {
   197         setImageResource(R.drawable.favicon);
   198         mDominantColor = 0;
   199     }
   201     private void showNoImage() {
   202         setImageDrawable(null);
   203         mDominantColor = 0;
   204     }
   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     }
   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     }
   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     }
   247     public Bitmap getBitmap() {
   248         return mIconBitmap;
   249     }
   250 }

mercurial