Bug 933459 - Reduce drawables created for FaviconsView. r=mfinkle, a=bajaj
authorSriram Ramasubramanian <sriram@mozilla.com>
Fri, 01 Nov 2013 13:18:29 -0700
changeset 167639 e072083c4a0d7be1a31b9ce38c0d61bd3a004b23
parent 167638 de98352c72c6fa282337c904c02313180b82b001
child 167640 37df29dd2f8f1e6ab099f3fffb9b3d59fb4b6adb
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle, bajaj
bugs933459
milestone27.0a2
Bug 933459 - Reduce drawables created for FaviconsView. r=mfinkle, a=bajaj
mobile/android/base/moz.build
mobile/android/base/resources/drawable/favicon_bg.xml
mobile/android/base/widget/FaviconView.java
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -772,17 +772,16 @@ ANDROID_RESFILES += [
     'resources/drawable-xlarge-v11/home_history_tabs_indicator.xml',
     'resources/drawable-xlarge-xhdpi-v11/ic_menu_bookmark_add.png',
     'resources/drawable-xlarge-xhdpi-v11/ic_menu_bookmark_remove.png',
     'resources/drawable/action_bar_button.xml',
     'resources/drawable/action_bar_button_inverse.xml',
     'resources/drawable/bookmark_folder.xml',
     'resources/drawable/divider_horizontal.xml',
     'resources/drawable/divider_vertical.xml',
-    'resources/drawable/favicon_bg.xml',
     'resources/drawable/handle_end_level.xml',
     'resources/drawable/handle_start_level.xml',
     'resources/drawable/home_banner.xml',
     'resources/drawable/home_history_tabs_indicator.xml',
     'resources/drawable/home_page_title_background.xml',
     'resources/drawable/ic_menu_back.xml',
     'resources/drawable/ic_menu_desktop_mode_off.xml',
     'resources/drawable/ic_menu_desktop_mode_on.xml',
deleted file mode 100644
--- a/mobile/android/base/resources/drawable/favicon_bg.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-       android:shape="rectangle">
-     <corners android:radius="@dimen/favicon_bg_radius"/>
-     <size android:height="@dimen/favicon_bg"/>
-     <solid android:color="#FFFFFF"/>
-     <stroke android:width="1dp" android:color="#DDDDDD"/>
-</shape>
--- a/mobile/android/base/widget/FaviconView.java
+++ b/mobile/android/base/widget/FaviconView.java
@@ -1,23 +1,23 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.widget;
 
+import org.mozilla.gecko.R;
 import org.mozilla.gecko.favicons.Favicons;
-import org.mozilla.gecko.R;
 
 import android.content.Context;
 import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.drawable.Drawable;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.RectF;
 import android.util.AttributeSet;
 import android.widget.ImageView;
 /**
  * Special version of ImageView for favicons.
  * Displays solid colour background around Favicon to fill space not occupied by the icon. Colour
  * selected is the dominant colour of the provided Favicon.
  */
 public class FaviconView extends ImageView {
@@ -33,34 +33,91 @@ public class FaviconView extends ImageVi
     private String mIconKey;
 
     private int mActualWidth;
     private int mActualHeight;
 
     // Flag indicating if the most recently assigned image is considered likely to need scaling.
     private boolean mScalingExpected;
 
+    // Dominant color of the favicon.
+    private int mDominantColor;
+
+    // Stroke width for the border.
+    private static float sStrokeWidth;
+
+    // Paint for drawing the stroke.
+    private static Paint sStrokePaint;
+
+    // Paint for drawing the background.
+    private static Paint sBackgroundPaint;
+
+    // Size of the stroke rectangle.
+    private final RectF mStrokeRect;
+
+    // Size of the background rectangle.
+    private final RectF mBackgroundRect;
+
+    // Initializing the static paints.
+    static {
+        sStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        sStrokePaint.setStyle(Paint.Style.STROKE);
+
+        sBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        sBackgroundPaint.setStyle(Paint.Style.FILL);
+    }
+
     public FaviconView(Context context, AttributeSet attrs) {
         super(context, attrs);
         setScaleType(ImageView.ScaleType.CENTER);
+
+        mStrokeRect = new RectF();
+        mBackgroundRect = new RectF();
+
+        if (sStrokeWidth == 0) {
+            sStrokeWidth = getResources().getDisplayMetrics().density;
+            sStrokePaint.setStrokeWidth(sStrokeWidth);
+        }
+
+        mStrokeRect.left = mStrokeRect.top = sStrokeWidth;
+        mBackgroundRect.left = mBackgroundRect.top = sStrokeWidth * 2.0f;
     }
 
     @Override
-    protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld){
-        super.onSizeChanged(xNew, yNew, xOld, yOld);
+    protected void onSizeChanged(int w, int h, int oldw, int oldh){
+        super.onSizeChanged(w, h, oldw, oldh);
 
         // No point rechecking the image if there hasn't really been any change.
-        if (xNew == mActualHeight && yNew == mActualWidth) {
+        if (w == mActualWidth && h == mActualHeight) {
             return;
         }
-        mActualWidth = xNew;
-        mActualHeight = yNew;
+
+        mActualWidth = w;
+        mActualHeight = h;
+
+        mStrokeRect.right = w - sStrokeWidth;
+        mStrokeRect.bottom = h - sStrokeWidth;
+        mBackgroundRect.right = mStrokeRect.right - sStrokeWidth;
+        mBackgroundRect.bottom = mStrokeRect.bottom - sStrokeWidth;
+
         formatImage();
     }
 
+    @Override
+    public void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+
+        // 27.5% transparent dominant color.
+        sBackgroundPaint.setColor(mDominantColor & 0x46FFFFFF);
+        canvas.drawRect(mStrokeRect, sBackgroundPaint);
+
+        sStrokePaint.setColor(mDominantColor);
+        canvas.drawRoundRect(mStrokeRect, sStrokeWidth, sStrokeWidth, sStrokePaint);
+    }
+
     /**
      * Formats the image for display, if the prerequisite data are available. Upscales tiny Favicons to
      * normal sized ones, replaces null bitmaps with the default Favicon, and fills all remaining space
      * in this view with the coloured background.
      */
     private void formatImage() {
         // If we're called before bitmap is set, or before size is set, show blank.
         if (mIconBitmap == null || mActualWidth == 0 || mActualHeight == 0) {
@@ -76,19 +133,22 @@ public class FaviconView extends ImageVi
 
         setImageBitmap(mIconBitmap);
 
         // After scaling, determine if we have empty space around the scaled image which we need to
         // fill with the coloured background. If applicable, show it.
         // We assume Favicons are still squares and only bother with the background if more than 3px
         // of it would be displayed.
         if (Math.abs(mIconBitmap.getWidth() - mActualWidth) > 3) {
-            showBackground();
+            mDominantColor = Favicons.getFaviconColor(mIconKey);
+            if (mDominantColor == -1) {
+                mDominantColor = 0;
+            }
         } else {
-            hideBackground();
+            mDominantColor = 0;
         }
     }
 
     private void scaleBitmap() {
         // If the Favicon can be resized to fill the view exactly without an enlargment of more than
         // a factor of two, do so.
         int doubledSize = mIconBitmap.getWidth()*2;
         if (mActualWidth > doubledSize) {
@@ -97,39 +157,16 @@ public class FaviconView extends ImageVi
             mIconBitmap = Bitmap.createScaledBitmap(mIconBitmap, doubledSize, doubledSize, true);
         } else {
             // Otherwise, scale the image to fill the view.
             mIconBitmap = Bitmap.createScaledBitmap(mIconBitmap, mActualWidth, mActualWidth, true);
         }
     }
 
     /**
-     * Helper method to display background of the dominant colour of the favicon to pad the remaining
-     * space.
-     */
-    private void showBackground() {
-        int color = Favicons.getFaviconColor(mIconKey);
-        if (color == -1) {
-            hideBackground();
-            return;
-        }
-        color = Color.argb(70, Color.red(color), Color.green(color), Color.blue(color));
-        final Drawable drawable = getResources().getDrawable(R.drawable.favicon_bg);
-        drawable.setColorFilter(color, Mode.SRC_ATOP);
-        setBackgroundDrawable(drawable);
-    }
-
-    /**
-     * Method to hide the background. The view will now have a transparent background.
-     */
-    private void hideBackground() {
-        setBackgroundResource(0);
-    }
-
-    /**
      * Sets the icon displayed in this Favicon view to the bitmap provided. If the size of the view
      * has been set, the display will be updated right away, otherwise the update will be deferred
      * until then. The key provided is used to cache the result of the calculation of the dominant
      * colour of the provided image - this value is used to draw the coloured background in this view
      * if the icon is not large enough to fill it.
      *
      * @param bitmap favicon image
      * @param key string used as a key to cache the dominant color of this image
@@ -153,22 +190,22 @@ public class FaviconView extends ImageVi
         mScalingExpected = allowScaling;
 
         // Possibly update the display.
         formatImage();
     }
 
     public void showDefaultFavicon() {
         setImageResource(R.drawable.favicon);
-        hideBackground();
+        mDominantColor = 0;
     }
 
     private void showNoImage() {
         setImageBitmap(null);
-        hideBackground();
+        mDominantColor = 0;
     }
 
     /**
      * Clear image and background shown by this view.
      */
     public void clearImage() {
         showNoImage();
         mUnscaledBitmap = null;