diff options
Diffstat (limited to 'components/mus/public')
5 files changed, 190 insertions, 2 deletions
diff --git a/components/mus/public/cpp/lib/property_type_converters.cc b/components/mus/public/cpp/lib/property_type_converters.cc index 2e1ff65..01c74a2 100644 --- a/components/mus/public/cpp/lib/property_type_converters.cc +++ b/components/mus/public/cpp/lib/property_type_converters.cc @@ -7,9 +7,19 @@ #include <stdint.h> #include "base/strings/utf_string_conversions.h" +#include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" +namespace { + +// Maximum allowed height or width of a bitmap, in pixels. This limit prevents +// malformed bitmap headers from causing arbitrarily large memory allocations +// for pixel data. +const int kMaxBitmapSize = 4096; + +} // namespace + namespace mojo { // static @@ -73,7 +83,7 @@ gfx::Size TypeConverter<gfx::Size, const std::vector<uint8_t>>::Convert( const std::vector<uint8_t> TypeConverter<const std::vector<uint8_t>, int32_t>::Convert( const int32_t& input) { - std::vector<uint8_t> vec(8); + std::vector<uint8_t> vec(4); vec[0] = (input >> 24) & 0xFF; vec[1] = (input >> 16) & 0xFF; vec[2] = (input >> 8) & 0xFF; @@ -118,5 +128,75 @@ TypeConverter<std::string, const std::vector<uint8_t>>::Convert( return std::string(input.begin(), input.end()); } -} // namespace mojo +// static +const std::vector<uint8_t> +TypeConverter<const std::vector<uint8_t>, SkBitmap>::Convert( + const SkBitmap& input) { + // Empty images are valid to serialize and are represented by an empty vector. + if (input.isNull()) + return std::vector<uint8_t>(); + + // Only RGBA 8888 bitmaps with premultiplied alpha are supported. + if (input.colorType() != kBGRA_8888_SkColorType || + input.alphaType() != kPremul_SkAlphaType) { + NOTREACHED(); + return std::vector<uint8_t>(); + } + + // Sanity check the bitmap size. + int width = input.width(); + int height = input.height(); + if (width < 0 || width > kMaxBitmapSize || height < 0 || + height > kMaxBitmapSize) { + NOTREACHED(); + return std::vector<uint8_t>(); + } + + // Serialize the bitmap. The size is restricted so only 2 bytes are required + // per dimension. + std::vector<uint8_t> vec(4 + input.getSize()); + vec[0] = (width >> 8) & 0xFF; + vec[1] = width & 0xFF; + vec[2] = (height >> 8) & 0xFF; + vec[3] = height & 0xFF; + if (!input.copyPixelsTo(&vec[4], input.getSize())) + return std::vector<uint8_t>(); + return vec; +} +// static +SkBitmap TypeConverter<SkBitmap, const std::vector<uint8_t>>::Convert( + const std::vector<uint8_t>& input) { + // Empty images are represented by empty vectors. + if (input.empty()) + return SkBitmap(); + + // Read and sanity check size. + int width = input[0] << 8 | input[1]; + int height = input[2] << 8 | input[3]; + if (width < 0 || width > kMaxBitmapSize || height < 0 || + height > kMaxBitmapSize) { + NOTREACHED(); + return SkBitmap(); + } + + // Try to allocate a bitmap of the appropriate size. + SkBitmap bitmap; + if (!bitmap.tryAllocPixels(SkImageInfo::Make( + width, height, kBGRA_8888_SkColorType, kPremul_SkAlphaType))) { + return SkBitmap(); + } + + // Ensure the vector contains the right amount of data. + if (input.size() != bitmap.getSize() + 4) { + NOTREACHED(); + return SkBitmap(); + } + + // Read the pixel data. + SkAutoLockPixels lock(bitmap); + memcpy(bitmap.getPixels(), &input[4], bitmap.getSize()); + return bitmap; +} + +} // namespace mojo diff --git a/components/mus/public/cpp/property_type_converters.h b/components/mus/public/cpp/property_type_converters.h index eac34a8..cec17d6 100644 --- a/components/mus/public/cpp/property_type_converters.h +++ b/components/mus/public/cpp/property_type_converters.h @@ -11,6 +11,8 @@ #include "base/strings/string16.h" #include "mojo/public/cpp/bindings/type_converter.h" +class SkBitmap; + namespace gfx { class Rect; class Size; @@ -21,6 +23,8 @@ namespace mojo { // TODO(beng): these methods serialize types used for standard properties // to vectors of bytes used by Window::SetSharedProperty(). // replace this with serialization code generated @ bindings. +// This would be especially useful for SkBitmap, which could be +// replaced with the skia.Bitmap mojom struct serialization. template <> struct TypeConverter<const std::vector<uint8_t>, gfx::Rect> { @@ -67,6 +71,17 @@ struct TypeConverter<std::string, const std::vector<uint8_t>> { static std::string Convert(const std::vector<uint8_t>& input); }; +// NOTE: These methods only serialize and deserialize the common case of RGBA +// 8888 bitmaps with premultiplied alpha. +template <> +struct TypeConverter<const std::vector<uint8_t>, SkBitmap> { + static const std::vector<uint8_t> Convert(const SkBitmap& input); +}; +template <> +struct TypeConverter<SkBitmap, const std::vector<uint8_t>> { + static SkBitmap Convert(const std::vector<uint8_t>& input); +}; + } // namespace mojo #endif // COMPONENTS_MUS_PUBLIC_CPP_PROPERTY_TYPE_CONVERTERS_H_ diff --git a/components/mus/public/cpp/tests/BUILD.gn b/components/mus/public/cpp/tests/BUILD.gn index d0c6a05..e7bf333 100644 --- a/components/mus/public/cpp/tests/BUILD.gn +++ b/components/mus/public/cpp/tests/BUILD.gn @@ -41,6 +41,7 @@ source_set("test_support") { test("mojo_view_manager_lib_unittests") { sources = [ + "property_type_converters_unittest.cc", "run_all_unittests.cc", "test_window_tree.cc", "test_window_tree.h", diff --git a/components/mus/public/cpp/tests/property_type_converters_unittest.cc b/components/mus/public/cpp/tests/property_type_converters_unittest.cc new file mode 100644 index 0000000..7726172 --- /dev/null +++ b/components/mus/public/cpp/tests/property_type_converters_unittest.cc @@ -0,0 +1,89 @@ +// Copyright 2016 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 "components/mus/public/cpp/property_type_converters.h" + +#include <stdint.h> + +#include <vector> + +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/skia_util.h" + +namespace mojo { +namespace { + +// Use a different width and height so tests can tell the values apart. +const int kBitmapWidth = 16; +const int kBitmapHeight = 32; + +// Makes a small rectangular bitmap. +SkBitmap MakeBitmap() { + SkBitmap bitmap; + bitmap.allocN32Pixels(kBitmapWidth, kBitmapHeight); + bitmap.eraseARGB(255, 11, 22, 33); + return bitmap; +} + +// Tests that an SkBitmap can be serialized. +TEST(PropertyTypeConvertersTest, SkBitmapSerialize) { + SkBitmap bitmap = MakeBitmap(); + std::vector<uint8_t> bytes = + TypeConverter<const std::vector<uint8_t>, SkBitmap>::Convert(bitmap); + + // Size should be 4 bytes of header plus size of RGBA pixels. + ASSERT_EQ(4 + bitmap.getSize(), bytes.size()); + + // Header contains width first then height. + EXPECT_EQ(0, bytes[0]); + EXPECT_EQ(kBitmapWidth, bytes[1]); + EXPECT_EQ(0, bytes[2]); + EXPECT_EQ(kBitmapHeight, bytes[3]); + + // The rest of the bytes are the image data. + EXPECT_EQ(0, memcmp(&bytes[4], bitmap.getPixels(), bitmap.getSize())); +} + +// Tests that an SkBitmap can be deserialized. +TEST(PropertyTypeConvertersTest, SkBitmapDeserialize) { + // Make a 1x2 pixel bitmap. + std::vector<uint8_t> bytes = {0, 1, 0, 2, 11, 22, 33, 44, 55, 66, 77, 88}; + SkBitmap bitmap = + TypeConverter<SkBitmap, const std::vector<uint8_t>>::Convert(bytes); + EXPECT_EQ(1, bitmap.width()); + EXPECT_EQ(2, bitmap.height()); + // The image pixels match the vector bytes. + ASSERT_EQ(8U, bitmap.getSize()); + EXPECT_EQ(0, memcmp(bitmap.getPixels(), &bytes[4], 8)); +} + +// Tests round-trip serializing and deserializing an SkBitmap. +TEST(PropertyTypeConvertersTest, SkBitmapRoundTrip) { + SkBitmap bitmap1 = MakeBitmap(); + std::vector<uint8_t> bytes = + TypeConverter<const std::vector<uint8_t>, SkBitmap>::Convert(bitmap1); + SkBitmap bitmap2 = + TypeConverter<SkBitmap, const std::vector<uint8_t>>::Convert(bytes); + EXPECT_TRUE(gfx::BitmapsAreEqual(bitmap1, bitmap2)); +} + +// Tests that an empty SkBitmap serializes to an empty vector. +TEST(PropertyTypeConvertersTest, SkBitmapSerializeEmpty) { + SkBitmap bitmap; + std::vector<uint8_t> bytes = + TypeConverter<const std::vector<uint8_t>, SkBitmap>::Convert(bitmap); + EXPECT_TRUE(bytes.empty()); +} + +// Tests that an empty vector deserializes to a null SkBitmap. +TEST(PropertyTypeConvertersTest, SkBitmapDeserializeEmpty) { + std::vector<uint8_t> bytes; + SkBitmap bitmap = + TypeConverter<SkBitmap, const std::vector<uint8_t>>::Convert(bytes); + EXPECT_TRUE(bitmap.isNull()); +} + +} // namespace +} // namespace mojo diff --git a/components/mus/public/interfaces/window_manager.mojom b/components/mus/public/interfaces/window_manager.mojom index 724c7ac..11cf1fe 100644 --- a/components/mus/public/interfaces/window_manager.mojom +++ b/components/mus/public/interfaces/window_manager.mojom @@ -32,6 +32,9 @@ interface WindowManager { const string kShowState_Property = "prop:show-state"; // The window bounds as set by user input. Type: gfx::Rect. const string kUserSetBounds_Property = "prop:user-set-bounds"; + // The window's app icon. Type: SkBitmap + const string kWindowAppIcon_Property = "prop:window-app-icon"; + // The window type. Type: mojom::WindowType const string kWindowType_Property = "prop:window-type"; // The window's title. Type: mojom::String const string kWindowTitle_Property = "prop:window-title"; |
