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