OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 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 "chrome/browser/notifications/notification_conversion_helper.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "base/memory/scoped_ptr.h" | |
9 #include "base/strings/utf_string_conversions.h" | |
10 #include "chrome/common/extensions/api/notification_provider.h" | |
11 #include "chrome/common/extensions/api/notifications/notification_style.h" | |
12 #include "ui/gfx/image/image_skia.h" | |
13 #include "ui/gfx/image/image_skia_rep.h" | |
14 #include "ui/gfx/skia_util.h" | |
15 | |
16 void NotificationConversionHelper::NotificationToNotificationOptions( | |
17 const Notification& notification, | |
18 extensions::api::notifications::NotificationOptions* options) { | |
19 // Extract required fields: type, title, message, and icon. | |
20 std::string type = MapTypeToString(notification.type()); | |
21 options->type = extensions::api::notifications::ParseTemplateType(type); | |
22 | |
23 if (!notification.icon().IsEmpty()) { | |
24 scoped_ptr<extensions::api::notifications::NotificationBitmap> icon( | |
25 new extensions::api::notifications::NotificationBitmap()); | |
26 GfxImageToNotificationBitmap(¬ification.icon(), icon.get()); | |
27 options->icon_bitmap = icon.Pass(); | |
28 } | |
29 | |
30 options->title.reset( | |
31 new std::string(base::UTF16ToUTF8(notification.title()))); | |
32 options->message.reset( | |
33 new std::string(base::UTF16ToUTF8(notification.message()))); | |
34 | |
35 // Handle optional data provided. | |
36 const message_center::RichNotificationData* rich_data = | |
37 ¬ification.rich_notification_data(); | |
38 | |
39 if (!rich_data->small_image.IsEmpty()) { | |
40 scoped_ptr<extensions::api::notifications::NotificationBitmap> icon_mask( | |
41 new extensions::api::notifications::NotificationBitmap()); | |
42 GfxImageToNotificationBitmap(&rich_data->small_image, icon_mask.get()); | |
43 options->app_icon_mask_bitmap = icon_mask.Pass(); | |
44 } | |
45 | |
46 options->priority.reset(new int(rich_data->priority)); | |
47 | |
48 options->is_clickable.reset(new bool(rich_data->clickable)); | |
49 | |
50 options->event_time.reset(new double(rich_data->timestamp.ToDoubleT())); | |
51 | |
52 if (!rich_data->context_message.empty()) | |
53 options->context_message.reset( | |
54 new std::string(base::UTF16ToUTF8(rich_data->context_message))); | |
55 | |
56 if (!rich_data->buttons.empty()) { | |
57 scoped_ptr<std::vector< | |
58 linked_ptr<extensions::api::notifications::NotificationButton> > > | |
59 button_list(new std::vector< | |
60 linked_ptr<extensions::api::notifications::NotificationButton> >); | |
61 for (size_t i = 0; i < rich_data->buttons.size(); i++) { | |
62 linked_ptr<extensions::api::notifications::NotificationButton> button( | |
63 new extensions::api::notifications::NotificationButton); | |
64 button->title = base::UTF16ToUTF8(rich_data->buttons[i].title); | |
65 | |
66 if (!rich_data->buttons[i].icon.IsEmpty()) { | |
67 scoped_ptr<extensions::api::notifications::NotificationBitmap> icon( | |
68 new extensions::api::notifications::NotificationBitmap()); | |
69 GfxImageToNotificationBitmap(&rich_data->buttons[i].icon, icon.get()); | |
70 button->icon_bitmap = icon.Pass(); | |
71 } | |
72 button_list->push_back(button); | |
73 } | |
74 options->buttons = button_list.Pass(); | |
75 } | |
76 | |
77 // Only image type notifications should have images. | |
78 if (type == "image" && !rich_data->image.IsEmpty()) { | |
79 scoped_ptr<extensions::api::notifications::NotificationBitmap> image( | |
80 new extensions::api::notifications::NotificationBitmap()); | |
81 GfxImageToNotificationBitmap(¬ification.image(), image.get()); | |
82 options->image_bitmap = image.Pass(); | |
83 } else if (type != "image" && !rich_data->image.IsEmpty()) { | |
84 DVLOG(1) << "Only image type notifications should have images."; | |
85 } | |
86 | |
87 // Only progress type notifications should have progress bars. | |
88 if (type == "progress") | |
89 options->progress.reset(new int(rich_data->progress)); | |
90 else if (rich_data->progress != 0) | |
91 DVLOG(1) << "Only progress type notifications should have progress."; | |
92 | |
93 // Only list type notifications should have lists. | |
94 if (type == "list" && !rich_data->items.empty()) { | |
95 scoped_ptr<std::vector< | |
96 linked_ptr<extensions::api::notifications::NotificationItem> > > | |
97 list(new std::vector< | |
98 linked_ptr<extensions::api::notifications::NotificationItem> >); | |
99 for (size_t j = 0; j < rich_data->items.size(); j++) { | |
100 linked_ptr<extensions::api::notifications::NotificationItem> item( | |
101 new extensions::api::notifications::NotificationItem); | |
102 item->title = base::UTF16ToUTF8(rich_data->items[j].title); | |
103 item->message = base::UTF16ToUTF8(rich_data->items[j].message); | |
104 list->push_back(item); | |
105 } | |
106 options->items = list.Pass(); | |
107 } else if (type != "list" && !rich_data->items.empty()) { | |
108 DVLOG(1) << "Only list type notifications should have lists."; | |
109 } | |
110 } | |
111 | |
112 void NotificationConversionHelper::GfxImageToNotificationBitmap( | |
113 const gfx::Image* gfx_image, | |
114 extensions::api::notifications::NotificationBitmap* notification_bitmap) { | |
115 SkBitmap sk_bitmap = gfx_image->AsBitmap(); | |
116 sk_bitmap.lockPixels(); | |
117 | |
118 notification_bitmap->width = sk_bitmap.width(); | |
119 notification_bitmap->height = sk_bitmap.height(); | |
120 int pixel_count = sk_bitmap.width() * sk_bitmap.height(); | |
121 const int BYTES_PER_PIXEL = 4; | |
122 | |
123 uint32_t* bitmap_pixels = sk_bitmap.getAddr32(0, 0); | |
124 const unsigned char* bitmap = | |
125 reinterpret_cast<const unsigned char*>(bitmap_pixels); | |
126 scoped_ptr<unsigned char[]> bitmap_data( | |
dewittj
2014/08/14 20:20:21
nit: name rgba_bitmap_data
liyanhou
2014/08/14 20:29:03
Done.
| |
127 new unsigned char[pixel_count * BYTES_PER_PIXEL]); | |
128 | |
129 gfx::ConvertSkiaToRGBA(bitmap, pixel_count, bitmap_data.get()); | |
130 sk_bitmap.unlockPixels(); | |
131 | |
132 notification_bitmap->data.reset(new std::string( | |
133 bitmap_data.get(), (bitmap_data.get() + pixel_count * BYTES_PER_PIXEL))); | |
134 return; | |
135 } | |
136 | |
137 bool NotificationConversionHelper::NotificationBitmapToGfxImage( | |
138 float max_scale, | |
139 const gfx::Size& target_size_dips, | |
140 extensions::api::notifications::NotificationBitmap* notification_bitmap, | |
141 gfx::Image* return_image) { | |
142 if (!notification_bitmap) | |
143 return false; | |
144 | |
145 const int max_device_pixel_width = target_size_dips.width() * max_scale; | |
146 const int max_device_pixel_height = target_size_dips.height() * max_scale; | |
147 | |
148 const int BYTES_PER_PIXEL = 4; | |
149 | |
150 const int width = notification_bitmap->width; | |
151 const int height = notification_bitmap->height; | |
152 | |
153 if (width < 0 || height < 0 || width > max_device_pixel_width || | |
154 height > max_device_pixel_height) | |
155 return false; | |
156 | |
157 // Ensure we have rgba data. | |
158 std::string* rgba_data = notification_bitmap->data.get(); | |
159 if (!rgba_data) | |
160 return false; | |
161 | |
162 const size_t rgba_data_length = rgba_data->length(); | |
163 const size_t rgba_area = width * height; | |
164 | |
165 if (rgba_data_length != rgba_area * BYTES_PER_PIXEL) | |
166 return false; | |
167 | |
168 SkBitmap bitmap; | |
169 // Allocate the actual backing store with the sanitized dimensions. | |
170 if (!bitmap.allocN32Pixels(width, height)) | |
171 return false; | |
172 | |
173 // Ensure that our bitmap and our data now refer to the same number of pixels. | |
174 if (rgba_data_length != bitmap.getSafeSize()) | |
175 return false; | |
176 | |
177 uint32_t* pixels = bitmap.getAddr32(0, 0); | |
178 const char* c_rgba_data = rgba_data->data(); | |
179 | |
180 for (size_t t = 0; t < rgba_area; ++t) { | |
181 // |c_rgba_data| is RGBA, pixels is ARGB. | |
182 size_t rgba_index = t * BYTES_PER_PIXEL; | |
183 pixels[t] = | |
184 SkPreMultiplyColor(((c_rgba_data[rgba_index + 3] & 0xFF) << 24) | | |
185 ((c_rgba_data[rgba_index + 0] & 0xFF) << 16) | | |
186 ((c_rgba_data[rgba_index + 1] & 0xFF) << 8) | | |
187 ((c_rgba_data[rgba_index + 2] & 0xFF) << 0)); | |
188 } | |
189 | |
190 // TODO(dewittj): Handle HiDPI images with more than one scale factor | |
191 // representation. | |
192 gfx::ImageSkia skia(gfx::ImageSkiaRep(bitmap, 1.0f)); | |
193 *return_image = gfx::Image(skia); | |
194 return true; | |
195 } | |
196 | |
197 std::string NotificationConversionHelper::MapTypeToString( | |
198 message_center::NotificationType type) { | |
199 switch (type) { | |
200 case message_center::NOTIFICATION_TYPE_BASE_FORMAT: | |
201 return "basic"; | |
202 case message_center::NOTIFICATION_TYPE_IMAGE: | |
203 return "image"; | |
204 case message_center::NOTIFICATION_TYPE_MULTIPLE: | |
205 return "list"; | |
206 case message_center::NOTIFICATION_TYPE_PROGRESS: | |
207 return "progress"; | |
208 default: | |
209 NOTREACHED(); | |
210 return ""; | |
211 } | |
212 } | |
OLD | NEW |