summaryrefslogtreecommitdiffstats
path: root/mobile/android/base/java/org/mozilla/gecko/icons/processing
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /mobile/android/base/java/org/mozilla/gecko/icons/processing
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'mobile/android/base/java/org/mozilla/gecko/icons/processing')
-rw-r--r--mobile/android/base/java/org/mozilla/gecko/icons/processing/ColorProcessor.java61
-rw-r--r--mobile/android/base/java/org/mozilla/gecko/icons/processing/DiskProcessor.java36
-rw-r--r--mobile/android/base/java/org/mozilla/gecko/icons/processing/MemoryProcessor.java38
-rw-r--r--mobile/android/base/java/org/mozilla/gecko/icons/processing/Processor.java21
-rw-r--r--mobile/android/base/java/org/mozilla/gecko/icons/processing/ResizingProcessor.java68
5 files changed, 224 insertions, 0 deletions
diff --git a/mobile/android/base/java/org/mozilla/gecko/icons/processing/ColorProcessor.java b/mobile/android/base/java/org/mozilla/gecko/icons/processing/ColorProcessor.java
new file mode 100644
index 000000000..3f7110034
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/icons/processing/ColorProcessor.java
@@ -0,0 +1,61 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; 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.icons.processing;
+
+import android.support.v7.graphics.Palette;
+import android.util.Log;
+
+import org.mozilla.gecko.gfx.BitmapUtils;
+import org.mozilla.gecko.icons.IconRequest;
+import org.mozilla.gecko.icons.IconResponse;
+import org.mozilla.gecko.util.HardwareUtils;
+
+/**
+ * Processor implementation to extract the dominant color from the icon and attach it to the icon
+ * response object.
+ */
+public class ColorProcessor implements Processor {
+ private static final String LOGTAG = "GeckoColorProcessor";
+ private static final int DEFAULT_COLOR = 0; // 0 == No color
+
+ @Override
+ public void process(IconRequest request, IconResponse response) {
+ if (response.hasColor()) {
+ return;
+ }
+
+ if (HardwareUtils.isX86System()) {
+ // (Bug 1318667) We are running into crashes when using the palette library with
+ // specific icons on x86 devices. They take down the whole VM and are not recoverable.
+ // Unfortunately our release icon is triggering this crash. Until we can switch to a
+ // newer version of the support library where this does not happen, we are using our
+ // own slower implementation.
+ extractColorUsingCustomImplementation(response);
+ } else {
+ extractColorUsingPaletteSupportLibrary(response);
+ }
+ }
+
+ private void extractColorUsingPaletteSupportLibrary(final IconResponse response) {
+ try {
+ final Palette palette = Palette.from(response.getBitmap()).generate();
+ response.updateColor(palette.getVibrantColor(DEFAULT_COLOR));
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // We saw the palette library fail with an ArrayIndexOutOfBoundsException intermittently
+ // in automation. In this case lets just swallow the exception and move on without a
+ // color. This is a valid condition and callers should handle this gracefully (Bug 1318560).
+ Log.e(LOGTAG, "Palette generation failed with ArrayIndexOutOfBoundsException", e);
+
+ response.updateColor(DEFAULT_COLOR);
+ }
+ }
+
+ private void extractColorUsingCustomImplementation(final IconResponse response) {
+ final int dominantColor = BitmapUtils.getDominantColor(response.getBitmap());
+
+ response.updateColor(dominantColor);
+ }
+}
diff --git a/mobile/android/base/java/org/mozilla/gecko/icons/processing/DiskProcessor.java b/mobile/android/base/java/org/mozilla/gecko/icons/processing/DiskProcessor.java
new file mode 100644
index 000000000..150aa503b
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/icons/processing/DiskProcessor.java
@@ -0,0 +1,36 @@
+package org.mozilla.gecko.icons.processing;
+
+import org.mozilla.gecko.icons.IconRequest;
+import org.mozilla.gecko.icons.IconResponse;
+import org.mozilla.gecko.icons.storage.DiskStorage;
+import org.mozilla.gecko.util.StringUtils;
+
+public class DiskProcessor implements Processor {
+ @Override
+ public void process(IconRequest request, IconResponse response) {
+ if (request.shouldSkipDisk()) {
+ return;
+ }
+
+ if (!response.hasUrl() || !StringUtils.isHttpOrHttps(response.getUrl())) {
+ // If the response does not contain an URL from which the icon was loaded or if this is
+ // not a http(s) URL then we cannot store this or do not need to (because it's already
+ // stored somewhere else, like for URLs pointing inside the omni.ja).
+ return;
+ }
+
+ final DiskStorage storage = DiskStorage.get(request.getContext());
+
+ if (response.isFromNetwork()) {
+ // The icon has been loaded from the network. Store it on the disk now.
+ storage.putIcon(response);
+ }
+
+ if (response.isFromMemory() || response.isFromDisk() || response.isFromNetwork()) {
+ // Remember mapping between page URL and storage URL. Even when this icon has been loaded
+ // from memory or disk this does not mean that we stored this mapping already: We could
+ // have loaded this icon for a different page URL previously.
+ storage.putMapping(request, response.getUrl());
+ }
+ }
+}
diff --git a/mobile/android/base/java/org/mozilla/gecko/icons/processing/MemoryProcessor.java b/mobile/android/base/java/org/mozilla/gecko/icons/processing/MemoryProcessor.java
new file mode 100644
index 000000000..245faded5
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/icons/processing/MemoryProcessor.java
@@ -0,0 +1,38 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; 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.icons.processing;
+
+import org.mozilla.gecko.icons.IconRequest;
+import org.mozilla.gecko.icons.IconResponse;
+import org.mozilla.gecko.icons.storage.MemoryStorage;
+
+public class MemoryProcessor implements Processor {
+ private final MemoryStorage storage;
+
+ public MemoryProcessor() {
+ storage = MemoryStorage.get();
+ }
+
+ @Override
+ public void process(IconRequest request, IconResponse response) {
+ if (request.shouldSkipMemory() || request.getIconCount() == 0 || response.isGenerated()) {
+ // Do not cache this icon in memory if we should skip the memory cache or if this icon
+ // has been generated. We can re-generate it if needed.
+ return;
+ }
+
+ final String iconUrl = request.getBestIcon().getUrl();
+
+ if (iconUrl.startsWith("data:image/")) {
+ // The image data is encoded in the URL. It doesn't make sense to store the URL and the
+ // bitmap in cache.
+ return;
+ }
+
+ storage.putMapping(request, iconUrl);
+ storage.putIcon(iconUrl, response);
+ }
+}
diff --git a/mobile/android/base/java/org/mozilla/gecko/icons/processing/Processor.java b/mobile/android/base/java/org/mozilla/gecko/icons/processing/Processor.java
new file mode 100644
index 000000000..df7d63c6c
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/icons/processing/Processor.java
@@ -0,0 +1,21 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; 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.icons.processing;
+
+import org.mozilla.gecko.icons.IconRequest;
+import org.mozilla.gecko.icons.IconResponse;
+
+/**
+ * Generic interface for a class that processes a response object after an icon has been loaded and
+ * decoded. A class implementing this interface can attach additional data to the response or modify
+ * the bitmap (e.g. resizing).
+ */
+public interface Processor {
+ /**
+ * Process a response object containing an icon loaded for this request.
+ */
+ void process(IconRequest request, IconResponse response);
+}
diff --git a/mobile/android/base/java/org/mozilla/gecko/icons/processing/ResizingProcessor.java b/mobile/android/base/java/org/mozilla/gecko/icons/processing/ResizingProcessor.java
new file mode 100644
index 000000000..63b479021
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/icons/processing/ResizingProcessor.java
@@ -0,0 +1,68 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; 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.icons.processing;
+
+import android.graphics.Bitmap;
+import android.support.annotation.VisibleForTesting;
+
+import org.mozilla.gecko.icons.IconRequest;
+import org.mozilla.gecko.icons.IconResponse;
+
+/**
+ * Processor implementation for resizing the loaded icon based on the target size.
+ */
+public class ResizingProcessor implements Processor {
+ @Override
+ public void process(IconRequest request, IconResponse response) {
+ if (response.isFromMemory()) {
+ // This bitmap has been loaded from memory, so it has already gone through the resizing
+ // process. We do not want to resize the image every time we hit the memory cache.
+ return;
+ }
+
+ final Bitmap originalBitmap = response.getBitmap();
+ final int size = originalBitmap.getWidth();
+
+ final int targetSize = request.getTargetSize();
+
+ if (size == targetSize) {
+ // The bitmap has exactly the size we are looking for.
+ return;
+ }
+
+ final Bitmap resizedBitmap;
+
+ if (size > targetSize) {
+ resizedBitmap = resize(originalBitmap, targetSize);
+ } else {
+ // Our largest primary is smaller than the desired size. Upscale by a maximum of 2x.
+ // 'largestSize' now reflects the maximum size we can upscale to.
+ final int largestSize = size * 2;
+
+ if (largestSize > targetSize) {
+ // Perfect! We can upscale by less than 2x and reach the needed size. Do it.
+ resizedBitmap = resize(originalBitmap, targetSize);
+ } else {
+ // We don't have enough information to make the target size look non terrible. Best effort:
+ resizedBitmap = resize(originalBitmap, largestSize);
+ }
+ }
+
+ response.updateBitmap(resizedBitmap);
+
+ originalBitmap.recycle();
+ }
+
+ @VisibleForTesting Bitmap resize(Bitmap bitmap, int targetSize) {
+ try {
+ return Bitmap.createScaledBitmap(bitmap, targetSize, targetSize, true);
+ } catch (OutOfMemoryError error) {
+ // There's not enough memory to create a resized copy of the bitmap in memory. Let's just
+ // use what we have.
+ return bitmap;
+ }
+ }
+}