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