blob: 80b2c0f58674719e07792bf8fcd3bba5c78f81c1 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/app_list/fast_show_pickler.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/app_list/app_list_item_model.h"
#include "ui/gfx/image/image_skia_rep.h"
namespace {
using app_list::AppListItemModel;
using app_list::AppListModel;
// These have the same meaning as SkBitmap::Config. Reproduced here to insure
// against their value changing in Skia. If the order of these changes kVersion
// should be incremented.
enum ImageFormat {
NONE,
A1,
A8,
INDEX_8,
RGB_565,
ARGB_4444,
ARGB_8888,
};
bool FormatToConfig(ImageFormat format, SkBitmap::Config* out) {
switch (format) {
case NONE:
*out = SkBitmap::kNo_Config;
break;
case A1:
*out = SkBitmap::kA1_Config;
break;
case A8:
*out = SkBitmap::kA8_Config;
break;
case INDEX_8:
*out = SkBitmap::kIndex8_Config;
break;
case RGB_565:
*out = SkBitmap::kRGB_565_Config;
break;
case ARGB_4444:
*out = SkBitmap::kARGB_4444_Config;
break;
case ARGB_8888:
*out = SkBitmap::kARGB_8888_Config;
break;
default: return false;
}
return true;
}
bool ConfigToFormat(SkBitmap::Config config, ImageFormat* out) {
switch (config) {
case SkBitmap::kNo_Config:
*out = NONE;
break;
case SkBitmap::kA1_Config:
*out = A1;
break;
case SkBitmap::kA8_Config:
*out = A8;
break;
case SkBitmap::kIndex8_Config:
*out = INDEX_8;
break;
case SkBitmap::kRGB_565_Config:
*out = RGB_565;
break;
case SkBitmap::kARGB_4444_Config:
*out = ARGB_4444;
break;
case SkBitmap::kARGB_8888_Config:
*out = ARGB_8888;
break;
default: return false;
}
return true;
}
bool PickleImage(Pickle* pickle, const gfx::ImageSkia& image) {
std::vector<gfx::ImageSkiaRep> reps(image.image_reps());
pickle->WriteInt(static_cast<int>(reps.size()));
for (std::vector<gfx::ImageSkiaRep>::const_iterator it = reps.begin();
it != reps.end(); ++it) {
pickle->WriteFloat(it->scale());
pickle->WriteInt(it->pixel_width());
pickle->WriteInt(it->pixel_height());
ImageFormat format = NONE;
if (!ConfigToFormat(it->sk_bitmap().getConfig(), &format))
return false;
pickle->WriteInt(static_cast<int>(format));
int size = static_cast<int>(it->sk_bitmap().getSafeSize());
pickle->WriteInt(size);
SkBitmap bitmap = it->sk_bitmap();
SkAutoLockPixels lock(bitmap);
pickle->WriteBytes(bitmap.getPixels(), size);
}
return true;
}
bool UnpickleImage(PickleIterator* it, gfx::ImageSkia* out) {
int rep_count = 0;
if (!it->ReadInt(&rep_count))
return false;
gfx::ImageSkia result;
for (int i = 0; i < rep_count; ++i) {
float scale = 0.0f;
if (!it->ReadFloat(&scale))
return false;
int width = 0;
if (!it->ReadInt(&width))
return false;
int height = 0;
if (!it->ReadInt(&height))
return false;
int format_int = 0;
if (!it->ReadInt(&format_int))
return false;
ImageFormat format = static_cast<ImageFormat>(format_int);
SkBitmap::Config config = SkBitmap::kNo_Config;
if (!FormatToConfig(format, &config))
return false;
int size = 0;
if (!it->ReadInt(&size))
return false;
const char* pixels = NULL;
if (!it->ReadBytes(&pixels, size))
return false;
SkBitmap bitmap;
bitmap.setConfig(static_cast<SkBitmap::Config>(config), width, height);
if (!bitmap.allocPixels())
return false;
{
SkAutoLockPixels lock(bitmap);
memcpy(bitmap.getPixels(), pixels, bitmap.getSize());
}
result.AddRepresentation(gfx::ImageSkiaRep(bitmap, scale));
}
*out = result;
return true;
}
scoped_ptr<AppListItemModel> UnpickleAppListItemModel(PickleIterator* it) {
std::string id;
if (!it->ReadString(&id))
return scoped_ptr<AppListItemModel>();
scoped_ptr<AppListItemModel> result(new AppListItemModel(id));
std::string title;
if (!it->ReadString(&title))
return scoped_ptr<AppListItemModel>();
std::string full_name;
if (!it->ReadString(&full_name))
return scoped_ptr<AppListItemModel>();
result->SetTitleAndFullName(title, full_name);
bool has_shadow = false;
if (!it->ReadBool(&has_shadow))
return scoped_ptr<AppListItemModel>();
gfx::ImageSkia icon;
if (!UnpickleImage(it, &icon))
return scoped_ptr<AppListItemModel>();
result->SetIcon(icon, has_shadow);
return result.Pass();
}
bool PickleAppListItemModel(Pickle* pickle, AppListItemModel* item) {
if (!pickle->WriteString(item->id()))
return false;
if (!pickle->WriteString(item->title()))
return false;
if (!pickle->WriteString(item->full_name()))
return false;
if (!pickle->WriteBool(item->has_shadow()))
return false;
if (!PickleImage(pickle, item->icon()))
return false;
return true;
}
void CopyOverItem(AppListItemModel* src_item, AppListItemModel* dest_item) {
dest_item->SetTitleAndFullName(src_item->title(), src_item->full_name());
dest_item->SetIcon(src_item->icon(), src_item->has_shadow());
}
} // namespace
// The version of the pickle format defined here. This needs to be incremented
// whenever this format is changed so new clients can invalidate old versions.
const int FastShowPickler::kVersion = 1;
scoped_ptr<Pickle> FastShowPickler::PickleAppListModelForFastShow(
AppListModel* model) {
scoped_ptr<Pickle> result(new Pickle);
if (!result->WriteInt(kVersion))
return scoped_ptr<Pickle>();
if (!result->WriteBool(model->signed_in()))
return scoped_ptr<Pickle>();
if (!result->WriteInt((int) model->apps()->item_count()))
return scoped_ptr<Pickle>();
for (size_t i = 0; i < model->apps()->item_count(); ++i) {
if (!PickleAppListItemModel(result.get(), model->apps()->GetItemAt(i)))
return scoped_ptr<Pickle>();
}
return result.Pass();
}
void FastShowPickler::CopyOver(AppListModel* src, AppListModel* dest) {
dest->apps()->DeleteAll();
dest->SetSignedIn(src->signed_in());
for (size_t i = 0; i < src->apps()->item_count(); i++) {
AppListItemModel* src_item = src->apps()->GetItemAt(i);
AppListItemModel* dest_item = new AppListItemModel(src_item->id());
CopyOverItem(src_item, dest_item);
dest->apps()->Add(dest_item);
}
}
scoped_ptr<AppListModel>
FastShowPickler::UnpickleAppListModelForFastShow(Pickle* pickle) {
PickleIterator it(*pickle);
int read_version = 0;
if (!it.ReadInt(&read_version))
return scoped_ptr<AppListModel>();
if (read_version != kVersion)
return scoped_ptr<AppListModel>();
int app_count = 0;
bool signed_in = false;
if (!it.ReadBool(&signed_in))
return scoped_ptr<AppListModel>();
if (!it.ReadInt(&app_count))
return scoped_ptr<AppListModel>();
scoped_ptr<AppListModel> model(new AppListModel);
model->SetSignedIn(signed_in);
for (int i = 0; i < app_count; ++i) {
scoped_ptr<AppListItemModel> item(UnpickleAppListItemModel(&it).Pass());
if (!item)
return scoped_ptr<AppListModel>();
model->apps()->Add(item.release());
}
return model.Pass();
}