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