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