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