OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/child/notifications/pending_notification.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/barrier_closure.h" | |
10 #include "base/bind.h" | |
11 #include "base/callback.h" | |
12 #include "base/location.h" | |
13 #include "base/metrics/histogram_macros.h" | |
14 #include "base/thread_task_runner_handle.h" | |
15 #include "content/common/notification_constants.h" | |
16 #include "content/public/common/notification_resources.h" | |
17 #include "skia/ext/image_operations.h" | |
18 #include "url/gurl.h" | |
19 | |
20 namespace content { | |
21 | |
22 namespace { | |
23 | |
24 // Scales down |icon| to fit within |max_size_px| if its width or height is | |
25 // larger than |max_size_px| and returns the result. Otherwise does nothing and | |
26 // returns |icon| unchanged. | |
27 SkBitmap ScaleDownIfNeeded(const SkBitmap& icon, int max_size_px) { | |
28 if (icon.width() > max_size_px || icon.height() > max_size_px) { | |
29 SCOPED_UMA_HISTOGRAM_TIMER("Notifications.Icon.ScaleDownTime"); | |
30 return skia::ImageOperations::Resize(icon, | |
31 skia::ImageOperations::RESIZE_BEST, | |
32 std::min(icon.width(), max_size_px), | |
33 std::min(icon.height(), max_size_px)); | |
34 } | |
35 return icon; | |
36 } | |
37 | |
38 } // namespace | |
39 | |
40 PendingNotification::PendingNotification( | |
41 const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner) | |
42 : main_task_runner_(main_task_runner), weak_factory_(this) {} | |
43 | |
44 PendingNotification::~PendingNotification() {} | |
45 | |
46 void PendingNotification::FetchResources( | |
47 const blink::WebNotificationData& notification_data, | |
48 const base::Closure& fetches_finished_callback) { | |
49 // TODO(mvanouwerkerk): Add a timeout mechanism: crbug.com/579137 | |
50 | |
51 size_t num_actions = notification_data.actions.size(); | |
52 action_icons_.resize(num_actions); | |
53 | |
54 size_t num_closures = 2 /* notification icon and badge */ + num_actions; | |
55 fetches_finished_barrier_closure_ = | |
56 base::BarrierClosure(num_closures, fetches_finished_callback); | |
57 | |
58 FetchImageResource(notification_data.icon, | |
59 base::Bind(&PendingNotification::DidFetchNotificationIcon, | |
60 weak_factory_.GetWeakPtr())); | |
61 FetchImageResource(notification_data.badge, | |
62 base::Bind(&PendingNotification::DidFetchBadge, | |
63 weak_factory_.GetWeakPtr())); | |
64 for (size_t i = 0; i < num_actions; i++) { | |
65 FetchImageResource(notification_data.actions[i].icon, | |
66 base::Bind(&PendingNotification::DidFetchActionIcon, | |
67 weak_factory_.GetWeakPtr(), i)); | |
68 } | |
69 } | |
70 | |
71 NotificationResources PendingNotification::GetResources() const { | |
72 NotificationResources resources; | |
73 resources.notification_icon = notification_icon_; | |
74 resources.badge = badge_; | |
75 resources.action_icons = action_icons_; | |
76 return resources; | |
77 } | |
78 | |
79 void PendingNotification::FetchImageResource( | |
80 const blink::WebURL& image_web_url, | |
81 const ImageLoadCompletedCallback& image_callback) { | |
82 if (image_web_url.isEmpty()) { | |
83 image_callback.Run(SkBitmap()); | |
84 return; | |
85 } | |
86 | |
87 // Explicitly convert the WebURL to a GURL before passing it to a different | |
88 // thread. This is important because WebURLs must not be passed between | |
89 // threads, and per base::Bind() semantics conversion would otherwise be done | |
90 // on the receiving thread. | |
91 GURL image_gurl(image_web_url); | |
92 | |
93 scoped_refptr<NotificationImageLoader> image_loader( | |
94 new NotificationImageLoader(image_callback, | |
95 base::ThreadTaskRunnerHandle::Get(), | |
96 main_task_runner_)); | |
97 image_loaders_.push_back(image_loader); | |
98 main_task_runner_->PostTask( | |
99 FROM_HERE, base::Bind(&NotificationImageLoader::StartOnMainThread, | |
100 image_loader, image_gurl)); | |
101 } | |
102 | |
103 void PendingNotification::DidFetchNotificationIcon(const SkBitmap& bitmap) { | |
104 notification_icon_ = | |
105 ScaleDownIfNeeded(bitmap, kPlatformNotificationMaxIconSizePx); | |
106 fetches_finished_barrier_closure_.Run(); | |
107 } | |
108 | |
109 void PendingNotification::DidFetchBadge(const SkBitmap& bitmap) { | |
110 badge_ = ScaleDownIfNeeded(bitmap, kPlatformNotificationMaxBadgeSizePx); | |
111 fetches_finished_barrier_closure_.Run(); | |
112 } | |
113 | |
114 void PendingNotification::DidFetchActionIcon(size_t action_index, | |
115 const SkBitmap& bitmap) { | |
116 DCHECK_LT(action_index, action_icons_.size()); | |
117 | |
118 action_icons_[action_index] = | |
119 ScaleDownIfNeeded(bitmap, kPlatformNotificationMaxActionIconSizePx); | |
120 fetches_finished_barrier_closure_.Run(); | |
121 } | |
122 | |
123 } // namespace content | |
OLD | NEW |