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