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 FormatToColorType(ImageFormat format, SkColorType* out) { 29 switch (format) { 30 case NONE: 31 *out = kUnknown_SkColorType; 32 break; 33 case A8: 34 *out = kAlpha_8_SkColorType; 35 break; 36 case INDEX_8: 37 *out = kIndex_8_SkColorType; 38 break; 39 case RGB_565: 40 *out = kRGB_565_SkColorType; 41 break; 42 case ARGB_4444: 43 *out = kARGB_4444_SkColorType; 44 break; 45 case ARGB_8888: 46 *out = kN32_SkColorType; 47 break; 48 default: return false; 49 } 50 return true; 51 } 52 53 bool ColorTypeToFormat(SkColorType colorType, ImageFormat* out) { 54 switch (colorType) { 55 case kUnknown_SkColorType: 56 *out = NONE; 57 break; 58 case kAlpha_8_SkColorType: 59 *out = A8; 60 break; 61 case kIndex_8_SkColorType: 62 *out = INDEX_8; 63 break; 64 case kRGB_565_SkColorType: 65 *out = RGB_565; 66 break; 67 case kARGB_4444_SkColorType: 68 *out = ARGB_4444; 69 break; 70 case kN32_SkColorType: 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 (!ColorTypeToFormat(it->sk_bitmap().colorType(), &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 SkColorType color_type = kUnknown_SkColorType; 123 if (!FormatToColorType(format, &color_type)) 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 if (!bitmap.tryAllocPixels(SkImageInfo::Make( 136 width, height, color_type, kPremul_SkAlphaType))) 137 return false; 138 139 memcpy(bitmap.getPixels(), pixels, bitmap.getSize()); 140 result.AddRepresentation(gfx::ImageSkiaRep(bitmap, scale)); 141 } 142 143 *out = result; 144 return true; 145 } 146 147 } // namespace 148 149 scoped_ptr<AppListItem> FastShowPickler::UnpickleAppListItem( 150 PickleIterator* it) { 151 std::string id; 152 if (!it->ReadString(&id)) 153 return scoped_ptr<AppListItem>(); 154 scoped_ptr<AppListItem> result(new AppListItem(id)); 155 std::string name; 156 if (!it->ReadString(&name)) 157 return scoped_ptr<AppListItem>(); 158 std::string short_name; 159 if (!it->ReadString(&short_name)) 160 return scoped_ptr<AppListItem>(); 161 result->SetNameAndShortName(name, short_name); 162 bool has_shadow = false; 163 if (!it->ReadBool(&has_shadow)) 164 return scoped_ptr<AppListItem>(); 165 gfx::ImageSkia icon; 166 if (!UnpickleImage(it, &icon)) 167 return scoped_ptr<AppListItem>(); 168 result->SetIcon(icon, has_shadow); 169 return result.Pass(); 170 } 171 172 bool FastShowPickler::PickleAppListItem(Pickle* pickle, AppListItem* item) { 173 if (!pickle->WriteString(item->id())) 174 return false; 175 if (!pickle->WriteString(item->name())) 176 return false; 177 if (!pickle->WriteString(item->short_name())) 178 return false; 179 if (!pickle->WriteBool(item->has_shadow())) 180 return false; 181 if (!PickleImage(pickle, item->icon())) 182 return false; 183 return true; 184 } 185 186 void FastShowPickler::CopyOverItem(AppListItem* src_item, 187 AppListItem* dest_item) { 188 dest_item->SetNameAndShortName(src_item->name(), src_item->short_name()); 189 dest_item->SetIcon(src_item->icon(), src_item->has_shadow()); 190 // Do not set folder_id, pass that to AppListModel::AddItemToFolder() instead. 191 } 192 193 // The version of the pickle format defined here. This needs to be incremented 194 // whenever this format is changed so new clients can invalidate old versions. 195 const int FastShowPickler::kVersion = 3; 196 197 scoped_ptr<Pickle> FastShowPickler::PickleAppListModelForFastShow( 198 AppListModel* model) { 199 scoped_ptr<Pickle> result(new Pickle); 200 if (!result->WriteInt(kVersion)) 201 return scoped_ptr<Pickle>(); 202 if (!result->WriteInt((int)model->top_level_item_list()->item_count())) 203 return scoped_ptr<Pickle>(); 204 for (size_t i = 0; i < model->top_level_item_list()->item_count(); ++i) { 205 if (!PickleAppListItem(result.get(), 206 model->top_level_item_list()->item_at(i))) { 207 return scoped_ptr<Pickle>(); 208 } 209 } 210 return result.Pass(); 211 } 212 213 void FastShowPickler::CopyOver(AppListModel* src, AppListModel* dest) { 214 DCHECK_EQ(0u, dest->top_level_item_list()->item_count()); 215 for (size_t i = 0; i < src->top_level_item_list()->item_count(); i++) { 216 AppListItem* src_item = src->top_level_item_list()->item_at(i); 217 scoped_ptr<AppListItem> dest_item(new AppListItem(src_item->id())); 218 CopyOverItem(src_item, dest_item.get()); 219 dest->AddItemToFolder(dest_item.Pass(), src_item->folder_id()); 220 } 221 } 222 223 scoped_ptr<AppListModel> 224 FastShowPickler::UnpickleAppListModelForFastShow(Pickle* pickle) { 225 PickleIterator it(*pickle); 226 int read_version = 0; 227 if (!it.ReadInt(&read_version)) 228 return scoped_ptr<AppListModel>(); 229 if (read_version != kVersion) 230 return scoped_ptr<AppListModel>(); 231 int app_count = 0; 232 if (!it.ReadInt(&app_count)) 233 return scoped_ptr<AppListModel>(); 234 235 scoped_ptr<AppListModel> model(new AppListModel); 236 for (int i = 0; i < app_count; ++i) { 237 scoped_ptr<AppListItem> item(UnpickleAppListItem(&it).Pass()); 238 if (!item) 239 return scoped_ptr<AppListModel>(); 240 std::string folder_id = item->folder_id(); 241 model->AddItemToFolder(item.Pass(), folder_id); 242 } 243 244 return model.Pass(); 245 } 246