diff options
author | vmpstr@chromium.org <vmpstr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-20 01:14:59 +0000 |
---|---|---|
committer | vmpstr@chromium.org <vmpstr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-20 01:14:59 +0000 |
commit | f95cc396f40937df6c0ae299ef0a94bf33945ecb (patch) | |
tree | 8b03ec6c06c79f8585bda2ddbe2bf197f2749b7d /cc | |
parent | 8b6bee0aa93f3947f297644ea7947cf91b9681f6 (diff) | |
download | chromium_src-f95cc396f40937df6c0ae299ef0a94bf33945ecb.zip chromium_src-f95cc396f40937df6c0ae299ef0a94bf33945ecb.tar.gz chromium_src-f95cc396f40937df6c0ae299ef0a94bf33945ecb.tar.bz2 |
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
Diffstat (limited to 'cc')
-rw-r--r-- | cc/cc_tests.gyp | 1 | ||||
-rw-r--r-- | cc/resources/picture.cc | 86 | ||||
-rw-r--r-- | cc/resources/picture.h | 6 | ||||
-rw-r--r-- | cc/resources/picture_unittest.cc | 124 |
4 files changed, 216 insertions, 1 deletions
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp index 144cfb5..7271c61 100644 --- a/cc/cc_tests.gyp +++ b/cc/cc_tests.gyp @@ -51,6 +51,7 @@ 'resources/picture_layer_tiling_set_unittest.cc', 'resources/picture_layer_tiling_unittest.cc', 'resources/picture_pile_impl_unittest.cc', + 'resources/picture_unittest.cc', 'resources/prioritized_resource_unittest.cc', 'trees/quad_culler_unittest.cc', 'base/region_unittest.cc', diff --git a/cc/resources/picture.cc b/cc/resources/picture.cc index 2b6eca8..b54e08f 100644 --- a/cc/resources/picture.cc +++ b/cc/resources/picture.cc @@ -2,15 +2,18 @@ // 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/base64.h" #include "base/debug/trace_event.h" #include "cc/debug/rendering_stats.h" #include "cc/layers/content_layer_client.h" -#include "cc/resources/picture.h" #include "skia/ext/analysis_canvas.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkData.h" #include "third_party/skia/include/core/SkDrawFilter.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 "ui/gfx/rect_conversions.h" #include "ui/gfx/skia_util.h" @@ -18,6 +21,11 @@ namespace { // URI label for a lazily decoded SkPixelRef. 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 { public: @@ -38,10 +46,59 @@ scoped_refptr<Picture> Picture::Create(gfx::Rect 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) : 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, gfx::Rect layer_rect, gfx::Rect opaque_rect) : @@ -178,4 +235,31 @@ void Picture::GatherPixelRefs(const gfx::Rect& layer_rect, 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 diff --git a/cc/resources/picture.h b/cc/resources/picture.h index 8598fbf..a29d5af 100644 --- a/cc/resources/picture.h +++ b/cc/resources/picture.h @@ -6,6 +6,7 @@ #define CC_RESOURCES_PICTURE_H_ #include <list> +#include <string> #include <vector> #include "base/basictypes.h" @@ -30,6 +31,8 @@ class CC_EXPORT Picture : public base::RefCountedThreadSafe<Picture> { public: 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& OpaqueRect() const { return opaque_rect_; } @@ -59,8 +62,11 @@ class CC_EXPORT Picture const gfx::Rect& layer_rect, std::list<skia::LazyPixelRef*>& pixel_ref_list); + void AsBase64String(std::string* output) const; + private: explicit Picture(gfx::Rect layer_rect); + Picture(const std::string& encoded_string, bool* success); // This constructor assumes SkPicture is already ref'd and transfers // ownership to this picture. Picture(const skia::RefPtr<SkPicture>&, diff --git a/cc/resources/picture_unittest.cc b/cc/resources/picture_unittest.cc new file mode 100644 index 0000000..f20c547 --- /dev/null +++ b/cc/resources/picture_unittest.cc @@ -0,0 +1,124 @@ +// 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 |