Home | History | Annotate | Download | only in renderer
      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/WebKit/public/web/WebArrayBufferConverter.h"
     15 #include "third_party/skia/include/core/SkBitmap.h"
     16 #include "ui/gfx/ipc/gfx_param_traits.h"
     17 
     18 namespace {
     19 
     20 const char* kImageSizeKeys[] = {"19", "38"};
     21 const char kInvalidDimensions[] = "ImageData has invalid dimensions.";
     22 const char kInvalidData[] = "ImageData data length does not match dimensions.";
     23 const char kNoMemory[] = "Chrome was unable to initialize icon.";
     24 
     25 }  // namespace
     26 
     27 namespace extensions {
     28 
     29 SetIconNatives::SetIconNatives(RequestSender* request_sender,
     30                                ScriptContext* context)
     31     : ObjectBackedNativeHandler(context), request_sender_(request_sender) {
     32   RouteFunction(
     33       "SetIconCommon",
     34       base::Bind(&SetIconNatives::SetIconCommon, base::Unretained(this)));
     35 }
     36 
     37 bool SetIconNatives::ConvertImageDataToBitmapValue(
     38     const v8::Local<v8::Object> image_data,
     39     v8::Local<v8::Value>* image_data_bitmap) {
     40   v8::Isolate* isolate = context()->v8_context()->GetIsolate();
     41   v8::Local<v8::Object> data =
     42       image_data->Get(v8::String::NewFromUtf8(isolate, "data"))->ToObject();
     43   int width =
     44       image_data->Get(v8::String::NewFromUtf8(isolate, "width"))->Int32Value();
     45   int height =
     46       image_data->Get(v8::String::NewFromUtf8(isolate, "height"))->Int32Value();
     47 
     48   if (width <= 0 || height <= 0) {
     49     isolate->ThrowException(v8::Exception::Error(
     50         v8::String::NewFromUtf8(isolate, kInvalidDimensions)));
     51     return false;
     52   }
     53 
     54   // We need to be able to safely check |data_length| == 4 * width * height
     55   // without overflowing below.
     56   int max_width = (std::numeric_limits<int>::max() / 4) / height;
     57   if (width > max_width) {
     58     isolate->ThrowException(v8::Exception::Error(
     59         v8::String::NewFromUtf8(isolate, kInvalidDimensions)));
     60     return false;
     61   }
     62 
     63   int data_length =
     64       data->Get(v8::String::NewFromUtf8(isolate, "length"))->Int32Value();
     65   if (data_length != 4 * width * height) {
     66     isolate->ThrowException(
     67         v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidData)));
     68     return false;
     69   }
     70 
     71   SkBitmap bitmap;
     72   if (!bitmap.tryAllocN32Pixels(width, height)) {
     73     isolate->ThrowException(
     74         v8::Exception::Error(v8::String::NewFromUtf8(isolate, kNoMemory)));
     75     return false;
     76   }
     77   bitmap.eraseARGB(0, 0, 0, 0);
     78 
     79   uint32_t* pixels = bitmap.getAddr32(0, 0);
     80   for (int t = 0; t < width * height; t++) {
     81     // |data| is RGBA, pixels is ARGB.
     82     pixels[t] = SkPreMultiplyColor(
     83         ((data->Get(v8::Integer::New(isolate, 4 * t + 3))->Int32Value() & 0xFF)
     84          << 24) |
     85         ((data->Get(v8::Integer::New(isolate, 4 * t + 0))->Int32Value() & 0xFF)
     86          << 16) |
     87         ((data->Get(v8::Integer::New(isolate, 4 * t + 1))->Int32Value() & 0xFF)
     88          << 8) |
     89         ((data->Get(v8::Integer::New(isolate, 4 * t + 2))->Int32Value() & 0xFF)
     90          << 0));
     91   }
     92 
     93   // Construct the Value object.
     94   IPC::Message bitmap_pickle;
     95   IPC::WriteParam(&bitmap_pickle, bitmap);
     96   blink::WebArrayBuffer buffer =
     97       blink::WebArrayBuffer::create(bitmap_pickle.size(), 1);
     98   memcpy(buffer.data(), bitmap_pickle.data(), bitmap_pickle.size());
     99   *image_data_bitmap = blink::WebArrayBufferConverter::toV8Value(
    100       &buffer, context()->v8_context()->Global(), isolate);
    101 
    102   return true;
    103 }
    104 
    105 bool SetIconNatives::ConvertImageDataSetToBitmapValueSet(
    106     v8::Local<v8::Object>& details,
    107     v8::Local<v8::Object>* bitmap_set_value) {
    108   v8::Isolate* isolate = context()->v8_context()->GetIsolate();
    109   v8::Local<v8::Object> image_data_set =
    110       details->Get(v8::String::NewFromUtf8(isolate, "imageData"))->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(isolate, kImageSizeKeys[i])))
    116       continue;
    117     v8::Local<v8::Object> image_data =
    118         image_data_set->Get(v8::String::NewFromUtf8(isolate, kImageSizeKeys[i]))
    119             ->ToObject();
    120     v8::Local<v8::Value> image_data_bitmap;
    121     if (!ConvertImageDataToBitmapValue(image_data, &image_data_bitmap))
    122       return false;
    123     (*bitmap_set_value)->Set(
    124         v8::String::NewFromUtf8(isolate, kImageSizeKeys[i]), image_data_bitmap);
    125   }
    126   return true;
    127 }
    128 
    129 void SetIconNatives::SetIconCommon(
    130     const v8::FunctionCallbackInfo<v8::Value>& args) {
    131   CHECK_EQ(1, args.Length());
    132   CHECK(args[0]->IsObject());
    133   v8::Local<v8::Object> details = args[0]->ToObject();
    134   v8::Local<v8::Object> bitmap_set_value(v8::Object::New(args.GetIsolate()));
    135   if (!ConvertImageDataSetToBitmapValueSet(details, &bitmap_set_value))
    136     return;
    137 
    138   v8::Local<v8::Object> dict(v8::Object::New(args.GetIsolate()));
    139   dict->Set(v8::String::NewFromUtf8(args.GetIsolate(), "imageData"),
    140             bitmap_set_value);
    141   if (details->Has(v8::String::NewFromUtf8(args.GetIsolate(), "tabId"))) {
    142     dict->Set(
    143         v8::String::NewFromUtf8(args.GetIsolate(), "tabId"),
    144         details->Get(v8::String::NewFromUtf8(args.GetIsolate(), "tabId")));
    145   }
    146   args.GetReturnValue().Set(dict);
    147 }
    148 
    149 }  // namespace extensions
    150