1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ash/display/display_layout.h"
6
7#include "ash/display/display_pref_util.h"
8#include "base/json/json_value_converter.h"
9#include "base/logging.h"
10#include "base/strings/string_number_conversions.h"
11#include "base/strings/string_piece.h"
12#include "base/strings/stringprintf.h"
13#include "base/values.h"
14#include "ui/gfx/display.h"
15
16namespace ash {
17namespace  {
18
19// The maximum value for 'offset' in DisplayLayout in case of outliers.  Need
20// to change this value in case to support even larger displays.
21const int kMaxValidOffset = 10000;
22
23// Persistent key names
24const char kPositionKey[] = "position";
25const char kOffsetKey[] = "offset";
26const char kMirroredKey[] = "mirrored";
27const char kPrimaryIdKey[] = "primary-id";
28
29typedef std::map<DisplayLayout::Position, std::string> PositionToStringMap;
30
31const PositionToStringMap* GetPositionToStringMap() {
32  static const PositionToStringMap* map = CreateToStringMap(
33      DisplayLayout::TOP, "top",
34      DisplayLayout::BOTTOM, "bottom",
35      DisplayLayout::RIGHT, "right",
36      DisplayLayout::LEFT, "left");
37  return map;
38}
39
40bool GetPositionFromString(const base::StringPiece& position,
41                           DisplayLayout::Position* field) {
42  if (ReverseFind(GetPositionToStringMap(), position, field))
43    return true;
44  LOG(ERROR) << "Invalid position value:" << position;
45  return false;
46}
47
48std::string GetStringFromPosition(DisplayLayout::Position position) {
49  const PositionToStringMap* map = GetPositionToStringMap();
50  PositionToStringMap::const_iterator iter = map->find(position);
51  return iter != map->end() ? iter->second : std::string("unknown");
52}
53
54bool GetDisplayIdFromString(const base::StringPiece& position, int64* field) {
55  return base::StringToInt64(position, field);
56}
57
58}  // namespace
59
60////////////////////////////////////////////////////////////////////////////////
61// DisplayLayout
62
63// static
64DisplayLayout DisplayLayout::FromInts(int position, int offsets) {
65  return DisplayLayout(static_cast<Position>(position), offsets);
66}
67
68DisplayLayout::DisplayLayout()
69    : position(RIGHT),
70      offset(0),
71      mirrored(false),
72      primary_id(gfx::Display::kInvalidDisplayID) {
73}
74
75DisplayLayout::DisplayLayout(DisplayLayout::Position position, int offset)
76    : position(position),
77      offset(offset),
78      mirrored(false),
79      primary_id(gfx::Display::kInvalidDisplayID) {
80  DCHECK_LE(TOP, position);
81  DCHECK_GE(LEFT, position);
82
83  // Set the default value to |position| in case position is invalid.  DCHECKs
84  // above doesn't stop in Release builds.
85  if (TOP > position || LEFT < position)
86    this->position = RIGHT;
87
88  DCHECK_GE(kMaxValidOffset, abs(offset));
89}
90
91DisplayLayout DisplayLayout::Invert() const {
92  Position inverted_position = RIGHT;
93  switch (position) {
94    case TOP:
95      inverted_position = BOTTOM;
96      break;
97    case BOTTOM:
98      inverted_position = TOP;
99      break;
100    case RIGHT:
101      inverted_position = LEFT;
102      break;
103    case LEFT:
104      inverted_position = RIGHT;
105      break;
106  }
107  DisplayLayout ret = DisplayLayout(inverted_position, -offset);
108  ret.primary_id = primary_id;
109  return ret;
110}
111
112// static
113bool DisplayLayout::ConvertFromValue(const base::Value& value,
114                                     DisplayLayout* layout) {
115  base::JSONValueConverter<DisplayLayout> converter;
116  return converter.Convert(value, layout);
117}
118
119// static
120bool DisplayLayout::ConvertToValue(const DisplayLayout& layout,
121                                   base::Value* value) {
122  base::DictionaryValue* dict_value = NULL;
123  if (!value->GetAsDictionary(&dict_value) || dict_value == NULL)
124    return false;
125
126  const std::string position_str = GetStringFromPosition(layout.position);
127  dict_value->SetString(kPositionKey, position_str);
128  dict_value->SetInteger(kOffsetKey, layout.offset);
129  dict_value->SetBoolean(kMirroredKey, layout.mirrored);
130  dict_value->SetString(kPrimaryIdKey, base::Int64ToString(layout.primary_id));
131  return true;
132}
133
134std::string DisplayLayout::ToString() const {
135  const std::string position_str = GetStringFromPosition(position);
136  return base::StringPrintf(
137      "%s, %d%s",
138      position_str.c_str(), offset, mirrored ? ", mirrored" : "");
139}
140
141// static
142void DisplayLayout::RegisterJSONConverter(
143    base::JSONValueConverter<DisplayLayout>* converter) {
144  converter->RegisterCustomField<Position>(
145      kPositionKey, &DisplayLayout::position, &GetPositionFromString);
146  converter->RegisterIntField(kOffsetKey, &DisplayLayout::offset);
147  converter->RegisterBoolField(kMirroredKey, &DisplayLayout::mirrored);
148  converter->RegisterCustomField<int64>(
149      kPrimaryIdKey, &DisplayLayout::primary_id, &GetDisplayIdFromString);
150}
151
152}  // namespace ash
153