Chromium Code Reviews| 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/NotificationImageLoader.h" | 5 #include "modules/notifications/NotificationImageLoader.h" | 
| 6 | 6 | 
| 7 #include "core/dom/ExecutionContext.h" | 7 #include "core/dom/ExecutionContext.h" | 
| 8 #include "core/fetch/ResourceLoaderOptions.h" | 8 #include "core/fetch/ResourceLoaderOptions.h" | 
| 9 #include "platform/Histogram.h" | 9 #include "platform/Histogram.h" | 
| 10 #include "platform/image-decoders/ImageDecoder.h" | 10 #include "platform/image-decoders/ImageDecoder.h" | 
| 11 #include "platform/image-decoders/ImageFrame.h" | 11 #include "platform/image-decoders/ImageFrame.h" | 
| 12 #include "platform/network/ResourceError.h" | 12 #include "platform/network/ResourceError.h" | 
| 13 #include "platform/network/ResourceLoadPriority.h" | 13 #include "platform/network/ResourceLoadPriority.h" | 
| 14 #include "platform/network/ResourceRequest.h" | 14 #include "platform/network/ResourceRequest.h" | 
| 15 #include "platform/weborigin/KURL.h" | 15 #include "platform/weborigin/KURL.h" | 
| 16 #include "public/platform/WebURLRequest.h" | 16 #include "public/platform/WebURLRequest.h" | 
| 17 #include "third_party/skia/include/core/SkBitmap.h" | 17 #include "public/platform/modules/notifications/WebNotificationConstants.h" | 
| 18 #include "skia/ext/image_operations.h" | |
| 18 #include "wtf/CurrentTime.h" | 19 #include "wtf/CurrentTime.h" | 
| 19 #include "wtf/Threading.h" | 20 #include "wtf/Threading.h" | 
| 20 #include <memory> | 21 #include <memory> | 
| 21 | 22 | 
| 23 #define NOTIFICATION_PER_TYPE_HISTOGRAM_COUNTS(metric, type_name, value, max) \ | |
| 24 case NotificationImageLoader::Type::type_name: { \ | |
| 
 
Peter Beverloo
2016/11/30 17:44:02
It's technically not needed to quality Notificatio
 
johnme
2016/11/30 19:08:35
Acknowledged.
 
 | |
| 25 DEFINE_THREAD_SAFE_STATIC_LOCAL( \ | |
| 26 CustomCountHistogram, metric##type_name##Histogram, \ | |
| 27 new CustomCountHistogram("Notifications." #metric "." #type_name, \ | |
| 28 1 /* min */, max, 50 /* buckets */)); \ | |
| 29 metric##type_name##Histogram.count(value); \ | |
| 30 break; \ | |
| 31 } | |
| 32 | |
| 33 #define NOTIFICATION_HISTOGRAM_COUNTS(metric, type, value, max) \ | |
| 34 switch (type) { \ | |
| 35 NOTIFICATION_PER_TYPE_HISTOGRAM_COUNTS(metric, Image, value, max) \ | |
| 36 NOTIFICATION_PER_TYPE_HISTOGRAM_COUNTS(metric, Icon, value, max) \ | |
| 37 NOTIFICATION_PER_TYPE_HISTOGRAM_COUNTS(metric, Badge, value, max) \ | |
| 38 NOTIFICATION_PER_TYPE_HISTOGRAM_COUNTS(metric, ActionIcon, value, max) \ | |
| 39 } | |
| 40 | |
| 22 namespace { | 41 namespace { | 
| 23 | 42 | 
| 24 // 99.9% of all images were fetched successfully in 90 seconds. | 43 // 99.9% of all images were fetched successfully in 90 seconds. | 
| 25 const unsigned long kImageFetchTimeoutInMs = 90000; | 44 const unsigned long kImageFetchTimeoutInMs = 90000; | 
| 26 | 45 | 
| 27 } // namespace | 46 } // namespace | 
| 28 | 47 | 
| 29 namespace blink { | 48 namespace blink { | 
| 30 | 49 | 
| 31 NotificationImageLoader::NotificationImageLoader() | 50 NotificationImageLoader::NotificationImageLoader(Type type) | 
| 32 : m_stopped(false), m_startTime(0.0) {} | 51 : m_type(type), m_stopped(false), m_startTime(0.0) {} | 
| 33 | 52 | 
| 34 NotificationImageLoader::~NotificationImageLoader() {} | 53 NotificationImageLoader::~NotificationImageLoader() {} | 
| 35 | 54 | 
| 55 // static | |
| 56 SkBitmap NotificationImageLoader::scaleDownIfNeeded(const SkBitmap& image, | |
| 57 Type type) { | |
| 58 int maxWidthPx = -1, maxHeightPx = -1; | |
| 59 switch (type) { | |
| 60 case Type::Image: | |
| 61 maxWidthPx = kWebNotificationMaxImageWidthPx; | |
| 62 maxHeightPx = kWebNotificationMaxImageHeightPx; | |
| 63 break; | |
| 64 case Type::Icon: | |
| 65 maxWidthPx = kWebNotificationMaxIconSizePx; | |
| 66 maxHeightPx = kWebNotificationMaxIconSizePx; | |
| 67 break; | |
| 68 case Type::Badge: | |
| 69 maxWidthPx = kWebNotificationMaxBadgeSizePx; | |
| 70 maxHeightPx = kWebNotificationMaxBadgeSizePx; | |
| 71 break; | |
| 72 case Type::ActionIcon: | |
| 73 maxWidthPx = kWebNotificationMaxActionIconSizePx; | |
| 74 maxHeightPx = kWebNotificationMaxActionIconSizePx; | |
| 75 break; | |
| 76 } | |
| 77 DCHECK_GT(maxWidthPx, 0); | |
| 78 DCHECK_GT(maxHeightPx, 0); | |
| 
 
Peter Beverloo
2016/11/30 17:44:02
micro nit: I have a very mild preference for initi
 
johnme
2016/11/30 19:08:35
Done.
 
 | |
| 79 // TODO(peter): Explore doing the scaling on a background thread. | |
| 80 if (image.width() > maxWidthPx || image.height() > maxHeightPx) { | |
| 81 double scale = std::min(static_cast<double>(maxWidthPx) / image.width(), | |
| 82 static_cast<double>(maxHeightPx) / image.height()); | |
| 83 double startTime = monotonicallyIncreasingTimeMS(); | |
| 84 // TODO(peter): Try using RESIZE_BETTER for large images. | |
| 85 SkBitmap scaledImage = | |
| 86 skia::ImageOperations::Resize(image, skia::ImageOperations::RESIZE_BEST, | |
| 87 std::lround(scale * image.width()), | |
| 88 std::lround(scale * image.height())); | |
| 89 NOTIFICATION_HISTOGRAM_COUNTS(LoadScaleDownTime, type, | |
| 90 monotonicallyIncreasingTimeMS() - startTime, | |
| 91 1000 * 10 /* 10 seconds max */); | |
| 92 return scaledImage; | |
| 93 } | |
| 94 return image; | |
| 95 } | |
| 96 | |
| 36 void NotificationImageLoader::start( | 97 void NotificationImageLoader::start( | 
| 37 ExecutionContext* executionContext, | 98 ExecutionContext* executionContext, | 
| 38 const KURL& url, | 99 const KURL& url, | 
| 39 std::unique_ptr<ImageCallback> imageCallback) { | 100 std::unique_ptr<ImageCallback> imageCallback) { | 
| 40 DCHECK(!m_stopped); | 101 DCHECK(!m_stopped); | 
| 41 | 102 | 
| 42 m_startTime = monotonicallyIncreasingTimeMS(); | 103 m_startTime = monotonicallyIncreasingTimeMS(); | 
| 43 m_imageCallback = std::move(imageCallback); | 104 m_imageCallback = std::move(imageCallback); | 
| 44 | 105 | 
| 45 ThreadableLoaderOptions threadableLoaderOptions; | 106 ThreadableLoaderOptions threadableLoaderOptions; | 
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 82 m_data->append(data, length); | 143 m_data->append(data, length); | 
| 83 } | 144 } | 
| 84 | 145 | 
| 85 void NotificationImageLoader::didFinishLoading(unsigned long resourceIdentifier, | 146 void NotificationImageLoader::didFinishLoading(unsigned long resourceIdentifier, | 
| 86 double finishTime) { | 147 double finishTime) { | 
| 87 // If this has been stopped it is not desirable to trigger further work, | 148 // If this has been stopped it is not desirable to trigger further work, | 
| 88 // there is a shutdown of some sort in progress. | 149 // there is a shutdown of some sort in progress. | 
| 89 if (m_stopped) | 150 if (m_stopped) | 
| 90 return; | 151 return; | 
| 91 | 152 | 
| 92 DEFINE_THREAD_SAFE_STATIC_LOCAL( | 153 NOTIFICATION_HISTOGRAM_COUNTS(LoadFinishTime, m_type, | 
| 93 CustomCountHistogram, finishedTimeHistogram, | 154 monotonicallyIncreasingTimeMS() - m_startTime, | 
| 94 new CustomCountHistogram("Notifications.Icon.LoadFinishTime", 1, | 155 1000 * 60 * 60 /* 1 hour max */); | 
| 95 1000 * 60 * 60 /* 1 hour max */, | |
| 96 50 /* buckets */)); | |
| 97 finishedTimeHistogram.count(monotonicallyIncreasingTimeMS() - m_startTime); | |
| 98 | 156 | 
| 99 if (m_data) { | 157 if (m_data) { | 
| 100 DEFINE_THREAD_SAFE_STATIC_LOCAL( | 158 NOTIFICATION_HISTOGRAM_COUNTS(LoadFileSize, m_type, m_data->size(), | 
| 101 CustomCountHistogram, fileSizeHistogram, | 159 10000000 /* ~10mb max */); | 
| 102 new CustomCountHistogram("Notifications.Icon.FileSize", 1, | |
| 103 10000000 /* ~10mb max */, 50 /* buckets */)); | |
| 104 fileSizeHistogram.count(m_data->size()); | |
| 105 | 160 | 
| 106 std::unique_ptr<ImageDecoder> decoder = ImageDecoder::create( | 161 std::unique_ptr<ImageDecoder> decoder = ImageDecoder::create( | 
| 107 m_data, true /* dataComplete */, ImageDecoder::AlphaPremultiplied, | 162 m_data, true /* dataComplete */, ImageDecoder::AlphaPremultiplied, | 
| 108 ImageDecoder::ColorSpaceApplied); | 163 ImageDecoder::ColorSpaceApplied); | 
| 109 if (decoder) { | 164 if (decoder) { | 
| 110 // The |ImageFrame*| is owned by the decoder. | 165 // The |ImageFrame*| is owned by the decoder. | 
| 111 ImageFrame* imageFrame = decoder->frameBufferAtIndex(0); | 166 ImageFrame* imageFrame = decoder->frameBufferAtIndex(0); | 
| 112 if (imageFrame) { | 167 if (imageFrame) { | 
| 113 (*m_imageCallback)(imageFrame->bitmap()); | 168 (*m_imageCallback)(imageFrame->bitmap()); | 
| 114 return; | 169 return; | 
| 115 } | 170 } | 
| 116 } | 171 } | 
| 117 } | 172 } | 
| 118 runCallbackWithEmptyBitmap(); | 173 runCallbackWithEmptyBitmap(); | 
| 119 } | 174 } | 
| 120 | 175 | 
| 121 void NotificationImageLoader::didFail(const ResourceError& error) { | 176 void NotificationImageLoader::didFail(const ResourceError& error) { | 
| 122 DEFINE_THREAD_SAFE_STATIC_LOCAL( | 177 NOTIFICATION_HISTOGRAM_COUNTS(LoadFailTime, m_type, | 
| 123 CustomCountHistogram, failedTimeHistogram, | 178 monotonicallyIncreasingTimeMS() - m_startTime, | 
| 124 new CustomCountHistogram("Notifications.Icon.LoadFailTime", 1, | 179 1000 * 60 * 60 /* 1 hour max */); | 
| 125 1000 * 60 * 60 /* 1 hour max */, | |
| 126 50 /* buckets */)); | |
| 127 failedTimeHistogram.count(monotonicallyIncreasingTimeMS() - m_startTime); | |
| 128 | 180 | 
| 129 runCallbackWithEmptyBitmap(); | 181 runCallbackWithEmptyBitmap(); | 
| 130 } | 182 } | 
| 131 | 183 | 
| 132 void NotificationImageLoader::didFailRedirectCheck() { | 184 void NotificationImageLoader::didFailRedirectCheck() { | 
| 133 runCallbackWithEmptyBitmap(); | 185 runCallbackWithEmptyBitmap(); | 
| 134 } | 186 } | 
| 135 | 187 | 
| 136 void NotificationImageLoader::runCallbackWithEmptyBitmap() { | 188 void NotificationImageLoader::runCallbackWithEmptyBitmap() { | 
| 137 // If this has been stopped it is not desirable to trigger further work, | 189 // If this has been stopped it is not desirable to trigger further work, | 
| 138 // there is a shutdown of some sort in progress. | 190 // there is a shutdown of some sort in progress. | 
| 139 if (m_stopped) | 191 if (m_stopped) | 
| 140 return; | 192 return; | 
| 141 | 193 | 
| 142 (*m_imageCallback)(SkBitmap()); | 194 (*m_imageCallback)(SkBitmap()); | 
| 143 } | 195 } | 
| 144 | 196 | 
| 145 } // namespace blink | 197 } // namespace blink | 
| OLD | NEW |