Commit f95cc396 authored by vmpstr@chromium.org's avatar vmpstr@chromium.org

cc: Add base64 encoding to picture

This adds ability to serialize cc::Picture to base64 string
and to initialize the picture back from that serialization.

Review URL: https://chromiumcodereview.appspot.com/13884018

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@195361 0039d316-1c4b-4281-b951-d872f2087c98
parent 8b6bee0a
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
'resources/picture_layer_tiling_set_unittest.cc', 'resources/picture_layer_tiling_set_unittest.cc',
'resources/picture_layer_tiling_unittest.cc', 'resources/picture_layer_tiling_unittest.cc',
'resources/picture_pile_impl_unittest.cc', 'resources/picture_pile_impl_unittest.cc',
'resources/picture_unittest.cc',
'resources/prioritized_resource_unittest.cc', 'resources/prioritized_resource_unittest.cc',
'trees/quad_culler_unittest.cc', 'trees/quad_culler_unittest.cc',
'base/region_unittest.cc', 'base/region_unittest.cc',
......
...@@ -2,15 +2,18 @@ ...@@ -2,15 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "cc/resources/picture.h"
#include "base/base64.h"
#include "base/debug/trace_event.h" #include "base/debug/trace_event.h"
#include "cc/debug/rendering_stats.h" #include "cc/debug/rendering_stats.h"
#include "cc/layers/content_layer_client.h" #include "cc/layers/content_layer_client.h"
#include "cc/resources/picture.h"
#include "skia/ext/analysis_canvas.h" #include "skia/ext/analysis_canvas.h"
#include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkData.h" #include "third_party/skia/include/core/SkData.h"
#include "third_party/skia/include/core/SkDrawFilter.h" #include "third_party/skia/include/core/SkDrawFilter.h"
#include "third_party/skia/include/core/SkPaint.h" #include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkStream.h"
#include "third_party/skia/include/utils/SkPictureUtils.h" #include "third_party/skia/include/utils/SkPictureUtils.h"
#include "ui/gfx/rect_conversions.h" #include "ui/gfx/rect_conversions.h"
#include "ui/gfx/skia_util.h" #include "ui/gfx/skia_util.h"
...@@ -18,6 +21,11 @@ ...@@ -18,6 +21,11 @@
namespace { namespace {
// URI label for a lazily decoded SkPixelRef. // URI label for a lazily decoded SkPixelRef.
const char kLabelLazyDecoded[] = "lazy"; const char kLabelLazyDecoded[] = "lazy";
// Version ID; to be used in serialization.
const int kPictureVersion = 1;
// Minimum size of a decoded stream that we need.
// 4 bytes for version, 4 * 4 for each of the 2 rects.
const unsigned int kMinPictureSizeBytes = 36;
class DisableLCDTextFilter : public SkDrawFilter { class DisableLCDTextFilter : public SkDrawFilter {
public: public:
...@@ -38,10 +46,59 @@ scoped_refptr<Picture> Picture::Create(gfx::Rect layer_rect) { ...@@ -38,10 +46,59 @@ scoped_refptr<Picture> Picture::Create(gfx::Rect layer_rect) {
return make_scoped_refptr(new Picture(layer_rect)); return make_scoped_refptr(new Picture(layer_rect));
} }
scoped_refptr<Picture> Picture::CreateFromBase64String(
const std::string& encoded_string) {
bool success;
scoped_refptr<Picture> picture =
make_scoped_refptr(new Picture(encoded_string, &success));
if (!success)
picture = NULL;
return picture;
}
Picture::Picture(gfx::Rect layer_rect) Picture::Picture(gfx::Rect layer_rect)
: layer_rect_(layer_rect) { : layer_rect_(layer_rect) {
} }
Picture::Picture(const std::string& encoded_string, bool* success) {
// Decode the picture from base64.
std::string decoded;
base::Base64Decode(encoded_string, &decoded);
SkMemoryStream stream(decoded.data(), decoded.size());
if (decoded.size() < kMinPictureSizeBytes) {
*success = false;
return;
}
int version = stream.readS32();
if (version != kPictureVersion) {
*success = false;
return;
}
// First, read the layer and opaque rects.
int layer_rect_x = stream.readS32();
int layer_rect_y = stream.readS32();
int layer_rect_width = stream.readS32();
int layer_rect_height = stream.readS32();
layer_rect_ = gfx::Rect(layer_rect_x,
layer_rect_y,
layer_rect_width,
layer_rect_height);
int opaque_rect_x = stream.readS32();
int opaque_rect_y = stream.readS32();
int opaque_rect_width = stream.readS32();
int opaque_rect_height = stream.readS32();
opaque_rect_ = gfx::Rect(opaque_rect_x,
opaque_rect_y,
opaque_rect_width,
opaque_rect_height);
// Read the picture. This creates an empty picture on failure.
picture_ = skia::AdoptRef(new SkPicture(&stream, success, NULL));
}
Picture::Picture(const skia::RefPtr<SkPicture>& picture, Picture::Picture(const skia::RefPtr<SkPicture>& picture,
gfx::Rect layer_rect, gfx::Rect layer_rect,
gfx::Rect opaque_rect) : gfx::Rect opaque_rect) :
...@@ -178,4 +235,31 @@ void Picture::GatherPixelRefs(const gfx::Rect& layer_rect, ...@@ -178,4 +235,31 @@ void Picture::GatherPixelRefs(const gfx::Rect& layer_rect,
pixel_refs->unref(); pixel_refs->unref();
} }
void Picture::AsBase64String(std::string* output) const {
SkDynamicMemoryWStream stream;
// First save the version, layer_rect_ and opaque_rect.
stream.write32(kPictureVersion);
stream.write32(layer_rect_.x());
stream.write32(layer_rect_.y());
stream.write32(layer_rect_.width());
stream.write32(layer_rect_.height());
stream.write32(opaque_rect_.x());
stream.write32(opaque_rect_.y());
stream.write32(opaque_rect_.width());
stream.write32(opaque_rect_.height());
// Serialize the picture.
picture_->serialize(&stream);
// Encode the picture as base64.
size_t serialized_size = stream.bytesWritten();
scoped_ptr<char[]> serialized_picture(new char[serialized_size]);
stream.copyTo(serialized_picture.get());
base::Base64Encode(std::string(serialized_picture.get(), serialized_size),
output);
}
} // namespace cc } // namespace cc
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define CC_RESOURCES_PICTURE_H_ #define CC_RESOURCES_PICTURE_H_
#include <list> #include <list>
#include <string>
#include <vector> #include <vector>
#include "base/basictypes.h" #include "base/basictypes.h"
...@@ -30,6 +31,8 @@ class CC_EXPORT Picture ...@@ -30,6 +31,8 @@ class CC_EXPORT Picture
: public base::RefCountedThreadSafe<Picture> { : public base::RefCountedThreadSafe<Picture> {
public: public:
static scoped_refptr<Picture> Create(gfx::Rect layer_rect); static scoped_refptr<Picture> Create(gfx::Rect layer_rect);
static scoped_refptr<Picture> CreateFromBase64String(
const std::string& encoded_string);
const gfx::Rect& LayerRect() const { return layer_rect_; } const gfx::Rect& LayerRect() const { return layer_rect_; }
const gfx::Rect& OpaqueRect() const { return opaque_rect_; } const gfx::Rect& OpaqueRect() const { return opaque_rect_; }
...@@ -59,8 +62,11 @@ class CC_EXPORT Picture ...@@ -59,8 +62,11 @@ class CC_EXPORT Picture
const gfx::Rect& layer_rect, const gfx::Rect& layer_rect,
std::list<skia::LazyPixelRef*>& pixel_ref_list); std::list<skia::LazyPixelRef*>& pixel_ref_list);
void AsBase64String(std::string* output) const;
private: private:
explicit Picture(gfx::Rect layer_rect); explicit Picture(gfx::Rect layer_rect);
Picture(const std::string& encoded_string, bool* success);
// This constructor assumes SkPicture is already ref'd and transfers // This constructor assumes SkPicture is already ref'd and transfers
// ownership to this picture. // ownership to this picture.
Picture(const skia::RefPtr<SkPicture>&, Picture(const skia::RefPtr<SkPicture>&,
......
// 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 "cc/resources/picture.h"
#include "base/memory/ref_counted.h"
#include "cc/test/fake_content_layer_client.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkDevice.h"
#include "third_party/skia/include/core/SkGraphics.h"
#include "third_party/skia/include/core/SkTileGridPicture.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/skia_util.h"
namespace cc {
namespace {
void DrawPicture(unsigned char* buffer,
gfx::Rect layer_rect,
scoped_refptr<Picture> picture) {
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config,
layer_rect.width(),
layer_rect.height());
bitmap.setPixels(buffer);
SkDevice device(bitmap);
SkCanvas canvas(&device);
canvas.clipRect(gfx::RectToSkRect(layer_rect));
picture->Raster(&canvas, layer_rect, 1.0f, false);
}
TEST(PictureTest, AsBase64String) {
SkGraphics::Init();
gfx::Rect layer_rect(100, 100);
SkTileGridPicture::TileGridInfo tile_grid_info;
tile_grid_info.fTileInterval = SkISize::Make(100, 100);
tile_grid_info.fMargin.setEmpty();
tile_grid_info.fOffset.setZero();
FakeContentLayerClient content_layer_client;
SkPaint red_paint;
red_paint.setColor(SkColorSetARGB(255, 255, 0, 0));
SkPaint green_paint;
green_paint.setColor(SkColorSetARGB(255, 0, 255, 0));
// Invalid picture (not base64).
scoped_refptr<Picture> invalid_picture =
Picture::CreateFromBase64String("abc!@#$%");
EXPECT_TRUE(!invalid_picture);
// Invalid picture (empty string).
scoped_refptr<Picture> second_invalid_picture =
Picture::CreateFromBase64String("");
EXPECT_TRUE(!second_invalid_picture);
// Invalid picture (random base64 string).
scoped_refptr<Picture> third_invalid_picture =
Picture::CreateFromBase64String("ABCDABCDABCDABCDABCDABCDABCDABCDABCD"
"ABCDABCDABCDABCDABCDABCDABCDABCDABCD"
"ABCDABCDABCDABCDABCDABCDABCDABCDABCD"
"ABCDABCDABCDABCDABCDABCDABCDABCDABCD"
"ABCDABCDABCDABCDABCDABCDABCDABCDABCD"
"ABCDABCDABCDABCDABCDABCDABCDABCDABCD"
"ABCDABCDABCDABCDABCDABCDABCDABCDABCD");
EXPECT_TRUE(!third_invalid_picture);
// Single full-size rect picture.
content_layer_client.add_draw_rect(layer_rect, red_paint);
scoped_refptr<Picture> one_rect_picture = Picture::Create(layer_rect);
one_rect_picture->Record(&content_layer_client, NULL, tile_grid_info);
std::string serialized_one_rect;
one_rect_picture->AsBase64String(&serialized_one_rect);
// Reconstruct the picture.
scoped_refptr<Picture> one_rect_picture_check =
Picture::CreateFromBase64String(serialized_one_rect);
EXPECT_TRUE(!!one_rect_picture_check);
// Check for equivalence.
unsigned char one_rect_buffer[4 * 100 * 100] = {0};
DrawPicture(one_rect_buffer, layer_rect, one_rect_picture);
unsigned char one_rect_buffer_check[4 * 100 * 100] = {0};
DrawPicture(one_rect_buffer_check, layer_rect, one_rect_picture_check);
EXPECT_EQ(one_rect_picture->LayerRect(),
one_rect_picture_check->LayerRect());
EXPECT_EQ(one_rect_picture->OpaqueRect(),
one_rect_picture_check->OpaqueRect());
EXPECT_TRUE(
memcmp(one_rect_buffer, one_rect_buffer_check, 4 * 100 * 100) == 0);
// Two rect picture.
content_layer_client.add_draw_rect(gfx::Rect(25, 25, 50, 50), green_paint);
scoped_refptr<Picture> two_rect_picture = Picture::Create(layer_rect);
two_rect_picture->Record(&content_layer_client, NULL, tile_grid_info);
std::string serialized_two_rect;
two_rect_picture->AsBase64String(&serialized_two_rect);
// Reconstruct the picture.
scoped_refptr<Picture> two_rect_picture_check =
Picture::CreateFromBase64String(serialized_two_rect);
EXPECT_TRUE(!!two_rect_picture_check);
// Check for equivalence.
unsigned char two_rect_buffer[4 * 100 * 100] = {0};
DrawPicture(two_rect_buffer, layer_rect, two_rect_picture);
unsigned char two_rect_buffer_check[4 * 100 * 100] = {0};
DrawPicture(two_rect_buffer_check, layer_rect, two_rect_picture_check);
EXPECT_EQ(two_rect_picture->LayerRect(),
two_rect_picture_check->LayerRect());
EXPECT_EQ(two_rect_picture->OpaqueRect(),
two_rect_picture_check->OpaqueRect());
EXPECT_TRUE(
memcmp(two_rect_buffer, two_rect_buffer_check, 4 * 100 * 100) == 0);
}
} // namespace
} // namespace cc
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment