// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/display/manager/json_converter.h"
#include <memory>
#include <string>
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
#include "ui/display/display_layout.h"
namespace display {
namespace {
// Persistent key names
const char kDefaultUnifiedKey[] = "default_unified";
const char kPrimaryIdKey[] = "primary-id";
const char kDisplayPlacementKey[] = "display_placement";
// DisplayPlacement key names
const char kPositionKey[] = "position";
const char kOffsetKey[] = "offset";
const char kDisplayPlacementDisplayIdKey[] = "display_id";
const char kDisplayPlacementParentDisplayIdKey[] = "parent_display_id";
bool AddLegacyValuesFromValue(const base::Value::Dict& dict,
DisplayLayout* layout) {
std::optional<int> optional_offset = dict.FindInt(kOffsetKey);
if (optional_offset) {
DisplayPlacement::Position position;
const std::string* position_str = dict.FindString(kPositionKey);
if (!position_str)
return false;
DisplayPlacement::StringToPosition(*position_str, &position);
layout->placement_list.emplace_back(position, *optional_offset);
}
return true;
}
// Returns true if
// The key is missing - output is left unchanged
// The key matches the type - output is updated to the dict.
bool UpdateFromDict(const base::Value::Dict& dict,
const std::string& field_name,
bool* output) {
const base::Value* field = dict.Find(field_name);
if (!field) {
LOG(WARNING) << "Missing field: " << field_name;
return true;
}
std::optional<bool> field_value = field->GetIfBool();
if (!field_value)
return false;
*output = *field_value;
return true;
}
// Returns true if
// The key is missing - output is left unchanged
// The key matches the type - output is updated to the dict.
bool UpdateFromDict(const base::Value::Dict& dict,
const std::string& field_name,
int* output) {
const base::Value* field = dict.Find(field_name);
if (!field) {
LOG(WARNING) << "Missing field: " << field_name;
return true;
}
std::optional<int> field_value = field->GetIfInt();
if (!field_value)
return false;
*output = *field_value;
return true;
}
// Returns true if
// The key is missing - output is left unchanged
// The key matches the type - output is updated to the dict.
bool UpdateFromDict(const base::Value::Dict& dict,
const std::string& field_name,
DisplayPlacement::Position* output) {
const base::Value* field = dict.Find(field_name);
if (!field) {
LOG(WARNING) << "Missing field: " << field_name;
return true;
}
const std::string* field_value = field->GetIfString();
if (!field_value)
return false;
return field_value->empty()
? true
: DisplayPlacement::StringToPosition(*field_value, output);
}
// Returns true if
// The key is missing - output is left unchanged
// The key matches the type - output is updated to the dict.
bool UpdateFromDict(const base::Value::Dict& dict,
const std::string& field_name,
int64_t* output) {
const base::Value* field = dict.Find(field_name);
if (!field) {
LOG(WARNING) << "Missing field: " << field_name;
return true;
}
const std::string* field_value = field->GetIfString();
if (!field_value)
return false;
return field_value->empty() ? true
: base::StringToInt64(*field_value, output);
}
// Returns true if
// The key is missing - output is left unchanged
// The key matches the type - output is updated to the dict.
bool UpdateFromDict(const base::Value::Dict& dict,
const std::string& field_name,
std::vector<DisplayPlacement>* output) {
const base::Value* field = dict.Find(field_name);
if (!field) {
LOG(WARNING) << "Missing field: " << field_name;
return true;
}
if (!field->is_list())
return false;
const base::Value::List& list = field->GetList();
output->reserve(list.size());
for (const base::Value& list_item : list) {
if (!list_item.is_dict())
return false;
DisplayPlacement item;
const base::Value::Dict& item_dict = list_item.GetDict();
if (!UpdateFromDict(item_dict, kOffsetKey, &item.offset) ||
!UpdateFromDict(item_dict, kPositionKey, &item.position) ||
!UpdateFromDict(item_dict, kDisplayPlacementDisplayIdKey,
&item.display_id) ||
!UpdateFromDict(item_dict, kDisplayPlacementParentDisplayIdKey,
&item.parent_display_id)) {
return false;
}
output->push_back(item);
}
return true;
}
} // namespace
bool JsonToDisplayLayout(const base::Value& value, DisplayLayout* layout) {
if (!value.is_dict())
return false;
return JsonToDisplayLayout(value.GetDict(), layout);
}
bool JsonToDisplayLayout(const base::Value::Dict& dict, DisplayLayout* layout) {
layout->placement_list.clear();
if (!UpdateFromDict(dict, kDefaultUnifiedKey, &layout->default_unified) ||
!UpdateFromDict(dict, kPrimaryIdKey, &layout->primary_id)) {
return false;
}
UpdateFromDict(dict, kDisplayPlacementKey, &layout->placement_list);
if (layout->placement_list.size() != 0u)
return true;
// For compatibility with old format.
return AddLegacyValuesFromValue(dict, layout);
}
void DisplayLayoutToJson(const DisplayLayout& layout, base::Value::Dict& dict) {
dict.Set(kDefaultUnifiedKey, layout.default_unified);
dict.Set(kPrimaryIdKey, base::NumberToString(layout.primary_id));
base::Value::List placement_list;
for (const auto& placement : layout.placement_list) {
base::Value::Dict placement_value;
placement_value.Set(kPositionKey,
DisplayPlacement::PositionToString(placement.position));
placement_value.Set(kOffsetKey, placement.offset);
placement_value.Set(kDisplayPlacementDisplayIdKey,
base::NumberToString(placement.display_id));
placement_value.Set(kDisplayPlacementParentDisplayIdKey,
base::NumberToString(placement.parent_display_id));
placement_list.Append(std::move(placement_value));
}
dict.Set(kDisplayPlacementKey, std::move(placement_list));
}
} // namespace display