Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(129)

Side by Side Diff: chrome/browser/extensions/api/notifications/notifications_api.cc

Issue 354733002: Notifications API support for images with multiple scale factors. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Updates custom bindings tests. Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | chrome/common/extensions/api/notifications.idl » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "chrome/browser/extensions/api/notifications/notifications_api.h" 5 #include "chrome/browser/extensions/api/notifications/notifications_api.h"
6 6
7 #include "base/callback.h" 7 #include "base/callback.h"
8 #include "base/guid.h" 8 #include "base/guid.h"
9 #include "base/rand_util.h" 9 #include "base/rand_util.h"
10 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/string_number_conversions.h"
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 "Unable to successfully use the provided image."; 46 "Unable to successfully use the provided image.";
47 const char kUnexpectedProgressValueForNonProgressType[] = 47 const char kUnexpectedProgressValueForNonProgressType[] =
48 "The progress value should not be specified for non-progress notification"; 48 "The progress value should not be specified for non-progress notification";
49 const char kInvalidProgressValue[] = 49 const char kInvalidProgressValue[] =
50 "The progress value should range from 0 to 100"; 50 "The progress value should range from 0 to 100";
51 const char kExtraListItemsProvided[] = 51 const char kExtraListItemsProvided[] =
52 "List items provided for notification type != list"; 52 "List items provided for notification type != list";
53 const char kExtraImageProvided[] = 53 const char kExtraImageProvided[] =
54 "Image resource provided for notification type != image"; 54 "Image resource provided for notification type != image";
55 55
56 // Converts an object with width, height, and data in RGBA format into an 56 typedef std::vector<linked_ptr<notifications::ImageRepresentation> >
57 // gfx::Image (in ARGB format). 57 ImageRepresentationList;
58 bool NotificationBitmapToGfxImage( 58
59 float max_scale, 59 bool ImageRepresentationToImageSkiaRep(float max_scale,
60 const gfx::Size& target_size_dips, 60 const gfx::Size& target_size_dips,
61 api::notifications::NotificationBitmap* notification_bitmap, 61 notifications::BitmapData* bitmap_data,
62 gfx::Image* return_image) { 62 float configured_scale,
63 if (!notification_bitmap) 63 gfx::ImageSkiaRep* return_rep) {
64 if (!bitmap_data || !return_rep) {
65 LOG(WARNING) << "Bitmap data: " << bitmap_data;
66 LOG(WARNING) << "return_rep: " << return_rep;
67
64 return false; 68 return false;
69 }
65 70
66 const int max_device_pixel_width = target_size_dips.width() * max_scale; 71 const int max_device_pixel_width = target_size_dips.width() * max_scale;
67 const int max_device_pixel_height = target_size_dips.height() * max_scale; 72 const int max_device_pixel_height = target_size_dips.height() * max_scale;
68 73
69 const int BYTES_PER_PIXEL = 4; 74 const int BYTES_PER_PIXEL = 4;
70 75
71 const int width = notification_bitmap->width; 76 const int width = bitmap_data->width;
72 const int height = notification_bitmap->height; 77 const int height = bitmap_data->height;
73 78
74 if (width < 0 || height < 0 || width > max_device_pixel_width || 79 if (configured_scale < 1.0f || width < 0 || height < 0 ||
75 height > max_device_pixel_height) 80 width > max_device_pixel_width || height > max_device_pixel_height) {
81 LOG(WARNING) << "Configured scale: " << configured_scale;
82 LOG(WARNING) << "width: " << width;
83 LOG(WARNING) << "height: " << height;
84 return false;
85 }
86
87 // Ensure we have rgba data.
88 if (!bitmap_data->data.length())
76 return false; 89 return false;
77 90
78 // Ensure we have rgba data. 91 const size_t rgba_data_length = bitmap_data->data.length();
79 std::string* rgba_data = notification_bitmap->data.get();
80 if (!rgba_data)
81 return false;
82
83 const size_t rgba_data_length = rgba_data->length();
84 const size_t rgba_area = width * height; 92 const size_t rgba_area = width * height;
85 93
86 if (rgba_data_length != rgba_area * BYTES_PER_PIXEL) 94 if (rgba_data_length != rgba_area * BYTES_PER_PIXEL)
87 return false; 95 return false;
88 96
89 // Now configure the bitmap with the sanitized dimensions. 97 // Now configure the bitmap with the sanitized dimensions.
90 SkBitmap bitmap; 98 SkBitmap bitmap;
91 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); 99 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
92 100
93 // Allocate the actual backing store. 101 // Allocate the actual backing store.
94 if (!bitmap.allocPixels()) 102 if (!bitmap.allocPixels())
95 return false; 103 return false;
96 104
97 // Ensure that our bitmap and our data now refer to the same number of pixels. 105 // Ensure that our bitmap and our data now refer to the same number of pixels.
98 if (rgba_data_length != bitmap.getSafeSize()) 106 if (rgba_data_length != bitmap.getSafeSize())
99 return false; 107 return false;
100 108
101 uint32_t* pixels = bitmap.getAddr32(0, 0); 109 uint32_t* pixels = bitmap.getAddr32(0, 0);
102 const char* c_rgba_data = rgba_data->data(); 110 const char* c_rgba_data = bitmap_data->data.data();
103 111
104 for (size_t t = 0; t < rgba_area; ++t) { 112 for (size_t t = 0; t < rgba_area; ++t) {
105 // |c_rgba_data| is RGBA, pixels is ARGB. 113 // |c_rgba_data| is RGBA, pixels is ARGB.
106 size_t rgba_index = t * BYTES_PER_PIXEL; 114 size_t rgba_index = t * BYTES_PER_PIXEL;
107 pixels[t] = SkPreMultiplyColor( 115 pixels[t] = SkPreMultiplyColor(
108 ((c_rgba_data[rgba_index + 3] & 0xFF) << 24) | 116 ((c_rgba_data[rgba_index + 3] & 0xFF) << 24) |
109 ((c_rgba_data[rgba_index + 0] & 0xFF) << 16) | 117 ((c_rgba_data[rgba_index + 0] & 0xFF) << 16) |
110 ((c_rgba_data[rgba_index + 1] & 0xFF) << 8) | 118 ((c_rgba_data[rgba_index + 1] & 0xFF) << 8) |
111 ((c_rgba_data[rgba_index + 2] & 0xFF) << 0)); 119 ((c_rgba_data[rgba_index + 2] & 0xFF) << 0));
112 } 120 }
113 121
114 // TODO(dewittj): Handle HiDPI images with more than one scale factor 122 // TODO(dewittj): Handle HiDPI images with more than one scale factor
115 // representation. 123 // representation.
116 gfx::ImageSkia skia(gfx::ImageSkiaRep(bitmap, 1.0f)); 124 *return_rep = gfx::ImageSkiaRep(bitmap, configured_scale);
117 *return_image = gfx::Image(skia);
118 return true; 125 return true;
119 } 126 }
120 127
128 // Converts an object with width, height, and data in RGBA format into an
129 // gfx::Image (in ARGB format).
130 bool ImageRepresentationListToGfxImage(float max_scale,
131 const gfx::Size& target_size_dips,
132 ImageRepresentationList* bitmap_list,
133 gfx::Image* return_image) {
134 if (!bitmap_list || bitmap_list->size() == 0)
135 return false;
136
137 gfx::ImageSkia out;
138 ImageRepresentationList::iterator iter = bitmap_list->begin();
139 while (iter != bitmap_list->end()) {
140 notifications::ImageRepresentation* rep = (*iter).get();
141 if (rep->density > max_scale)
142 return false;
143
144 notifications::BitmapData* bitmap = rep->src.as_bitmap_data.get();
145 gfx::ImageSkiaRep skia_rep;
146 if (!ImageRepresentationToImageSkiaRep(
147 max_scale, target_size_dips, bitmap, rep->density, &skia_rep))
148 return false;
149
150 out.AddRepresentation(skia_rep);
151
152 ++iter;
153 }
154 *return_image = gfx::Image(out);
155 return true;
156 }
157
121 // Given an extension id and another id, returns an id that is unique 158 // Given an extension id and another id, returns an id that is unique
122 // relative to other extensions. 159 // relative to other extensions.
123 std::string CreateScopedIdentifier(const std::string& extension_id, 160 std::string CreateScopedIdentifier(const std::string& extension_id,
124 const std::string& id) { 161 const std::string& id) {
125 return extension_id + "-" + id; 162 return extension_id + "-" + id;
126 } 163 }
127 164
128 // Removes the unique internal identifier to send the ID as the 165 // Removes the unique internal identifier to send the ID as the
129 // extension expects it. 166 // extension expects it.
130 std::string StripScopeFromIdentifier(const std::string& extension_id, 167 std::string StripScopeFromIdentifier(const std::string& extension_id,
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 NotificationsApiFunction::~NotificationsApiFunction() { 290 NotificationsApiFunction::~NotificationsApiFunction() {
254 } 291 }
255 292
256 bool NotificationsApiFunction::CreateNotification( 293 bool NotificationsApiFunction::CreateNotification(
257 const std::string& id, 294 const std::string& id,
258 api::notifications::NotificationOptions* options) { 295 api::notifications::NotificationOptions* options) {
259 // First, make sure the required fields exist: type, title, message, icon. 296 // First, make sure the required fields exist: type, title, message, icon.
260 // These fields are defined as optional in IDL such that they can be used as 297 // These fields are defined as optional in IDL such that they can be used as
261 // optional for notification updates. But for notification creations, they 298 // optional for notification updates. But for notification creations, they
262 // should be present. 299 // should be present.
263 if (options->type == api::notifications::TEMPLATE_TYPE_NONE || 300 if (options->icon_reps == NULL || options->icon_reps->size() < 1) {
264 !options->icon_url || !options->title || !options->message) {
265 SetError(kMissingRequiredPropertiesForCreateNotification); 301 SetError(kMissingRequiredPropertiesForCreateNotification);
266 return false; 302 return false;
267 } 303 }
304 if (options->type == api::notifications::TEMPLATE_TYPE_NONE ||
305 !options->title || !options->message) {
306 SetError(kMissingRequiredPropertiesForCreateNotification);
307 return false;
308 }
268 309
269 NotificationBitmapSizes bitmap_sizes = GetNotificationBitmapSizes(); 310 NotificationBitmapSizes bitmap_sizes = GetNotificationBitmapSizes();
270 311
271 float image_scale = 312 float image_scale =
272 ui::GetScaleForScaleFactor(ui::GetSupportedScaleFactors().back()); 313 ui::GetScaleForScaleFactor(ui::GetSupportedScaleFactors().back());
273 314
274 // Extract required fields: type, title, message, and icon. 315 // Extract required fields: type, title, message, and icon.
275 message_center::NotificationType type = 316 message_center::NotificationType type =
276 MapApiTemplateTypeToType(options->type); 317 MapApiTemplateTypeToType(options->type);
277 const base::string16 title(base::UTF8ToUTF16(*options->title)); 318 const base::string16 title(base::UTF8ToUTF16(*options->title));
278 const base::string16 message(base::UTF8ToUTF16(*options->message)); 319 const base::string16 message(base::UTF8ToUTF16(*options->message));
279 gfx::Image icon; 320 gfx::Image icon;
280 321
281 if (!NotificationBitmapToGfxImage(image_scale, 322 if (!ImageRepresentationListToGfxImage(image_scale,
282 bitmap_sizes.icon_size, 323 bitmap_sizes.icon_size,
283 options->icon_bitmap.get(), 324 options->icon_reps.get(),
284 &icon)) { 325 &icon)) {
285 SetError(kUnableToDecodeIconError); 326 SetError(kUnableToDecodeIconError);
286 return false; 327 return false;
287 } 328 }
288 329
289 // Then, handle any optional data that's been provided. 330 // Then, handle any optional data that's been provided.
290 message_center::RichNotificationData optional_fields; 331 message_center::RichNotificationData optional_fields;
291 if (options->priority.get()) 332 if (options->priority.get())
292 optional_fields.priority = *options->priority; 333 optional_fields.priority = *options->priority;
293 334
294 if (options->event_time.get()) 335 if (options->event_time.get())
295 optional_fields.timestamp = base::Time::FromJsTime(*options->event_time); 336 optional_fields.timestamp = base::Time::FromJsTime(*options->event_time);
296 337
297 if (options->buttons.get()) { 338 if (options->buttons.get()) {
298 // Currently we allow up to 2 buttons. 339 // Currently we allow up to 2 buttons.
299 size_t number_of_buttons = options->buttons->size(); 340 size_t number_of_buttons = options->buttons->size();
300 number_of_buttons = number_of_buttons > 2 ? 2 : number_of_buttons; 341 number_of_buttons = number_of_buttons > 2 ? 2 : number_of_buttons;
301 342
302 for (size_t i = 0; i < number_of_buttons; i++) { 343 for (size_t i = 0; i < number_of_buttons; i++) {
303 message_center::ButtonInfo info( 344 message_center::ButtonInfo info(
304 base::UTF8ToUTF16((*options->buttons)[i]->title)); 345 base::UTF8ToUTF16((*options->buttons)[i]->title));
305 NotificationBitmapToGfxImage(image_scale, 346 ImageRepresentationListToGfxImage(image_scale,
306 bitmap_sizes.button_icon_size, 347 bitmap_sizes.button_icon_size,
307 (*options->buttons)[i]->icon_bitmap.get(), 348 (*options->buttons)[i]->icon_reps.get(),
308 &info.icon); 349 &info.icon);
309 optional_fields.buttons.push_back(info); 350 optional_fields.buttons.push_back(info);
310 } 351 }
311 } 352 }
312 353
313 if (options->context_message) { 354 if (options->context_message) {
314 optional_fields.context_message = 355 optional_fields.context_message =
315 base::UTF8ToUTF16(*options->context_message); 356 base::UTF8ToUTF16(*options->context_message);
316 } 357 }
317 358
318 bool has_image = NotificationBitmapToGfxImage(image_scale, 359 bool has_image = ImageRepresentationListToGfxImage(image_scale,
319 bitmap_sizes.image_size, 360 bitmap_sizes.image_size,
320 options->image_bitmap.get(), 361 options->image_reps.get(),
321 &optional_fields.image); 362 &optional_fields.image);
322 // We should have an image if and only if the type is an image type. 363 // We should have an image if and only if the type is an image type.
323 if (has_image != (type == message_center::NOTIFICATION_TYPE_IMAGE)) { 364 if (has_image != (type == message_center::NOTIFICATION_TYPE_IMAGE)) {
324 SetError(kExtraImageProvided); 365 SetError(kExtraImageProvided);
325 return false; 366 return false;
326 } 367 }
327 368
328 // We should have list items if and only if the type is a multiple type. 369 // We should have list items if and only if the type is a multiple type.
329 bool has_list_items = options->items.get() && options->items->size() > 0; 370 bool has_list_items = options->items.get() && options->items->size() > 0;
330 if (has_list_items != (type == message_center::NOTIFICATION_TYPE_MULTIPLE)) { 371 if (has_list_items != (type == message_center::NOTIFICATION_TYPE_MULTIPLE)) {
331 SetError(kExtraListItemsProvided); 372 SetError(kExtraListItemsProvided);
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 432
392 // Update optional fields if provided. 433 // Update optional fields if provided.
393 if (options->type != api::notifications::TEMPLATE_TYPE_NONE) 434 if (options->type != api::notifications::TEMPLATE_TYPE_NONE)
394 notification->set_type(MapApiTemplateTypeToType(options->type)); 435 notification->set_type(MapApiTemplateTypeToType(options->type));
395 if (options->title) 436 if (options->title)
396 notification->set_title(base::UTF8ToUTF16(*options->title)); 437 notification->set_title(base::UTF8ToUTF16(*options->title));
397 if (options->message) 438 if (options->message)
398 notification->set_message(base::UTF8ToUTF16(*options->message)); 439 notification->set_message(base::UTF8ToUTF16(*options->message));
399 440
400 // TODO(dewittj): Return error if this fails. 441 // TODO(dewittj): Return error if this fails.
401 if (options->icon_bitmap) { 442 if (options->icon_reps) {
402 gfx::Image icon; 443 gfx::Image icon;
403 NotificationBitmapToGfxImage( 444 ImageRepresentationListToGfxImage(
404 image_scale, bitmap_sizes.icon_size, options->icon_bitmap.get(), &icon); 445 image_scale, bitmap_sizes.icon_size, options->icon_reps.get(), &icon);
405 notification->set_icon(icon); 446 notification->set_icon(icon);
406 } 447 }
407 448
408 if (options->priority) 449 if (options->priority)
409 notification->set_priority(*options->priority); 450 notification->set_priority(*options->priority);
410 451
411 if (options->event_time) 452 if (options->event_time)
412 notification->set_timestamp(base::Time::FromJsTime(*options->event_time)); 453 notification->set_timestamp(base::Time::FromJsTime(*options->event_time));
413 454
414 if (options->buttons) { 455 if (options->buttons) {
415 // Currently we allow up to 2 buttons. 456 // Currently we allow up to 2 buttons.
416 size_t number_of_buttons = options->buttons->size(); 457 size_t number_of_buttons = options->buttons->size();
417 number_of_buttons = number_of_buttons > 2 ? 2 : number_of_buttons; 458 number_of_buttons = number_of_buttons > 2 ? 2 : number_of_buttons;
418 459
419 std::vector<message_center::ButtonInfo> buttons; 460 std::vector<message_center::ButtonInfo> buttons;
420 for (size_t i = 0; i < number_of_buttons; i++) { 461 for (size_t i = 0; i < number_of_buttons; i++) {
421 message_center::ButtonInfo button( 462 message_center::ButtonInfo button(
422 base::UTF8ToUTF16((*options->buttons)[i]->title)); 463 base::UTF8ToUTF16((*options->buttons)[i]->title));
423 NotificationBitmapToGfxImage(image_scale, 464 ImageRepresentationListToGfxImage(image_scale,
424 bitmap_sizes.button_icon_size, 465 bitmap_sizes.button_icon_size,
425 (*options->buttons)[i]->icon_bitmap.get(), 466 (*options->buttons)[i]->icon_reps.get(),
426 &button.icon); 467 &button.icon);
427 buttons.push_back(button); 468 buttons.push_back(button);
428 } 469 }
429 notification->set_buttons(buttons); 470 notification->set_buttons(buttons);
430 } 471 }
431 472
432 if (options->context_message) { 473 if (options->context_message) {
433 notification->set_context_message( 474 notification->set_context_message(
434 base::UTF8ToUTF16(*options->context_message)); 475 base::UTF8ToUTF16(*options->context_message));
435 } 476 }
436 477
437 gfx::Image image; 478 gfx::Image image;
438 bool has_image = NotificationBitmapToGfxImage(image_scale, 479 bool has_image = ImageRepresentationListToGfxImage(
439 bitmap_sizes.image_size, 480 image_scale, bitmap_sizes.image_size, options->image_reps.get(), &image);
440 options->image_bitmap.get(),
441 &image);
442 if (has_image) { 481 if (has_image) {
443 // We should have an image if and only if the type is an image type. 482 // We should have an image if and only if the type is an image type.
444 if (notification->type() != message_center::NOTIFICATION_TYPE_IMAGE) { 483 if (notification->type() != message_center::NOTIFICATION_TYPE_IMAGE) {
445 SetError(kExtraImageProvided); 484 SetError(kExtraImageProvided);
446 return false; 485 return false;
447 } 486 }
448 notification->set_image(image); 487 notification->set_image(image);
449 } 488 }
450 489
451 if (options->progress) { 490 if (options->progress) {
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
669 ? api::notifications::PERMISSION_LEVEL_GRANTED 708 ? api::notifications::PERMISSION_LEVEL_GRANTED
670 : api::notifications::PERMISSION_LEVEL_DENIED; 709 : api::notifications::PERMISSION_LEVEL_DENIED;
671 710
672 SetResult(new base::StringValue(api::notifications::ToString(result))); 711 SetResult(new base::StringValue(api::notifications::ToString(result)));
673 SendResponse(true); 712 SendResponse(true);
674 713
675 return true; 714 return true;
676 } 715 }
677 716
678 } // namespace extensions 717 } // namespace extensions
OLDNEW
« no previous file with comments | « no previous file | chrome/common/extensions/api/notifications.idl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698