|  | // Copyright 2020 The Fuchsia 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 "tests/common/svg/svg_scene.h" | 
|  |  | 
|  | #include <gtest/gtest.h> | 
|  |  | 
|  | #include "scoped_svg.h" | 
|  | #include "tests/common/affine_transform_test_utils.h" | 
|  |  | 
|  | TEST(SvgSceneTest, SingleSvg) | 
|  | { | 
|  | // clang-format off | 
|  | ScopedSvg svg = ScopedSvg::parseString( | 
|  | "<svg xmlns=\"http://www.w3.org/2000/svg\">" | 
|  | "  <g style = \"fill: #FF0000\">" | 
|  | "    <rect x=\"10\" y=\"20\" width=\"100\" height=\"50\" />" | 
|  | "  </g>" | 
|  | "</svg>" | 
|  | ); | 
|  | // clang-format on | 
|  |  | 
|  | SvgScene scene; | 
|  | scene.addSvgDocument(svg.get(), 200., 300.); | 
|  |  | 
|  | double xmin, ymin, xmax, ymax; | 
|  | scene.getBounds(&xmin, &ymin, &xmax, &ymax); | 
|  | EXPECT_DOUBLE_EQ(xmin, 210.); | 
|  | EXPECT_DOUBLE_EQ(ymin, 320.); | 
|  | EXPECT_DOUBLE_EQ(xmax, 310.); | 
|  | EXPECT_DOUBLE_EQ(ymax, 370.); | 
|  |  | 
|  | const auto & svgs = scene.unique_svgs(); | 
|  | ASSERT_EQ(svgs.size(), 1u); | 
|  | EXPECT_EQ(svgs[0], svg.get()); | 
|  |  | 
|  | const auto & paths = scene.unique_paths(); | 
|  | ASSERT_EQ(paths.size(), 1u); | 
|  | EXPECT_EQ(paths[0].svg_index, 0u); | 
|  | EXPECT_EQ(paths[0].path_id, 0u); | 
|  |  | 
|  | const auto & rasters = scene.unique_rasters(); | 
|  | ASSERT_EQ(rasters.size(), 1u); | 
|  | EXPECT_EQ(rasters[0].svg_index, 0u); | 
|  | EXPECT_EQ(rasters[0].raster_id, 0u); | 
|  | EXPECT_EQ(rasters[0].path_index, 0u); | 
|  |  | 
|  | EXPECT_AFFINE_TRANSFORM_EQ(rasters[0].transform, affine_transform_make_translation(200., 300.)); | 
|  |  | 
|  | const auto & layers = scene.layers(); | 
|  | ASSERT_EQ(layers.size(), 1u); | 
|  | EXPECT_EQ(layers[0].svg_index, 0u); | 
|  | EXPECT_EQ(layers[0].layer_id, 0u); | 
|  | EXPECT_EQ(layers[0].fill_color, 0xff0000u); | 
|  | EXPECT_DOUBLE_EQ(layers[0].fill_opacity, 1.0); | 
|  | EXPECT_FALSE(layers[0].fill_even_odd); | 
|  | EXPECT_DOUBLE_EQ(layers[0].opacity, 1.0); | 
|  | ASSERT_EQ(layers[0].prints.size(), 1u); | 
|  | EXPECT_EQ(layers[0].prints[0].raster_index, 0u); | 
|  | EXPECT_EQ(layers[0].prints[0].tx, 0); | 
|  | EXPECT_EQ(layers[0].prints[0].ty, 0); | 
|  | } | 
|  |  | 
|  | TEST(SvgSceneTest, RepeatedSvg) | 
|  | { | 
|  | // Same SVG document repeated multiple times on the scene with different | 
|  | // transforms. | 
|  | // clang-format off | 
|  | ScopedSvg svg = ScopedSvg::parseString( | 
|  | "<svg xmlns=\"http://www.w3.org/2000/svg\">" | 
|  | "  <g style = \"fill: #FF0000\">" | 
|  | "    <rect x=\"10\" y=\"20\" width=\"100\" height=\"50\" />" | 
|  | "  </g>" | 
|  | "</svg>" | 
|  | ); | 
|  | // clang-format on | 
|  |  | 
|  | SvgScene scene; | 
|  |  | 
|  | const size_t kCount      = 10; | 
|  | const double kTranslateX = 20.; | 
|  | const double kTranslateY = 60.; | 
|  |  | 
|  | for (size_t nn = 0; nn < kCount; ++nn) | 
|  | scene.addSvgDocument(svg.get(), nn * kTranslateX, nn * kTranslateY); | 
|  |  | 
|  | double xmin, ymin, xmax, ymax; | 
|  | scene.getBounds(&xmin, &ymin, &xmax, &ymax); | 
|  | EXPECT_DOUBLE_EQ(xmin, 10.); | 
|  | EXPECT_DOUBLE_EQ(ymin, 20.); | 
|  | EXPECT_DOUBLE_EQ(xmax, 110. + kTranslateX * (kCount - 1)); | 
|  | EXPECT_DOUBLE_EQ(ymax, 70. + kTranslateY * (kCount - 1)); | 
|  |  | 
|  | const auto & svgs = scene.unique_svgs(); | 
|  | ASSERT_EQ(svgs.size(), 1u); | 
|  | EXPECT_EQ(svgs[0], svg.get()); | 
|  |  | 
|  | const auto & paths = scene.unique_paths(); | 
|  | ASSERT_EQ(paths.size(), 1u); | 
|  | EXPECT_EQ(paths[0].svg_index, 0u); | 
|  | EXPECT_EQ(paths[0].path_id, 0u); | 
|  |  | 
|  | const auto & rasters = scene.unique_rasters(); | 
|  | ASSERT_EQ(rasters.size(), kCount); | 
|  | for (size_t nn = 0; nn < kCount; ++nn) | 
|  | { | 
|  | std::string  text   = std::string("raster") + std::to_string(nn); | 
|  | const auto & raster = rasters[nn]; | 
|  | EXPECT_EQ(raster.svg_index, 0u) << text; | 
|  | EXPECT_EQ(raster.raster_id, 0u) << text; | 
|  | EXPECT_EQ(raster.path_index, 0u) << text; | 
|  |  | 
|  | EXPECT_AFFINE_TRANSFORM_EQ( | 
|  | raster.transform, | 
|  | affine_transform_make_translation(nn * kTranslateX, nn * kTranslateY)); | 
|  | } | 
|  |  | 
|  | const auto & layers = scene.layers(); | 
|  | ASSERT_EQ(layers.size(), kCount); | 
|  | for (size_t nn = 0; nn < kCount; ++nn) | 
|  | { | 
|  | std::string  text  = std::string("layer") + std::to_string(nn); | 
|  | const auto & layer = layers[nn]; | 
|  |  | 
|  | EXPECT_EQ(layer.svg_index, 0u) << text; | 
|  | EXPECT_EQ(layer.layer_id, nn) << text; | 
|  | EXPECT_EQ(layer.fill_color, 0xff0000u) << text; | 
|  | EXPECT_DOUBLE_EQ(layer.fill_opacity, 1.0) << text; | 
|  | EXPECT_FALSE(layer.fill_even_odd) << text; | 
|  | EXPECT_DOUBLE_EQ(layer.opacity, 1.0) << text; | 
|  | ASSERT_EQ(layer.prints.size(), 1u) << text; | 
|  | EXPECT_EQ(layer.prints[0].raster_index, nn) << text; | 
|  | EXPECT_EQ(layer.prints[0].tx, 0) << text; | 
|  | EXPECT_EQ(layer.prints[0].ty, 0) << text; | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(SvgSceneTest, MultipleSvgs) | 
|  | { | 
|  | // Same SVG document repeated multiple times on the scene with different | 
|  | // transforms. | 
|  |  | 
|  | // clang-format off | 
|  | ScopedSvg svg1 = ScopedSvg::parseString( | 
|  | "<svg xmlns=\"http://www.w3.org/2000/svg\">" | 
|  | "  <g style = \"fill: #FF0000\">" | 
|  | "    <rect x=\"10\" y=\"20\" width=\"100\" height=\"50\" />" | 
|  | "  </g>" | 
|  | "</svg>" | 
|  | ); | 
|  | ScopedSvg svg2 = ScopedSvg::parseString( | 
|  | "<svg xmlns=\"http://www.w3.org/2000/svg\">" | 
|  | "  <g style = \"fill: #0000FF\">" | 
|  | "    <path d=\"M 10 20 l 100 25 l -100 25 Z\" />" | 
|  | "  </g>" | 
|  | "</svg>" | 
|  | ); | 
|  | // clang-format on | 
|  |  | 
|  | const size_t kGridWidth  = 8; | 
|  | const size_t kGridHeight = 4; | 
|  | const size_t kCount      = kGridWidth * kGridHeight; | 
|  | const double kTranslateX = 20.; | 
|  | const double kTranslateY = 60.; | 
|  |  | 
|  | SvgScene scene; | 
|  | for (size_t nn = 0; nn < kCount; ++nn) | 
|  | { | 
|  | // Organize items in a grid, alternating each instance between svg1 and | 
|  | // svg2, so it looks like: | 
|  | // | 
|  | //    X O X O X O | 
|  | //    O X O X O X | 
|  | //    X O X O X O | 
|  | //    ... | 
|  | size_t grid_y = nn / kGridWidth; | 
|  | size_t grid_x = nn % kGridWidth; | 
|  |  | 
|  | const svg * item = (nn & 1) ? svg2.get() : svg1.get(); | 
|  |  | 
|  | scene.addSvgDocument( | 
|  | item, | 
|  | affine_transform_make_translation(grid_x * kTranslateX, grid_y * kTranslateY)); | 
|  | } | 
|  |  | 
|  | double xmin, ymin, xmax, ymax; | 
|  | scene.getBounds(&xmin, &ymin, &xmax, &ymax); | 
|  | EXPECT_DOUBLE_EQ(xmin, 10.); | 
|  | EXPECT_DOUBLE_EQ(ymin, 20.); | 
|  | EXPECT_DOUBLE_EQ(xmax, 110. + kTranslateX * (kGridWidth - 1)); | 
|  | EXPECT_DOUBLE_EQ(ymax, 70. + kTranslateY * (kGridHeight - 1)); | 
|  |  | 
|  | const auto & svgs = scene.unique_svgs(); | 
|  | ASSERT_EQ(svgs.size(), 2u); | 
|  | EXPECT_EQ(svgs[0], svg1.get()); | 
|  | EXPECT_EQ(svgs[1], svg2.get()); | 
|  |  | 
|  | const auto & paths = scene.unique_paths(); | 
|  | ASSERT_EQ(paths.size(), 2u); | 
|  | EXPECT_EQ(paths[0].svg_index, 0u); | 
|  | EXPECT_EQ(paths[0].path_id, 0u); | 
|  | EXPECT_EQ(paths[1].svg_index, 1u); | 
|  | EXPECT_EQ(paths[1].path_id, 0u); | 
|  |  | 
|  | const auto & rasters = scene.unique_rasters(); | 
|  | ASSERT_EQ(rasters.size(), kCount); | 
|  | for (size_t nn = 0; nn < kCount; ++nn) | 
|  | { | 
|  | std::string text   = std::string("raster") + std::to_string(nn); | 
|  | size_t      grid_x = nn % kGridWidth; | 
|  | size_t      grid_y = nn / kGridWidth; | 
|  |  | 
|  | const auto & raster = rasters[nn]; | 
|  | EXPECT_EQ(raster.svg_index, (nn & 1u)) << text; | 
|  | EXPECT_EQ(raster.raster_id, 0u) << text; | 
|  | EXPECT_EQ(raster.path_index, (nn & 1u)) << text; | 
|  |  | 
|  | EXPECT_AFFINE_TRANSFORM_EQ( | 
|  | raster.transform, | 
|  | affine_transform_make_translation(grid_x * kTranslateX, grid_y * kTranslateY)); | 
|  | } | 
|  |  | 
|  | const auto & layers = scene.layers(); | 
|  | ASSERT_EQ(layers.size(), kCount); | 
|  | for (size_t nn = 0; nn < kCount; ++nn) | 
|  | { | 
|  | std::string  text  = std::string("layer") + std::to_string(nn); | 
|  | const auto & layer = layers[nn]; | 
|  |  | 
|  | EXPECT_EQ(layer.svg_index, (nn & 1u)) << text; | 
|  | EXPECT_EQ(layer.layer_id, nn) << text; | 
|  | EXPECT_EQ(layer.fill_color, (nn & 1u) ? 0x000000ffu : 0xff0000u) << text; | 
|  | EXPECT_DOUBLE_EQ(layer.fill_opacity, 1.0) << text; | 
|  | EXPECT_FALSE(layer.fill_even_odd) << text; | 
|  | EXPECT_DOUBLE_EQ(layer.opacity, 1.0) << text; | 
|  | ASSERT_EQ(layer.prints.size(), 1u) << text; | 
|  | EXPECT_EQ(layer.prints[0].raster_index, nn) << text; | 
|  | EXPECT_EQ(layer.prints[0].tx, 0) << text; | 
|  | EXPECT_EQ(layer.prints[0].ty, 0) << text; | 
|  | } | 
|  | } |