Bug 1406338 - Part 1: Support applying specific text size while creating a favicon. r?nechen draft
authorJing-wei Wu <topwu.tw@gmail.com>
Mon, 09 Oct 2017 10:36:56 +0800
changeset 676597 5b6ca7b000ecc0921f00597e50f3a6e740c8e3fc
parent 676596 791123af8cdbbde69dcd8043ca12dc60e642f4de
child 676598 10352df8f7180858682e8525dafd6138d447bcef
push id83540
push userbmo:topwu.tw@gmail.com
push dateMon, 09 Oct 2017 03:04:13 +0000
reviewersnechen
bugs1406338
milestone58.0a1
Bug 1406338 - Part 1: Support applying specific text size while creating a favicon. r?nechen MozReview-Commit-ID: Dcx1RgcRdka
mobile/android/base/java/org/mozilla/gecko/icons/IconRequest.java
mobile/android/base/java/org/mozilla/gecko/icons/IconRequestBuilder.java
mobile/android/base/java/org/mozilla/gecko/icons/loader/IconGenerator.java
--- a/mobile/android/base/java/org/mozilla/gecko/icons/IconRequest.java
+++ b/mobile/android/base/java/org/mozilla/gecko/icons/IconRequest.java
@@ -26,30 +26,34 @@ public class IconRequest {
     /* package-private */ TreeSet<IconDescriptor> icons;
     /* package-private */ boolean skipNetwork;
     /* package-private */ boolean backgroundThread;
     /* package-private */ boolean skipDisk;
     /* package-private */ boolean skipMemory;
     /* package-private */ int targetSize;
     /* package-private */ int minimumSizePxAfterScaling;
     /* package-private */ boolean prepareOnly;
+    /* package-private */ float textSize;
     private IconCallback callback;
 
     /* package-private */ IconRequest(Context context) {
         this.context = context.getApplicationContext();
         this.icons = new TreeSet<>(new IconDescriptorComparator());
 
         // Setting some sensible defaults.
         this.privileged = false;
         this.skipMemory = false;
         this.skipDisk = false;
         this.skipNetwork = false;
         this.targetSize = context.getResources().getDimensionPixelSize(R.dimen.favicon_bg);
         this.minimumSizePxAfterScaling = 0;
         this.prepareOnly = false;
+
+        // textSize is only used in IconGenerator.java for creating a icon with specific text size.
+        this.textSize = 0;
     }
 
     /**
      * Execute this request and try to load an icon. Once an icon has been loaded successfully the
      * callback will be executed.
      *
      * The returned Future can be used to cancel the job.
      */
@@ -141,16 +145,24 @@ public class IconRequest {
     /**
      * Get an iterator to iterate over all icon descriptors associated with this request.
      */
     public Iterator<IconDescriptor> getIconIterator() {
         return icons.iterator();
     }
 
     /**
+     * Get the required text size of the icon created by
+     * {@link org.mozilla.gecko.icons.loader.IconGenerator}.
+     */
+    public float getTextSize() {
+        return textSize;
+    }
+
+    /**
      * Create a builder to modify this request.
      *
      * Calling methods on the builder will modify this object and not create a copy.
      */
     public IconRequestBuilder modify() {
         return new IconRequestBuilder(this);
     }
 
--- a/mobile/android/base/java/org/mozilla/gecko/icons/IconRequestBuilder.java
+++ b/mobile/android/base/java/org/mozilla/gecko/icons/IconRequestBuilder.java
@@ -102,16 +102,24 @@ public class IconRequestBuilder {
      * preferred Android launcher icon size.
      */
     public IconRequestBuilder forLauncherIcon() {
         internal.targetSize = GeckoAppShell.getPreferredIconSize();
         return this;
     }
 
     /**
+     * The icon will be scaled to the given size.
+     */
+    public IconRequestBuilder targetSize(final int targetSize) {
+        internal.targetSize = targetSize;
+        return this;
+    }
+
+    /**
      * The icon will be used in Activity Stream: a minimum size for the icon will be set.
      */
     public IconRequestBuilder forActivityStream() {
         // This value was set anecdotally: 16px icons scaled up both look blurry and
         // don't fill the space well. 32px icons look good enough.
         internal.minimumSizePxAfterScaling = 32 * ResizingProcessor.MAX_SCALE_FACTOR;
         return this;
     }
@@ -132,16 +140,25 @@ public class IconRequestBuilder {
      * perform a lookup of the URL but doesn't want to load the icon yet.
      */
     public IconRequestBuilder prepareOnly() {
         internal.prepareOnly = true;
         return this;
     }
 
     /**
+     * The text size will be resized to the given size, and this field is only used by
+     * {@link org.mozilla.gecko.icons.loader.IconGenerator} for creating a new icon.
+     */
+    public IconRequestBuilder textSize(final float textSize) {
+        internal.textSize = textSize;
+        return this;
+    }
+
+    /**
      * Return the request built with this builder.
      */
     @CheckResult
     public IconRequest build() {
         if (TextUtils.isEmpty(internal.pageUrl)) {
             throw new IllegalStateException("Page URL is required");
         }
 
@@ -151,16 +168,17 @@ public class IconRequestBuilder {
         request.icons = new TreeSet<>(internal.icons);
         request.skipNetwork = internal.skipNetwork;
         request.backgroundThread = internal.backgroundThread;
         request.skipDisk = internal.skipDisk;
         request.skipMemory = internal.skipMemory;
         request.targetSize = internal.targetSize;
         request.minimumSizePxAfterScaling = internal.minimumSizePxAfterScaling;
         request.prepareOnly = internal.prepareOnly;
+        request.textSize = internal.textSize;
         return request;
     }
 
     /**
      * This is a no-op method.
      *
      * All builder methods are annotated with @CheckResult to denote that the
      * methods return the builder object and that it is typically an error to not call another method
--- a/mobile/android/base/java/org/mozilla/gecko/icons/loader/IconGenerator.java
+++ b/mobile/android/base/java/org/mozilla/gecko/icons/loader/IconGenerator.java
@@ -44,44 +44,55 @@ public class IconGenerator implements Ic
     @Override
     public IconResponse load(IconRequest request) {
         if (request.getIconCount() > 1) {
             // There are still other icons to try. We will only generate an icon if there's only one
             // icon left and all previous loaders have failed (assuming this is the last one).
             return null;
         }
 
-        return generate(request.getContext(), request.getPageUrl());
+        return generate(request.getContext(), request.getPageUrl(), request.getTargetSize(), request.getTextSize());
+    }
+
+    public static IconResponse generate(Context context, String pageURL) {
+        return generate(context, pageURL, 0, 0);
     }
 
     /**
      * Generate default favicon for the given page URL.
      */
-    public static IconResponse generate(Context context, String pageURL) {
+    public static IconResponse generate(final Context context, final String pageURL,
+                                        int widthAndHeight, float textSize) {
         final Resources resources = context.getResources();
-        final int widthAndHeight = resources.getDimensionPixelSize(R.dimen.favicon_bg);
+        if (widthAndHeight == 0) {
+            widthAndHeight = resources.getDimensionPixelSize(R.dimen.favicon_bg);
+        }
         final int roundedCorners = resources.getDimensionPixelOffset(R.dimen.favicon_corner_radius);
 
         final Bitmap favicon = Bitmap.createBitmap(widthAndHeight, widthAndHeight, Bitmap.Config.ARGB_8888);
         final Canvas canvas = new Canvas(favicon);
 
         final int color = pickColor(pageURL);
 
         final Paint paint = new Paint();
         paint.setColor(color);
 
         canvas.drawRoundRect(new RectF(0, 0, widthAndHeight, widthAndHeight), roundedCorners, roundedCorners, paint);
 
         paint.setColor(Color.WHITE);
 
         final String character = getRepresentativeCharacter(pageURL);
 
-        // The text size is calculated dynamically based on the target icon size (1/8th). For an icon
-        // size of 112dp we'd use a text size of 14dp (112 / 8).
-        final float textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, widthAndHeight / 8, context.getResources().getDisplayMetrics());
+        if (textSize == 0) {
+            // The text size is calculated dynamically based on the target icon size (1/8th). For an icon
+            // size of 112dp we'd use a text size of 14dp (112 / 8).
+            textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                                                 widthAndHeight / 8,
+                                                 resources.getDisplayMetrics());
+        }
 
         paint.setTextAlign(Paint.Align.CENTER);
         paint.setTextSize(textSize);
         paint.setAntiAlias(true);
 
         canvas.drawText(character,
                 canvas.getWidth() / 2,
                 (int) ((canvas.getHeight() / 2) - ((paint.descent() + paint.ascent()) / 2)),