Home | History | Annotate | Download | only in app_list
      1 // Copyright 2013 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/ui/app_list/fast_show_pickler.h"
      6 
      7 #include "third_party/skia/include/core/SkBitmap.h"
      8 #include "ui/app_list/app_list_item.h"
      9 #include "ui/gfx/image/image_skia_rep.h"
     10 
     11 namespace {
     12 
     13 using app_list::AppListItem;
     14 using app_list::AppListModel;
     15 
     16 // These have the same meaning as SkBitmap::Config. Reproduced here to insure
     17 // against their value changing in Skia. If the order of these changes kVersion
     18 // should be incremented.
     19 enum ImageFormat {
     20   NONE,
     21   A8,
     22   INDEX_8,
     23   RGB_565,
     24   ARGB_4444,
     25   ARGB_8888,
     26 };
     27 
     28 bool FormatToConfig(ImageFormat format, SkBitmap::Config* out) {
     29   switch (format) {
     30     case NONE:
     31       *out = SkBitmap::kNo_Config;
     32       break;
     33     case A8:
     34       *out = SkBitmap::kA8_Config;
     35       break;
     36     case INDEX_8:
     37       *out = SkBitmap::kIndex8_Config;
     38       break;
     39     case RGB_565:
     40       *out = SkBitmap::kRGB_565_Config;
     41       break;
     42     case ARGB_4444:
     43       *out = SkBitmap::kARGB_4444_Config;
     44       break;
     45     case ARGB_8888:
     46       *out = SkBitmap::kARGB_8888_Config;
     47       break;
     48     default: return false;
     49   }
     50   return true;
     51 }
     52 
     53 bool ConfigToFormat(SkBitmap::Config config, ImageFormat* out) {
     54   switch (config) {
     55     case SkBitmap::kNo_Config:
     56       *out = NONE;
     57       break;
     58     case SkBitmap::kA8_Config:
     59       *out = A8;
     60       break;
     61     case SkBitmap::kIndex8_Config:
     62       *out = INDEX_8;
     63       break;
     64     case SkBitmap::kRGB_565_Config:
     65       *out = RGB_565;
     66       break;
     67     case SkBitmap::kARGB_4444_Config:
     68       *out = ARGB_4444;
     69       break;
     70     case SkBitmap::kARGB_8888_Config:
     71       *out = ARGB_8888;
     72       break;
     73     default: return false;
     74   }
     75   return true;
     76 }
     77 
     78 bool PickleImage(Pickle* pickle, const gfx::ImageSkia& image) {
     79   std::vector<gfx::ImageSkiaRep> reps(image.image_reps());
     80   pickle->WriteInt(static_cast<int>(reps.size()));
     81   for (std::vector<gfx::ImageSkiaRep>::const_iterator it = reps.begin();
     82        it != reps.end(); ++it) {
     83     pickle->WriteFloat(it->scale());
     84     pickle->WriteInt(it->pixel_width());
     85     pickle->WriteInt(it->pixel_height());
     86     ImageFormat format = NONE;
     87     if (!ConfigToFormat(it->sk_bitmap().config(), &format))
     88       return false;
     89     pickle->WriteInt(static_cast<int>(format));
     90     int size = static_cast<int>(it->sk_bitmap().getSafeSize());
     91     pickle->WriteInt(size);
     92     SkBitmap bitmap = it->sk_bitmap();
     93     SkAutoLockPixels lock(bitmap);
     94     pickle->WriteBytes(bitmap.getPixels(), size);
     95   }
     96   return true;
     97 }
     98 
     99 bool UnpickleImage(PickleIterator* it, gfx::ImageSkia* out) {
    100   int rep_count = 0;
    101   if (!it->ReadInt(&rep_count))
    102     return false;
    103 
    104   gfx::ImageSkia result;
    105   for (int i = 0; i < rep_count; ++i) {
    106     float scale = 0.0f;
    107     if (!it->ReadFloat(&scale))
    108       return false;
    109 
    110     int width = 0;
    111     if (!it->ReadInt(&width))
    112       return false;
    113 
    114     int height = 0;
    115     if (!it->ReadInt(&height))
    116       return false;
    117 
    118     int format_int = 0;
    119     if (!it->ReadInt(&format_int))
    120       return false;
    121     ImageFormat format = static_cast<ImageFormat>(format_int);
    122     SkBitmap::Config config = SkBitmap::kNo_Config;
    123     if (!FormatToConfig(format, &config))
    124       return false;
    125 
    126     int size = 0;
    127     if (!it->ReadInt(&size))
    128       return false;
    129 
    130     const char* pixels = NULL;
    131     if (!it->ReadBytes(&pixels, size))
    132       return false;
    133 
    134     SkBitmap bitmap;
    135     bitmap.setConfig(static_cast<SkBitmap::Config>(config), width, height);
    136     if (!bitmap.allocPixels())
    137       return false;
    138     {
    139       SkAutoLockPixels lock(bitmap);
    140       memcpy(bitmap.getPixels(), pixels, bitmap.getSize());
    141     }
    142     result.AddRepresentation(gfx::ImageSkiaRep(bitmap, scale));
    143   }
    144 
    145   *out = result;
    146   return true;
    147 }
    148 
    149 }  // namespace
    150 
    151 scoped_ptr<AppListItem> FastShowPickler::UnpickleAppListItem(
    152     PickleIterator* it) {
    153   std::string id;
    154   if (!it->ReadString(&id))
    155     return scoped_ptr<AppListItem>();
    156   scoped_ptr<AppListItem> result(new AppListItem(id));
    157   std::string name;
    158   if (!it->ReadString(&name))
    159     return scoped_ptr<AppListItem>();
    160   std::string short_name;
    161   if (!it->ReadString(&short_name))
    162     return scoped_ptr<AppListItem>();
    163   result->SetNameAndShortName(name, short_name);
    164   bool has_shadow = false;
    165   if (!it->ReadBool(&has_shadow))
    166     return scoped_ptr<AppListItem>();
    167   gfx::ImageSkia icon;
    168   if (!UnpickleImage(it, &icon))
    169     return scoped_ptr<AppListItem>();
    170   result->SetIcon(icon, has_shadow);
    171   return result.Pass();
    172 }
    173 
    174 bool FastShowPickler::PickleAppListItem(Pickle* pickle, AppListItem* item) {
    175   if (!pickle->WriteString(item->id()))
    176     return false;
    177   if (!pickle->WriteString(item->name()))
    178     return false;
    179   if (!pickle->WriteString(item->short_name()))
    180     return false;
    181   if (!pickle->WriteBool(item->has_shadow()))
    182     return false;
    183   if (!PickleImage(pickle, item->icon()))
    184     return false;
    185   return true;
    186 }
    187 
    188 void FastShowPickler::CopyOverItem(AppListItem* src_item,
    189                                    AppListItem* dest_item) {
    190   dest_item->SetNameAndShortName(src_item->name(), src_item->short_name());
    191   dest_item->SetIcon(src_item->icon(), src_item->has_shadow());
    192   // Do not set folder_id, pass that to AppListModel::AddItemToFolder() instead.
    193 }
    194 
    195 // The version of the pickle format defined here. This needs to be incremented
    196 // whenever this format is changed so new clients can invalidate old versions.
    197 const int FastShowPickler::kVersion = 3;
    198 
    199 scoped_ptr<Pickle> FastShowPickler::PickleAppListModelForFastShow(
    200     AppListModel* model) {
    201   scoped_ptr<Pickle> result(new Pickle);
    202   if (!result->WriteInt(kVersion))
    203     return scoped_ptr<Pickle>();
    204   if (!result->WriteInt((int)model->top_level_item_list()->item_count()))
    205     return scoped_ptr<Pickle>();
    206   for (size_t i = 0; i < model->top_level_item_list()->item_count(); ++i) {
    207     if (!PickleAppListItem(result.get(),
    208                            model->top_level_item_list()->item_at(i))) {
    209       return scoped_ptr<Pickle>();
    210     }
    211   }
    212   return result.Pass();
    213 }
    214 
    215 void FastShowPickler::CopyOver(AppListModel* src, AppListModel* dest) {
    216   DCHECK_EQ(0u, dest->top_level_item_list()->item_count());
    217   for (size_t i = 0; i < src->top_level_item_list()->item_count(); i++) {
    218     AppListItem* src_item = src->top_level_item_list()->item_at(i);
    219     scoped_ptr<AppListItem> dest_item(new AppListItem(src_item->id()));
    220     CopyOverItem(src_item, dest_item.get());
    221     dest->AddItemToFolder(dest_item.Pass(), src_item->folder_id());
    222   }
    223 }
    224 
    225 scoped_ptr<AppListModel>
    226 FastShowPickler::UnpickleAppListModelForFastShow(Pickle* pickle) {
    227   PickleIterator it(*pickle);
    228   int read_version = 0;
    229   if (!it.ReadInt(&read_version))
    230     return scoped_ptr<AppListModel>();
    231   if (read_version != kVersion)
    232     return scoped_ptr<AppListModel>();
    233   int app_count = 0;
    234   if (!it.ReadInt(&app_count))
    235     return scoped_ptr<AppListModel>();
    236 
    237   scoped_ptr<AppListModel> model(new AppListModel);
    238   for (int i = 0; i < app_count; ++i) {
    239     scoped_ptr<AppListItem> item(UnpickleAppListItem(&it).Pass());
    240     if (!item)
    241       return scoped_ptr<AppListModel>();
    242     std::string folder_id = item->folder_id();
    243     model->AddItemToFolder(item.Pass(), folder_id);
    244   }
    245 
    246   return model.Pass();
    247 }
    248