| 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 |