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 unsigned char* bitmap_data(new unsigned char[pixel_count * BYTES_PER_PIXEL]); |
| 127 |
| 128 gfx::ConvertSkiaToRGBA(bitmap, pixel_count, bitmap_data); |
| 129 sk_bitmap.unlockPixels(); |
| 130 |
| 131 notification_bitmap->data.reset(new std::string( |
| 132 bitmap_data, (bitmap_data + pixel_count * BYTES_PER_PIXEL))); |
| 133 return; |
| 134 } |
| 135 |
| 136 bool NotificationConversionHelper::NotificationBitmapToGfxImage( |
| 137 float max_scale, |
| 138 const gfx::Size& target_size_dips, |
| 139 extensions::api::notifications::NotificationBitmap* notification_bitmap, |
| 140 gfx::Image* return_image) { |
| 141 if (!notification_bitmap) |
| 142 return false; |
| 143 |
| 144 const int max_device_pixel_width = target_size_dips.width() * max_scale; |
| 145 const int max_device_pixel_height = target_size_dips.height() * max_scale; |
| 146 |
| 147 const int BYTES_PER_PIXEL = 4; |
| 148 |
| 149 const int width = notification_bitmap->width; |
| 150 const int height = notification_bitmap->height; |
| 151 |
| 152 if (width < 0 || height < 0 || width > max_device_pixel_width || |
| 153 height > max_device_pixel_height) |
| 154 return false; |
| 155 |
| 156 // Ensure we have rgba data. |
| 157 std::string* rgba_data = notification_bitmap->data.get(); |
| 158 if (!rgba_data) |
| 159 return false; |
| 160 |
| 161 const size_t rgba_data_length = rgba_data->length(); |
| 162 const size_t rgba_area = width * height; |
| 163 |
| 164 if (rgba_data_length != rgba_area * BYTES_PER_PIXEL) |
| 165 return false; |
| 166 |
| 167 SkBitmap bitmap; |
| 168 // Allocate the actual backing store with the sanitized dimensions. |
| 169 if (!bitmap.allocN32Pixels(width, height)) |
| 170 return false; |
| 171 |
| 172 // Ensure that our bitmap and our data now refer to the same number of pixels. |
| 173 if (rgba_data_length != bitmap.getSafeSize()) |
| 174 return false; |
| 175 |
| 176 uint32_t* pixels = bitmap.getAddr32(0, 0); |
| 177 const char* c_rgba_data = rgba_data->data(); |
| 178 |
| 179 for (size_t t = 0; t < rgba_area; ++t) { |
| 180 // |c_rgba_data| is RGBA, pixels is ARGB. |
| 181 size_t rgba_index = t * BYTES_PER_PIXEL; |
| 182 pixels[t] = |
| 183 SkPreMultiplyColor(((c_rgba_data[rgba_index + 3] & 0xFF) << 24) | |
| 184 ((c_rgba_data[rgba_index + 0] & 0xFF) << 16) | |
| 185 ((c_rgba_data[rgba_index + 1] & 0xFF) << 8) | |
| 186 ((c_rgba_data[rgba_index + 2] & 0xFF) << 0)); |
| 187 } |
| 188 |
| 189 // TODO(dewittj): Handle HiDPI images with more than one scale factor |
| 190 // representation. |
| 191 gfx::ImageSkia skia(gfx::ImageSkiaRep(bitmap, 1.0f)); |
| 192 *return_image = gfx::Image(skia); |
| 193 return true; |
| 194 } |
| 195 |
| 196 std::string NotificationConversionHelper::MapTypeToString( |
| 197 message_center::NotificationType type) { |
| 198 switch (type) { |
| 199 case message_center::NOTIFICATION_TYPE_BASE_FORMAT: |
| 200 return "basic"; |
| 201 case message_center::NOTIFICATION_TYPE_IMAGE: |
| 202 return "image"; |
| 203 case message_center::NOTIFICATION_TYPE_MULTIPLE: |
| 204 return "list"; |
| 205 case message_center::NOTIFICATION_TYPE_PROGRESS: |
| 206 return "progress"; |
| 207 default: |
| 208 NOTREACHED(); |
| 209 return ""; |
| 210 } |
| 211 } |
OLD | NEW |