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 "extensions/renderer/set_icon_natives.h" 6 7 #include <limits> 8 9 #include "base/memory/scoped_ptr.h" 10 #include "content/public/common/common_param_traits.h" 11 #include "extensions/renderer/request_sender.h" 12 #include "extensions/renderer/script_context.h" 13 #include "ipc/ipc_message_utils.h" 14 #include "third_party/skia/include/core/SkBitmap.h" 15 16 namespace { 17 18 const char* kImageSizeKeys[] = {"19", "38"}; 19 const char kInvalidDimensions[] = "ImageData has invalid dimensions."; 20 const char kInvalidData[] = "ImageData data length does not match dimensions."; 21 const char kNoMemory[] = "Chrome was unable to initialize icon."; 22 23 } // namespace 24 25 namespace extensions { 26 27 SetIconNatives::SetIconNatives(RequestSender* request_sender, 28 ScriptContext* context) 29 : ObjectBackedNativeHandler(context), request_sender_(request_sender) { 30 RouteFunction( 31 "SetIconCommon", 32 base::Bind(&SetIconNatives::SetIconCommon, base::Unretained(this))); 33 } 34 35 bool SetIconNatives::ConvertImageDataToBitmapValue( 36 const v8::Local<v8::Object> image_data, 37 base::Value** bitmap_value) { 38 v8::Isolate* isolate = context()->v8_context()->GetIsolate(); 39 v8::Local<v8::Object> data = 40 image_data->Get(v8::String::NewFromUtf8(isolate, "data"))->ToObject(); 41 int width = 42 image_data->Get(v8::String::NewFromUtf8(isolate, "width"))->Int32Value(); 43 int height = 44 image_data->Get(v8::String::NewFromUtf8(isolate, "height"))->Int32Value(); 45 46 if (width <= 0 || height <= 0) { 47 isolate->ThrowException(v8::Exception::Error( 48 v8::String::NewFromUtf8(isolate, kInvalidDimensions))); 49 return false; 50 } 51 52 // We need to be able to safely check |data_length| == 4 * width * height 53 // without overflowing below. 54 int max_width = (std::numeric_limits<int>::max() / 4) / height; 55 if (width > max_width) { 56 isolate->ThrowException(v8::Exception::Error( 57 v8::String::NewFromUtf8(isolate, kInvalidDimensions))); 58 return false; 59 } 60 61 int data_length = 62 data->Get(v8::String::NewFromUtf8(isolate, "length"))->Int32Value(); 63 if (data_length != 4 * width * height) { 64 isolate->ThrowException( 65 v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidData))); 66 return false; 67 } 68 69 SkBitmap bitmap; 70 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); 71 if (!bitmap.allocPixels()) { 72 isolate->ThrowException( 73 v8::Exception::Error(v8::String::NewFromUtf8(isolate, kNoMemory))); 74 return false; 75 } 76 bitmap.eraseARGB(0, 0, 0, 0); 77 78 uint32_t* pixels = bitmap.getAddr32(0, 0); 79 for (int t = 0; t < width * height; t++) { 80 // |data| is RGBA, pixels is ARGB. 81 pixels[t] = SkPreMultiplyColor( 82 ((data->Get(v8::Integer::New(isolate, 4 * t + 3))->Int32Value() & 0xFF) 83 << 24) | 84 ((data->Get(v8::Integer::New(isolate, 4 * t + 0))->Int32Value() & 0xFF) 85 << 16) | 86 ((data->Get(v8::Integer::New(isolate, 4 * t + 1))->Int32Value() & 0xFF) 87 << 8) | 88 ((data->Get(v8::Integer::New(isolate, 4 * t + 2))->Int32Value() & 0xFF) 89 << 0)); 90 } 91 92 // Construct the Value object. 93 IPC::Message bitmap_pickle; 94 IPC::WriteParam(&bitmap_pickle, bitmap); 95 *bitmap_value = base::BinaryValue::CreateWithCopiedBuffer( 96 static_cast<const char*>(bitmap_pickle.data()), bitmap_pickle.size()); 97 98 return true; 99 } 100 101 bool SetIconNatives::ConvertImageDataSetToBitmapValueSet( 102 const v8::FunctionCallbackInfo<v8::Value>& args, 103 base::DictionaryValue* bitmap_set_value) { 104 v8::Local<v8::Object> extension_args = args[1]->ToObject(); 105 v8::Local<v8::Object> details = 106 extension_args->Get(v8::String::NewFromUtf8(args.GetIsolate(), "0")) 107 ->ToObject(); 108 v8::Local<v8::Object> image_data_set = 109 details->Get(v8::String::NewFromUtf8(args.GetIsolate(), "imageData")) 110 ->ToObject(); 111 112 DCHECK(bitmap_set_value); 113 for (size_t i = 0; i < arraysize(kImageSizeKeys); i++) { 114 if (!image_data_set->Has( 115 v8::String::NewFromUtf8(args.GetIsolate(), kImageSizeKeys[i]))) 116 continue; 117 v8::Local<v8::Object> image_data = 118 image_data_set->Get(v8::String::NewFromUtf8(args.GetIsolate(), 119 kImageSizeKeys[i])) 120 ->ToObject(); 121 base::Value* image_data_bitmap = NULL; 122 if (!ConvertImageDataToBitmapValue(image_data, &image_data_bitmap)) 123 return false; 124 bitmap_set_value->Set(kImageSizeKeys[i], image_data_bitmap); 125 } 126 return true; 127 } 128 129 void SetIconNatives::SetIconCommon( 130 const v8::FunctionCallbackInfo<v8::Value>& args) { 131 scoped_ptr<base::DictionaryValue> bitmap_set_value( 132 new base::DictionaryValue()); 133 if (!ConvertImageDataSetToBitmapValueSet(args, bitmap_set_value.get())) 134 return; 135 136 v8::Local<v8::Object> extension_args = args[1]->ToObject(); 137 v8::Local<v8::Object> details = 138 extension_args->Get(v8::String::NewFromUtf8(args.GetIsolate(), "0")) 139 ->ToObject(); 140 141 base::DictionaryValue* dict = new base::DictionaryValue(); 142 dict->Set("imageData", bitmap_set_value.release()); 143 144 if (details->Has(v8::String::NewFromUtf8(args.GetIsolate(), "tabId"))) { 145 dict->SetInteger( 146 "tabId", 147 details->Get(v8::String::NewFromUtf8(args.GetIsolate(), "tabId")) 148 ->Int32Value()); 149 } 150 151 base::ListValue list_value; 152 list_value.Append(dict); 153 154 std::string name = *v8::String::Utf8Value(args[0]); 155 int request_id = args[2]->Int32Value(); 156 bool has_callback = args[3]->BooleanValue(); 157 bool for_io_thread = args[4]->BooleanValue(); 158 159 request_sender_->StartRequest( 160 context(), name, request_id, has_callback, for_io_thread, &list_value); 161 } 162 163 } // namespace extensions 164