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
11namespace {
12
13using app_list::AppListItem;
14using 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.
19enum ImageFormat {
20  NONE,
21  A8,
22  INDEX_8,
23  RGB_565,
24  ARGB_4444,
25  ARGB_8888,
26};
27
28bool 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
53bool 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
78bool 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
99bool 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
149scoped_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
172bool 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
186void 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.
195const int FastShowPickler::kVersion = 3;
196
197scoped_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
213void 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
223scoped_ptr<AppListModel>
224FastShowPickler::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