blob: 424cf11418336120def1f073ad79f588bf25f3d6 [file] [log] [blame]
// 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 "ash/display/json_converter.h"
#include <memory>
#include <string>
#include "ash/display/display_pref_util.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
#include "ui/display/manager/display_layout.h"
namespace ash {
namespace {
// Persistent key names
const char kMirroredKey[] = "mirrored";
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& value,
display::DisplayLayout* layout) {
const base::DictionaryValue* dict_value = nullptr;
if (!value.GetAsDictionary(&dict_value))
return false;
int offset;
if (dict_value->GetInteger(kOffsetKey, &offset)) {
display::DisplayPlacement::Position position;
std::string position_str;
if (!dict_value->GetString(kPositionKey, &position_str))
return false;
display::DisplayPlacement::StringToPosition(position_str, &position);
layout->placement_list.emplace_back(position, offset);
}
return true;
}
// Returns true if
// The key is missing - output is left unchanged
// The key matches the type - output is updated to the value.
template <typename Getter, typename Output>
bool UpdateFromDict(const base::DictionaryValue* dict_value,
const std::string& field_name,
Getter getter,
Output* output) {
const base::Value* field = nullptr;
if (!dict_value->Get(field_name, &field)) {
LOG(WARNING) << "Missing field: " << field_name;
return true;
}
return (field->*getter)(output);
}
// No implementation here as specialization is required.
template <typename Output>
bool UpdateFromDict(const base::DictionaryValue* dict_value,
const std::string& field_name,
Output* output);
template <>
bool UpdateFromDict(const base::DictionaryValue* dict_value,
const std::string& field_name,
bool* output) {
return UpdateFromDict(dict_value, field_name, &base::Value::GetAsBoolean,
output);
}
template <>
bool UpdateFromDict(const base::DictionaryValue* dict_value,
const std::string& field_name,
int* output) {
return UpdateFromDict(dict_value, field_name, &base::Value::GetAsInteger,
output);
}
template <>
bool UpdateFromDict(const base::DictionaryValue* dict_value,
const std::string& field_name,
display::DisplayPlacement::Position* output) {
bool (base::Value::*getter)(std::string*) const = &base::Value::GetAsString;
std::string value;
if (!UpdateFromDict(dict_value, field_name, getter, &value))
return false;
return value.empty() ? true : display::DisplayPlacement::StringToPosition(
value, output);
}
template <>
bool UpdateFromDict(const base::DictionaryValue* dict_value,
const std::string& field_name,
int64_t* output) {
bool (base::Value::*getter)(std::string*) const = &base::Value::GetAsString;
std::string value;
if (!UpdateFromDict(dict_value, field_name, getter, &value))
return false;
return value.empty() ? true : base::StringToInt64(value, output);
}
template <>
bool UpdateFromDict(const base::DictionaryValue* dict_value,
const std::string& field_name,
std::vector<display::DisplayPlacement>* output) {
bool (base::Value::*getter)(const base::ListValue**) const =
&base::Value::GetAsList;
const base::ListValue* list = nullptr;
if (!UpdateFromDict(dict_value, field_name, getter, &list))
return false;
if (list == nullptr)
return true;
output->reserve(list->GetSize());
for (const auto& list_item : *list) {
const base::DictionaryValue* item_values = nullptr;
if (!list_item->GetAsDictionary(&item_values))
return false;
display::DisplayPlacement item;
if (!UpdateFromDict(item_values, kOffsetKey, &item.offset) ||
!UpdateFromDict(item_values, kPositionKey, &item.position) ||
!UpdateFromDict(item_values, kDisplayPlacementDisplayIdKey,
&item.display_id) ||
!UpdateFromDict(item_values, kDisplayPlacementParentDisplayIdKey,
&item.parent_display_id)) {
return false;
}
output->push_back(item);
}
return true;
}
} // namespace
bool JsonToDisplayLayout(const base::Value& value,
display::DisplayLayout* layout) {
layout->placement_list.clear();
const base::DictionaryValue* dict_value = nullptr;
if (!value.GetAsDictionary(&dict_value))
return false;
if (!UpdateFromDict(dict_value, kMirroredKey, &layout->mirrored) ||
!UpdateFromDict(dict_value, kDefaultUnifiedKey,
&layout->default_unified) ||
!UpdateFromDict(dict_value, kPrimaryIdKey, &layout->primary_id)) {
return false;
}
UpdateFromDict(dict_value, kDisplayPlacementKey, &layout->placement_list);
if (layout->placement_list.size() != 0u)
return true;
// For compatibility with old format.
return AddLegacyValuesFromValue(value, layout);
}
bool DisplayLayoutToJson(const display::DisplayLayout& layout,
base::Value* value) {
base::DictionaryValue* dict_value = nullptr;
if (!value->GetAsDictionary(&dict_value))
return false;
dict_value->SetBoolean(kMirroredKey, layout.mirrored);
dict_value->SetBoolean(kDefaultUnifiedKey, layout.default_unified);
dict_value->SetString(kPrimaryIdKey, base::Int64ToString(layout.primary_id));
std::unique_ptr<base::ListValue> placement_list(new base::ListValue);
for (const auto& placement : layout.placement_list) {
std::unique_ptr<base::DictionaryValue> placement_value(
new base::DictionaryValue);
placement_value->SetString(
kPositionKey,
display::DisplayPlacement::PositionToString(placement.position));
placement_value->SetInteger(kOffsetKey, placement.offset);
placement_value->SetString(kDisplayPlacementDisplayIdKey,
base::Int64ToString(placement.display_id));
placement_value->SetString(
kDisplayPlacementParentDisplayIdKey,
base::Int64ToString(placement.parent_display_id));
placement_list->Append(std::move(placement_value));
}
dict_value->Set(kDisplayPlacementKey, std::move(placement_list));
return true;
}
} // namespace ash