| 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" | |
| 10 #include "public/platform/modules/notifications/WebNotificationData.h" | 9 #include "public/platform/modules/notifications/WebNotificationData.h" |
| 11 #include "public/platform/modules/notifications/WebNotificationResources.h" | 10 #include "public/platform/modules/notifications/WebNotificationResources.h" |
| 12 #include "skia/ext/image_operations.h" | |
| 13 #include "third_party/skia/include/core/SkBitmap.h" | |
| 14 #include "wtf/CurrentTime.h" | 11 #include "wtf/CurrentTime.h" |
| 15 #include "wtf/Threading.h" | 12 #include "wtf/Threading.h" |
| 16 #include <cmath> | 13 #include <cmath> |
| 17 | 14 |
| 18 namespace blink { | 15 namespace blink { |
| 19 | 16 |
| 20 namespace { | |
| 21 | |
| 22 // Scales down |image| to fit within |maxWidthPx|x|maxHeightPx| if it is larger | |
| 23 // and returns the result. Otherwise does nothing and returns |image| unchanged. | |
| 24 // TODO(mvanouwerkerk): Explore doing the scaling on a background thread. | |
| 25 SkBitmap scaleDownIfNeeded(const SkBitmap& image, | |
| 26 int maxWidthPx, | |
| 27 int maxHeightPx) { | |
| 28 if (image.width() > maxWidthPx || image.height() > maxHeightPx) { | |
| 29 double scale = std::min(static_cast<double>(maxWidthPx) / image.width(), | |
| 30 static_cast<double>(maxHeightPx) / image.height()); | |
| 31 DEFINE_THREAD_SAFE_STATIC_LOCAL( | |
| 32 CustomCountHistogram, scaleTimeHistogram, | |
| 33 new CustomCountHistogram("Notifications.Icon.ScaleDownTime", 1, | |
| 34 1000 * 10 /* 10 seconds max */, | |
| 35 50 /* buckets */)); | |
| 36 double startTime = monotonicallyIncreasingTimeMS(); | |
| 37 // TODO(peter): Try using RESIZE_BETTER for large images. | |
| 38 SkBitmap scaledImage = | |
| 39 skia::ImageOperations::Resize(image, skia::ImageOperations::RESIZE_BEST, | |
| 40 std::lround(scale * image.width()), | |
| 41 std::lround(scale * image.height())); | |
| 42 scaleTimeHistogram.count(monotonicallyIncreasingTimeMS() - startTime); | |
| 43 return scaledImage; | |
| 44 } | |
| 45 return image; | |
| 46 } | |
| 47 | |
| 48 } // namespace | |
| 49 | |
| 50 NotificationResourcesLoader::NotificationResourcesLoader( | 17 NotificationResourcesLoader::NotificationResourcesLoader( |
| 51 std::unique_ptr<CompletionCallback> completionCallback) | 18 std::unique_ptr<CompletionCallback> completionCallback) |
| 52 : m_started(false), | 19 : m_started(false), |
| 53 m_completionCallback(std::move(completionCallback)), | 20 m_completionCallback(std::move(completionCallback)), |
| 54 m_pendingRequestCount(0) { | 21 m_pendingRequestCount(0) { |
| 55 ThreadState::current()->registerPreFinalizer(this); | 22 ThreadState::current()->registerPreFinalizer(this); |
| 56 DCHECK(m_completionCallback); | 23 DCHECK(m_completionCallback); |
| 57 } | 24 } |
| 58 | 25 |
| 59 NotificationResourcesLoader::~NotificationResourcesLoader() {} | 26 NotificationResourcesLoader::~NotificationResourcesLoader() {} |
| 60 | 27 |
| 61 void NotificationResourcesLoader::start( | 28 void NotificationResourcesLoader::start( |
| 62 ExecutionContext* executionContext, | 29 ExecutionContext* executionContext, |
| 63 const WebNotificationData& notificationData) { | 30 const WebNotificationData& notificationData) { |
| 64 DCHECK(!m_started); | 31 DCHECK(!m_started); |
| 65 m_started = true; | 32 m_started = true; |
| 66 | 33 |
| 67 size_t numActions = notificationData.actions.size(); | 34 size_t numActions = notificationData.actions.size(); |
| 68 m_pendingRequestCount = 3 /* image, icon, badge */ + numActions; | 35 m_pendingRequestCount = 3 /* image, icon, badge */ + numActions; |
| 69 | 36 |
| 70 // TODO(johnme): ensure image is not loaded when it will not be used. | 37 // TODO(johnme): ensure image is not loaded when it will not be used. |
| 71 // TODO(mvanouwerkerk): ensure no badge is loaded when it will not be used. | 38 // TODO(mvanouwerkerk): ensure no badge is loaded when it will not be used. |
| 72 loadImage(executionContext, notificationData.image, | 39 loadImage(executionContext, NotificationImageLoader::Type::Image, |
| 40 notificationData.image, |
| 73 WTF::bind(&NotificationResourcesLoader::didLoadImage, | 41 WTF::bind(&NotificationResourcesLoader::didLoadImage, |
| 74 wrapWeakPersistent(this))); | 42 wrapWeakPersistent(this))); |
| 75 loadImage(executionContext, notificationData.icon, | 43 loadImage(executionContext, NotificationImageLoader::Type::Icon, |
| 44 notificationData.icon, |
| 76 WTF::bind(&NotificationResourcesLoader::didLoadIcon, | 45 WTF::bind(&NotificationResourcesLoader::didLoadIcon, |
| 77 wrapWeakPersistent(this))); | 46 wrapWeakPersistent(this))); |
| 78 loadImage(executionContext, notificationData.badge, | 47 loadImage(executionContext, NotificationImageLoader::Type::Badge, |
| 48 notificationData.badge, |
| 79 WTF::bind(&NotificationResourcesLoader::didLoadBadge, | 49 WTF::bind(&NotificationResourcesLoader::didLoadBadge, |
| 80 wrapWeakPersistent(this))); | 50 wrapWeakPersistent(this))); |
| 81 | 51 |
| 82 m_actionIcons.resize(numActions); | 52 m_actionIcons.resize(numActions); |
| 83 for (size_t i = 0; i < numActions; i++) | 53 for (size_t i = 0; i < numActions; i++) |
| 84 loadImage(executionContext, notificationData.actions[i].icon, | 54 loadImage(executionContext, NotificationImageLoader::Type::ActionIcon, |
| 55 notificationData.actions[i].icon, |
| 85 WTF::bind(&NotificationResourcesLoader::didLoadActionIcon, | 56 WTF::bind(&NotificationResourcesLoader::didLoadActionIcon, |
| 86 wrapWeakPersistent(this), i)); | 57 wrapWeakPersistent(this), i)); |
| 87 } | 58 } |
| 88 | 59 |
| 89 std::unique_ptr<WebNotificationResources> | 60 std::unique_ptr<WebNotificationResources> |
| 90 NotificationResourcesLoader::getResources() const { | 61 NotificationResourcesLoader::getResources() const { |
| 91 std::unique_ptr<WebNotificationResources> resources( | 62 std::unique_ptr<WebNotificationResources> resources( |
| 92 new WebNotificationResources()); | 63 new WebNotificationResources()); |
| 93 resources->image = m_image; | 64 resources->image = m_image; |
| 94 resources->icon = m_icon; | 65 resources->icon = m_icon; |
| 95 resources->badge = m_badge; | 66 resources->badge = m_badge; |
| 96 resources->actionIcons = m_actionIcons; | 67 resources->actionIcons = m_actionIcons; |
| 97 return resources; | 68 return resources; |
| 98 } | 69 } |
| 99 | 70 |
| 100 void NotificationResourcesLoader::stop() { | 71 void NotificationResourcesLoader::stop() { |
| 101 for (auto imageLoader : m_imageLoaders) | 72 for (auto imageLoader : m_imageLoaders) |
| 102 imageLoader->stop(); | 73 imageLoader->stop(); |
| 103 } | 74 } |
| 104 | 75 |
| 105 DEFINE_TRACE(NotificationResourcesLoader) { | 76 DEFINE_TRACE(NotificationResourcesLoader) { |
| 106 visitor->trace(m_imageLoaders); | 77 visitor->trace(m_imageLoaders); |
| 107 } | 78 } |
| 108 | 79 |
| 109 void NotificationResourcesLoader::loadImage( | 80 void NotificationResourcesLoader::loadImage( |
| 110 ExecutionContext* executionContext, | 81 ExecutionContext* executionContext, |
| 82 NotificationImageLoader::Type type, |
| 111 const KURL& url, | 83 const KURL& url, |
| 112 std::unique_ptr<NotificationImageLoader::ImageCallback> imageCallback) { | 84 std::unique_ptr<NotificationImageLoader::ImageCallback> imageCallback) { |
| 113 if (url.isNull() || url.isEmpty() || !url.isValid()) { | 85 if (url.isNull() || url.isEmpty() || !url.isValid()) { |
| 114 didFinishRequest(); | 86 didFinishRequest(); |
| 115 return; | 87 return; |
| 116 } | 88 } |
| 117 | 89 |
| 118 NotificationImageLoader* imageLoader = new NotificationImageLoader(); | 90 NotificationImageLoader* imageLoader = new NotificationImageLoader(type); |
| 119 m_imageLoaders.append(imageLoader); | 91 m_imageLoaders.append(imageLoader); |
| 120 imageLoader->start(executionContext, url, std::move(imageCallback)); | 92 imageLoader->start(executionContext, url, std::move(imageCallback)); |
| 121 } | 93 } |
| 122 | 94 |
| 123 void NotificationResourcesLoader::didLoadImage(const SkBitmap& image) { | 95 void NotificationResourcesLoader::didLoadImage(const SkBitmap& image) { |
| 124 m_image = scaleDownIfNeeded(image, kWebNotificationMaxImageWidthPx, | 96 m_image = NotificationImageLoader::scaleDownIfNeeded( |
| 125 kWebNotificationMaxImageHeightPx); | 97 image, NotificationImageLoader::Type::Image); |
| 126 didFinishRequest(); | 98 didFinishRequest(); |
| 127 } | 99 } |
| 128 | 100 |
| 129 void NotificationResourcesLoader::didLoadIcon(const SkBitmap& image) { | 101 void NotificationResourcesLoader::didLoadIcon(const SkBitmap& image) { |
| 130 m_icon = scaleDownIfNeeded(image, kWebNotificationMaxIconSizePx, | 102 m_icon = NotificationImageLoader::scaleDownIfNeeded( |
| 131 kWebNotificationMaxIconSizePx); | 103 image, NotificationImageLoader::Type::Icon); |
| 132 didFinishRequest(); | 104 didFinishRequest(); |
| 133 } | 105 } |
| 134 | 106 |
| 135 void NotificationResourcesLoader::didLoadBadge(const SkBitmap& image) { | 107 void NotificationResourcesLoader::didLoadBadge(const SkBitmap& image) { |
| 136 m_badge = scaleDownIfNeeded(image, kWebNotificationMaxBadgeSizePx, | 108 m_badge = NotificationImageLoader::scaleDownIfNeeded( |
| 137 kWebNotificationMaxBadgeSizePx); | 109 image, NotificationImageLoader::Type::Badge); |
| 138 didFinishRequest(); | 110 didFinishRequest(); |
| 139 } | 111 } |
| 140 | 112 |
| 141 void NotificationResourcesLoader::didLoadActionIcon(size_t actionIndex, | 113 void NotificationResourcesLoader::didLoadActionIcon(size_t actionIndex, |
| 142 const SkBitmap& image) { | 114 const SkBitmap& image) { |
| 143 DCHECK_LT(actionIndex, m_actionIcons.size()); | 115 DCHECK_LT(actionIndex, m_actionIcons.size()); |
| 144 | 116 |
| 145 m_actionIcons[actionIndex] = | 117 m_actionIcons[actionIndex] = NotificationImageLoader::scaleDownIfNeeded( |
| 146 scaleDownIfNeeded(image, kWebNotificationMaxActionIconSizePx, | 118 image, NotificationImageLoader::Type::ActionIcon); |
| 147 kWebNotificationMaxActionIconSizePx); | |
| 148 didFinishRequest(); | 119 didFinishRequest(); |
| 149 } | 120 } |
| 150 | 121 |
| 151 void NotificationResourcesLoader::didFinishRequest() { | 122 void NotificationResourcesLoader::didFinishRequest() { |
| 152 DCHECK_GT(m_pendingRequestCount, 0); | 123 DCHECK_GT(m_pendingRequestCount, 0); |
| 153 m_pendingRequestCount--; | 124 m_pendingRequestCount--; |
| 154 if (!m_pendingRequestCount) { | 125 if (!m_pendingRequestCount) { |
| 155 stop(); | 126 stop(); |
| 156 (*m_completionCallback)(this); | 127 (*m_completionCallback)(this); |
| 157 // The |this| pointer may have been deleted now. | 128 // The |this| pointer may have been deleted now. |
| 158 } | 129 } |
| 159 } | 130 } |
| 160 | 131 |
| 161 } // namespace blink | 132 } // namespace blink |
| OLD | NEW |