| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "modules/notifications/NotificationResourcesLoader.h" | 5 #include "modules/notifications/NotificationResourcesLoader.h" |
| 6 | 6 |
| 7 #include "platform/Histogram.h" | 7 #include "platform/Histogram.h" |
| 8 #include "platform/weborigin/KURL.h" | 8 #include "platform/weborigin/KURL.h" |
| 9 #include "public/platform/modules/notifications/WebNotificationConstants.h" | 9 #include "public/platform/modules/notifications/WebNotificationConstants.h" |
| 10 #include "public/platform/modules/notifications/WebNotificationData.h" | 10 #include "public/platform/modules/notifications/WebNotificationData.h" |
| 11 #include "public/platform/modules/notifications/WebNotificationResources.h" | 11 #include "public/platform/modules/notifications/WebNotificationResources.h" |
| 12 #include "skia/ext/image_operations.h" | 12 #include "skia/ext/image_operations.h" |
| 13 #include "third_party/skia/include/core/SkBitmap.h" | 13 #include "third_party/skia/include/core/SkBitmap.h" |
| 14 #include "wtf/CurrentTime.h" | 14 #include "wtf/CurrentTime.h" |
| 15 #include "wtf/Threading.h" | 15 #include "wtf/Threading.h" |
| 16 #include <cmath> |
| 16 | 17 |
| 17 namespace blink { | 18 namespace blink { |
| 18 | 19 |
| 19 namespace { | 20 namespace { |
| 20 | 21 |
| 21 // Scales down |image| to fit within |maxSizePx| if its width or height is | 22 // Scales down |image| to fit within |maxWidthPx|x|maxHeightPx| if it is larger |
| 22 // larger than |maxSizePx| and returns the result. Otherwise does nothing and | 23 // and returns the result. Otherwise does nothing and returns |image| unchanged. |
| 23 // returns |image| unchanged. | |
| 24 // TODO(mvanouwerkerk): Explore doing the scaling on a background thread. | 24 // TODO(mvanouwerkerk): Explore doing the scaling on a background thread. |
| 25 SkBitmap scaleDownIfNeeded(const SkBitmap& image, int maxSizePx) | 25 SkBitmap scaleDownIfNeeded(const SkBitmap& image, int maxWidthPx, int maxHeightP
x) |
| 26 { | 26 { |
| 27 if (image.width() > maxSizePx || image.height() > maxSizePx) { | 27 if (image.width() > maxWidthPx || image.height() > maxHeightPx) { |
| 28 double scale = std::min( |
| 29 static_cast<double>(maxWidthPx) / image.width(), |
| 30 static_cast<double>(maxHeightPx) / image.height()); |
| 28 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, scaleTimeHistogram
, new CustomCountHistogram("Notifications.Icon.ScaleDownTime", 1, 1000 * 10 /* 1
0 seconds max */, 50 /* buckets */)); | 31 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, scaleTimeHistogram
, new CustomCountHistogram("Notifications.Icon.ScaleDownTime", 1, 1000 * 10 /* 1
0 seconds max */, 50 /* buckets */)); |
| 29 double startTime = monotonicallyIncreasingTimeMS(); | 32 double startTime = monotonicallyIncreasingTimeMS(); |
| 30 SkBitmap scaledImage = skia::ImageOperations::Resize(image, skia::ImageO
perations::RESIZE_BEST, std::min(image.width(), maxSizePx), std::min(image.heigh
t(), maxSizePx)); | 33 // TODO(peter): Try using RESIZE_BETTER for large images. |
| 34 SkBitmap scaledImage = skia::ImageOperations::Resize(image, skia::ImageO
perations::RESIZE_BEST, std::lround(scale * image.width()), std::lround(scale *
image.height())); |
| 31 scaleTimeHistogram.count(monotonicallyIncreasingTimeMS() - startTime); | 35 scaleTimeHistogram.count(monotonicallyIncreasingTimeMS() - startTime); |
| 32 return scaledImage; | 36 return scaledImage; |
| 33 } | 37 } |
| 34 return image; | 38 return image; |
| 35 } | 39 } |
| 36 | 40 |
| 37 } // namespace | 41 } // namespace |
| 38 | 42 |
| 39 NotificationResourcesLoader::NotificationResourcesLoader(std::unique_ptr<Complet
ionCallback> completionCallback) | 43 NotificationResourcesLoader::NotificationResourcesLoader(std::unique_ptr<Complet
ionCallback> completionCallback) |
| 40 : m_started(false), m_completionCallback(std::move(completionCallback)), m_p
endingRequestCount(0) | 44 : m_started(false), m_completionCallback(std::move(completionCallback)), m_p
endingRequestCount(0) |
| 41 { | 45 { |
| 42 ThreadState::current()->registerPreFinalizer(this); | 46 ThreadState::current()->registerPreFinalizer(this); |
| 43 DCHECK(m_completionCallback); | 47 DCHECK(m_completionCallback); |
| 44 } | 48 } |
| 45 | 49 |
| 46 NotificationResourcesLoader::~NotificationResourcesLoader() | 50 NotificationResourcesLoader::~NotificationResourcesLoader() |
| 47 { | 51 { |
| 48 } | 52 } |
| 49 | 53 |
| 50 void NotificationResourcesLoader::start(ExecutionContext* executionContext, cons
t WebNotificationData& notificationData) | 54 void NotificationResourcesLoader::start(ExecutionContext* executionContext, cons
t WebNotificationData& notificationData) |
| 51 { | 55 { |
| 52 DCHECK(!m_started); | 56 DCHECK(!m_started); |
| 53 m_started = true; | 57 m_started = true; |
| 54 | 58 |
| 55 size_t numActions = notificationData.actions.size(); | 59 size_t numActions = notificationData.actions.size(); |
| 56 m_pendingRequestCount = 2 /* icon and badge */ + numActions; | 60 m_pendingRequestCount = 3 /* image, icon, badge */ + numActions; |
| 57 | 61 |
| 62 // TODO(johnme): ensure image is not loaded when it will not be used. |
| 63 // TODO(mvanouwerkerk): ensure no badge is loaded when it will not be used. |
| 64 loadImage(executionContext, notificationData.image, WTF::bind(&NotificationR
esourcesLoader::didLoadImage, wrapWeakPersistent(this))); |
| 58 loadImage(executionContext, notificationData.icon, WTF::bind(&NotificationRe
sourcesLoader::didLoadIcon, wrapWeakPersistent(this))); | 65 loadImage(executionContext, notificationData.icon, WTF::bind(&NotificationRe
sourcesLoader::didLoadIcon, wrapWeakPersistent(this))); |
| 59 loadImage(executionContext, notificationData.badge, WTF::bind(&NotificationR
esourcesLoader::didLoadBadge, wrapWeakPersistent(this))); | 66 loadImage(executionContext, notificationData.badge, WTF::bind(&NotificationR
esourcesLoader::didLoadBadge, wrapWeakPersistent(this))); |
| 60 | 67 |
| 61 m_actionIcons.resize(numActions); | 68 m_actionIcons.resize(numActions); |
| 62 for (size_t i = 0; i < numActions; i++) | 69 for (size_t i = 0; i < numActions; i++) |
| 63 loadImage(executionContext, notificationData.actions[i].icon, WTF::bind(
&NotificationResourcesLoader::didLoadActionIcon, wrapWeakPersistent(this), i)); | 70 loadImage(executionContext, notificationData.actions[i].icon, WTF::bind(
&NotificationResourcesLoader::didLoadActionIcon, wrapWeakPersistent(this), i)); |
| 64 } | 71 } |
| 65 | 72 |
| 66 std::unique_ptr<WebNotificationResources> NotificationResourcesLoader::getResour
ces() const | 73 std::unique_ptr<WebNotificationResources> NotificationResourcesLoader::getResour
ces() const |
| 67 { | 74 { |
| 68 std::unique_ptr<WebNotificationResources> resources(new WebNotificationResou
rces()); | 75 std::unique_ptr<WebNotificationResources> resources(new WebNotificationResou
rces()); |
| 76 resources->image = m_image; |
| 69 resources->icon = m_icon; | 77 resources->icon = m_icon; |
| 70 resources->badge = m_badge; | 78 resources->badge = m_badge; |
| 71 resources->actionIcons = m_actionIcons; | 79 resources->actionIcons = m_actionIcons; |
| 72 return resources; | 80 return resources; |
| 73 } | 81 } |
| 74 | 82 |
| 75 void NotificationResourcesLoader::stop() | 83 void NotificationResourcesLoader::stop() |
| 76 { | 84 { |
| 77 for (auto imageLoader : m_imageLoaders) | 85 for (auto imageLoader : m_imageLoaders) |
| 78 imageLoader->stop(); | 86 imageLoader->stop(); |
| 79 } | 87 } |
| 80 | 88 |
| 81 DEFINE_TRACE(NotificationResourcesLoader) | 89 DEFINE_TRACE(NotificationResourcesLoader) |
| 82 { | 90 { |
| 83 visitor->trace(m_imageLoaders); | 91 visitor->trace(m_imageLoaders); |
| 84 } | 92 } |
| 85 | 93 |
| 86 void NotificationResourcesLoader::loadImage(ExecutionContext* executionContext,
const KURL& url, std::unique_ptr<NotificationImageLoader::ImageCallback> imageCa
llback) | 94 void NotificationResourcesLoader::loadImage(ExecutionContext* executionContext,
const KURL& url, std::unique_ptr<NotificationImageLoader::ImageCallback> imageCa
llback) |
| 87 { | 95 { |
| 88 if (url.isNull() || url.isEmpty() || !url.isValid()) { | 96 if (url.isNull() || url.isEmpty() || !url.isValid()) { |
| 89 didFinishRequest(); | 97 didFinishRequest(); |
| 90 return; | 98 return; |
| 91 } | 99 } |
| 92 | 100 |
| 93 NotificationImageLoader* imageLoader = new NotificationImageLoader(); | 101 NotificationImageLoader* imageLoader = new NotificationImageLoader(); |
| 94 m_imageLoaders.append(imageLoader); | 102 m_imageLoaders.append(imageLoader); |
| 95 imageLoader->start(executionContext, url, std::move(imageCallback)); | 103 imageLoader->start(executionContext, url, std::move(imageCallback)); |
| 96 } | 104 } |
| 97 | 105 |
| 106 void NotificationResourcesLoader::didLoadImage(const SkBitmap& image) |
| 107 { |
| 108 m_image = scaleDownIfNeeded(image, kWebNotificationMaxImageWidthPx, kWebNoti
ficationMaxImageHeightPx); |
| 109 didFinishRequest(); |
| 110 } |
| 111 |
| 98 void NotificationResourcesLoader::didLoadIcon(const SkBitmap& image) | 112 void NotificationResourcesLoader::didLoadIcon(const SkBitmap& image) |
| 99 { | 113 { |
| 100 m_icon = scaleDownIfNeeded(image, kWebNotificationMaxIconSizePx); | 114 m_icon = scaleDownIfNeeded(image, kWebNotificationMaxIconSizePx, kWebNotific
ationMaxIconSizePx); |
| 101 didFinishRequest(); | 115 didFinishRequest(); |
| 102 } | 116 } |
| 103 | 117 |
| 104 void NotificationResourcesLoader::didLoadBadge(const SkBitmap& image) | 118 void NotificationResourcesLoader::didLoadBadge(const SkBitmap& image) |
| 105 { | 119 { |
| 106 m_badge = scaleDownIfNeeded(image, kWebNotificationMaxBadgeSizePx); | 120 m_badge = scaleDownIfNeeded(image, kWebNotificationMaxBadgeSizePx, kWebNotif
icationMaxBadgeSizePx); |
| 107 didFinishRequest(); | 121 didFinishRequest(); |
| 108 } | 122 } |
| 109 | 123 |
| 110 void NotificationResourcesLoader::didLoadActionIcon(size_t actionIndex, const Sk
Bitmap& image) | 124 void NotificationResourcesLoader::didLoadActionIcon(size_t actionIndex, const Sk
Bitmap& image) |
| 111 { | 125 { |
| 112 DCHECK_LT(actionIndex, m_actionIcons.size()); | 126 DCHECK_LT(actionIndex, m_actionIcons.size()); |
| 113 | 127 |
| 114 m_actionIcons[actionIndex] = scaleDownIfNeeded(image, kWebNotificationMaxAct
ionIconSizePx); | 128 m_actionIcons[actionIndex] = scaleDownIfNeeded(image, kWebNotificationMaxAct
ionIconSizePx, kWebNotificationMaxActionIconSizePx); |
| 115 didFinishRequest(); | 129 didFinishRequest(); |
| 116 } | 130 } |
| 117 | 131 |
| 118 void NotificationResourcesLoader::didFinishRequest() | 132 void NotificationResourcesLoader::didFinishRequest() |
| 119 { | 133 { |
| 120 DCHECK_GT(m_pendingRequestCount, 0); | 134 DCHECK_GT(m_pendingRequestCount, 0); |
| 121 m_pendingRequestCount--; | 135 m_pendingRequestCount--; |
| 122 if (!m_pendingRequestCount) { | 136 if (!m_pendingRequestCount) { |
| 123 stop(); | 137 stop(); |
| 124 (*m_completionCallback)(this); | 138 (*m_completionCallback)(this); |
| 125 // The |this| pointer may have been deleted now. | 139 // The |this| pointer may have been deleted now. |
| 126 } | 140 } |
| 127 } | 141 } |
| 128 | 142 |
| 129 } // namespace blink | 143 } // namespace blink |
| OLD | NEW |