blob: d380e8b31a70bf990be5a7cbd85d8e17749bc99f [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/test/layer_tree_json_parser.h"
#include <stddef.h>
#include <memory>
#include <utility>
#include "base/test/values_test_util.h"
#include "base/values.h"
#include "cc/layers/layer.h"
#include "cc/layers/nine_patch_layer.h"
#include "cc/layers/picture_layer.h"
#include "cc/layers/solid_color_layer.h"
#include "cc/layers/texture_layer.h"
#include "cc/trees/layer_tree_settings.h"
namespace cc {
namespace {
scoped_refptr<Layer> ParseTreeFromValue(const base::Value& val,
ContentLayerClient* content_client) {
if (!val.is_dict())
return nullptr;
const base::Value::Dict& dict = val.GetDict();
const std::string* layer_type = dict.FindString("LayerType");
if (!layer_type)
return nullptr;
const base::Value::List* bounds_list = dict.FindList("Bounds");
if (!bounds_list)
return nullptr;
if (bounds_list->size() < 2)
return nullptr;
absl::optional<int> width = (*bounds_list)[0].GetIfInt();
absl::optional<int> height = (*bounds_list)[1].GetIfInt();
if (!width.has_value() || !height.has_value())
return nullptr;
absl::optional<bool> draws_content = dict.FindBool("DrawsContent");
if (!draws_content.has_value())
return nullptr;
absl::optional<bool> hit_testable = dict.FindBool("HitTestable");
// If we cannot load hit_testable, we may try loading the old version, since
// we do not record |hit_testable_without_draws_content| in the past, we use
// |draws_content| as the value of |hit_testable|.
if (!hit_testable.has_value()) {
hit_testable = *draws_content;
}
scoped_refptr<Layer> new_layer;
if (*layer_type == "SolidColorLayer") {
new_layer = SolidColorLayer::Create();
} else if (*layer_type == "NinePatchLayer") {
const base::Value::List* aperture_list = dict.FindList("ImageAperture");
if (!aperture_list)
return nullptr;
if (aperture_list->size() < 4)
return nullptr;
absl::optional<int> aperture_x = (*aperture_list)[0].GetIfInt();
absl::optional<int> aperture_y = (*aperture_list)[1].GetIfInt();
absl::optional<int> aperture_width = (*aperture_list)[2].GetIfInt();
absl::optional<int> aperture_height = (*aperture_list)[3].GetIfInt();
if (!(aperture_x.has_value() && aperture_y.has_value() &&
aperture_width.has_value() && aperture_height.has_value()))
return nullptr;
const base::Value::List* image_bounds_list = dict.FindList("ImageBounds");
if (!image_bounds_list)
return nullptr;
if (image_bounds_list->size() < 2)
return nullptr;
absl::optional<double> image_width = (*image_bounds_list)[0].GetIfDouble();
absl::optional<double> image_height = (*image_bounds_list)[1].GetIfDouble();
if (!(image_width.has_value() && image_height.has_value()))
return nullptr;
const base::Value::List* border_list = dict.FindList("Border");
if (!border_list)
return nullptr;
if (border_list->size() < 4)
return nullptr;
absl::optional<int> border_x = (*border_list)[0].GetIfInt();
absl::optional<int> border_y = (*border_list)[1].GetIfInt();
absl::optional<int> border_width = (*border_list)[2].GetIfInt();
absl::optional<int> border_height = (*border_list)[3].GetIfInt();
if (!(border_x.has_value() && border_y.has_value() &&
border_width.has_value() && border_height.has_value()))
return nullptr;
absl::optional<bool> fill_center = dict.FindBool("FillCenter");
if (!fill_center.has_value())
return nullptr;
scoped_refptr<NinePatchLayer> nine_patch_layer = NinePatchLayer::Create();
SkBitmap bitmap;
bitmap.allocN32Pixels(*image_width, *image_height);
bitmap.setImmutable();
nine_patch_layer->SetBitmap(bitmap);
nine_patch_layer->SetAperture(
gfx::Rect(*aperture_x, *aperture_y, *aperture_width, *aperture_height));
nine_patch_layer->SetBorder(
gfx::Rect(*border_x, *border_y, *border_width, *border_height));
nine_patch_layer->SetFillCenter(*fill_center);
new_layer = nine_patch_layer;
} else if (*layer_type == "TextureLayer") {
new_layer = TextureLayer::CreateForMailbox(nullptr);
} else if (*layer_type == "PictureLayer") {
new_layer = PictureLayer::Create(content_client);
} else { // Type "Layer" or "unknown"
new_layer = Layer::Create();
}
new_layer->SetBounds(gfx::Size(*width, *height));
new_layer->SetIsDrawable(*draws_content);
new_layer->SetHitTestable(*hit_testable);
absl::optional<double> opacity = dict.FindDouble("Opacity");
if (opacity.has_value())
new_layer->SetOpacity(*opacity);
absl::optional<bool> contents_opaque = dict.FindBool("ContentsOpaque");
if (contents_opaque.has_value())
new_layer->SetContentsOpaque(*contents_opaque);
const base::Value::List* touch_region_list = dict.FindList("TouchRegion");
if (touch_region_list) {
TouchActionRegion touch_action_region;
for (size_t i = 0; i + 3 < touch_region_list->size(); i += 4) {
absl::optional<int> rect_x = (*touch_region_list)[i + 0].GetIfInt();
absl::optional<int> rect_y = (*touch_region_list)[i + 1].GetIfInt();
absl::optional<int> rect_width = (*touch_region_list)[i + 2].GetIfInt();
absl::optional<int> rect_height = (*touch_region_list)[i + 3].GetIfInt();
if (!(rect_x.has_value() && rect_y.has_value() &&
rect_width.has_value() && rect_height.has_value()))
return nullptr;
touch_action_region.Union(
TouchAction::kNone,
gfx::Rect(*rect_x, *rect_y, *rect_width, *rect_height));
}
new_layer->SetTouchActionRegion(std::move(touch_action_region));
}
const base::Value::List* transform_list = dict.FindList("Transform");
if (!transform_list)
return nullptr;
if (transform_list->size() < 16)
return nullptr;
float transform[16];
for (int i = 0; i < 16; ++i) {
// GetDouble can implicitly convert from either double or int; however, it's
// not clear if "is_double" is sufficient for this check. Given that int is
// also a valid type that can be gotten, check it here.
if (!((*transform_list)[i].is_double() || (*transform_list)[i].is_int())) {
return nullptr;
}
transform[i] = (*transform_list)[i].GetDouble();
}
new_layer->SetTransform(gfx::Transform::ColMajorF(transform));
const base::Value::List* child_list = dict.FindList("Children");
if (!child_list)
return nullptr;
for (const auto& value : *child_list) {
new_layer->AddChild(ParseTreeFromValue(value, content_client));
}
return new_layer;
}
} // namespace
scoped_refptr<Layer> ParseTreeFromJson(std::string json,
ContentLayerClient* content_client) {
return ParseTreeFromValue(base::test::ParseJson(json), content_client);
}
} // namespace cc