Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / options / chromeos / display_options_handler.cc
1 // Copyright (c) 2012 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 "chrome/browser/ui/webui/options/chromeos/display_options_handler.h"
6
7 #include <string>
8
9 #include "ash/display/display_controller.h"
10 #include "ash/display/display_manager.h"
11 #include "ash/display/output_configurator_animation.h"
12 #include "ash/display/resolution_notification_controller.h"
13 #include "ash/shell.h"
14 #include "base/bind.h"
15 #include "base/logging.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/values.h"
19 #include "chrome/browser/chromeos/display/display_preferences.h"
20 #include "chromeos/display/output_configurator.h"
21 #include "content/public/browser/web_ui.h"
22 #include "grit/ash_strings.h"
23 #include "grit/generated_resources.h"
24 #include "ui/base/l10n/l10n_util.h"
25 #include "ui/gfx/display.h"
26 #include "ui/gfx/rect.h"
27 #include "ui/gfx/screen.h"
28 #include "ui/gfx/size_conversions.h"
29
30 using ash::internal::DisplayManager;
31
32 namespace chromeos {
33 namespace options {
34 namespace {
35
36 DisplayManager* GetDisplayManager() {
37   return ash::Shell::GetInstance()->display_manager();
38 }
39
40 int64 GetDisplayId(const base::ListValue* args) {
41   // Assumes the display ID is specified as the first argument.
42   std::string id_value;
43   if (!args->GetString(0, &id_value)) {
44     LOG(ERROR) << "Can't find ID";
45     return gfx::Display::kInvalidDisplayID;
46   }
47
48   int64 display_id = gfx::Display::kInvalidDisplayID;
49   if (!base::StringToInt64(id_value, &display_id)) {
50     LOG(ERROR) << "Invalid display id: " << id_value;
51     return gfx::Display::kInvalidDisplayID;
52   }
53
54   return display_id;
55 }
56
57 bool CompareDisplayMode(ash::internal::DisplayMode d1,
58                         ash::internal::DisplayMode d2) {
59   if (d1.size.GetArea() == d2.size.GetArea())
60     return d1.refresh_rate < d2.refresh_rate;
61   return d1.size.GetArea() < d2.size.GetArea();
62 }
63
64 }  // namespace
65
66 DisplayOptionsHandler::DisplayOptionsHandler() {
67   ash::Shell::GetInstance()->display_controller()->AddObserver(this);
68 }
69
70 DisplayOptionsHandler::~DisplayOptionsHandler() {
71   ash::Shell::GetInstance()->display_controller()->RemoveObserver(this);
72 }
73
74 void DisplayOptionsHandler::GetLocalizedValues(
75     base::DictionaryValue* localized_strings) {
76   DCHECK(localized_strings);
77   RegisterTitle(localized_strings, "displayOptionsPage",
78                 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_TAB_TITLE);
79
80   localized_strings->SetString(
81       "selectedDisplayTitleOptions", l10n_util::GetStringUTF16(
82           IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_OPTIONS));
83   localized_strings->SetString(
84       "selectedDisplayTitleResolution", l10n_util::GetStringUTF16(
85           IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_RESOLUTION));
86   localized_strings->SetString(
87       "selectedDisplayTitleOrientation", l10n_util::GetStringUTF16(
88           IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_ORIENTATION));
89   localized_strings->SetString(
90       "selectedDisplayTitleOverscan", l10n_util::GetStringUTF16(
91           IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_OVERSCAN));
92
93   localized_strings->SetString("startMirroring", l10n_util::GetStringUTF16(
94       IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_START_MIRRORING));
95   localized_strings->SetString("stopMirroring", l10n_util::GetStringUTF16(
96       IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_STOP_MIRRORING));
97   localized_strings->SetString("mirroringDisplay", l10n_util::GetStringUTF16(
98       IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_MIRRORING_DISPLAY_NAME));
99   localized_strings->SetString("setPrimary", l10n_util::GetStringUTF16(
100       IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_SET_PRIMARY));
101   localized_strings->SetString("annotateBest", l10n_util::GetStringUTF16(
102       IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_RESOLUTION_ANNOTATION_BEST));
103   localized_strings->SetString("orientation0", l10n_util::GetStringUTF16(
104       IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_STANDARD_ORIENTATION));
105   localized_strings->SetString("orientation90", l10n_util::GetStringUTF16(
106       IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90));
107   localized_strings->SetString("orientation180", l10n_util::GetStringUTF16(
108       IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_180));
109   localized_strings->SetString("orientation270", l10n_util::GetStringUTF16(
110       IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_270));
111   localized_strings->SetString(
112       "startCalibratingOverscan", l10n_util::GetStringUTF16(
113           IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_START_CALIBRATING_OVERSCAN));
114 }
115
116 void DisplayOptionsHandler::InitializePage() {
117   DCHECK(web_ui());
118 }
119
120 void DisplayOptionsHandler::RegisterMessages() {
121   web_ui()->RegisterMessageCallback(
122       "getDisplayInfo",
123       base::Bind(&DisplayOptionsHandler::HandleDisplayInfo,
124                  base::Unretained(this)));
125   web_ui()->RegisterMessageCallback(
126       "setMirroring",
127       base::Bind(&DisplayOptionsHandler::HandleMirroring,
128                  base::Unretained(this)));
129   web_ui()->RegisterMessageCallback(
130       "setPrimary",
131       base::Bind(&DisplayOptionsHandler::HandleSetPrimary,
132                  base::Unretained(this)));
133   web_ui()->RegisterMessageCallback(
134       "setDisplayLayout",
135       base::Bind(&DisplayOptionsHandler::HandleDisplayLayout,
136                  base::Unretained(this)));
137   web_ui()->RegisterMessageCallback(
138       "setUIScale",
139       base::Bind(&DisplayOptionsHandler::HandleSetUIScale,
140                  base::Unretained(this)));
141   web_ui()->RegisterMessageCallback(
142       "setResolution",
143       base::Bind(&DisplayOptionsHandler::HandleSetResolution,
144                  base::Unretained(this)));
145   web_ui()->RegisterMessageCallback(
146       "setOrientation",
147       base::Bind(&DisplayOptionsHandler::HandleSetOrientation,
148                  base::Unretained(this)));
149 }
150
151 void DisplayOptionsHandler::OnDisplayConfigurationChanging() {
152 }
153
154 void DisplayOptionsHandler::OnDisplayConfigurationChanged() {
155   SendAllDisplayInfo();
156 }
157
158 void DisplayOptionsHandler::SendAllDisplayInfo() {
159   DisplayManager* display_manager = GetDisplayManager();
160
161   std::vector<gfx::Display> displays;
162   for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
163     displays.push_back(display_manager->GetDisplayAt(i));
164   }
165   SendDisplayInfo(displays);
166 }
167
168 void DisplayOptionsHandler::SendDisplayInfo(
169     const std::vector<gfx::Display>& displays) {
170   DisplayManager* display_manager = GetDisplayManager();
171   base::FundamentalValue mirroring(display_manager->IsMirrored());
172
173   int64 primary_id = ash::Shell::GetScreen()->GetPrimaryDisplay().id();
174   base::ListValue js_displays;
175   for (size_t i = 0; i < displays.size(); ++i) {
176     const gfx::Display& display = displays[i];
177     const ash::internal::DisplayInfo& display_info =
178         display_manager->GetDisplayInfo(display.id());
179     const gfx::Rect& bounds = display.bounds();
180     base::DictionaryValue* js_display = new base::DictionaryValue();
181     js_display->SetString("id", base::Int64ToString(display.id()));
182     js_display->SetInteger("x", bounds.x());
183     js_display->SetInteger("y", bounds.y());
184     js_display->SetInteger("width", bounds.width());
185     js_display->SetInteger("height", bounds.height());
186     js_display->SetString("name",
187                           display_manager->GetDisplayNameForId(display.id()));
188     js_display->SetBoolean("isPrimary", display.id() == primary_id);
189     js_display->SetBoolean("isInternal", display.IsInternal());
190     js_display->SetInteger("orientation",
191                            static_cast<int>(display_info.rotation()));
192     std::vector<ash::internal::DisplayMode> display_modes;
193     std::vector<float> ui_scales;
194     if (display.IsInternal()) {
195       ui_scales = DisplayManager::GetScalesForDisplay(display_info);
196       gfx::SizeF base_size = display_info.bounds_in_native().size();
197       base_size.Scale(1.0f / display_info.device_scale_factor());
198       if (display_info.rotation() == gfx::Display::ROTATE_90 ||
199           display_info.rotation() == gfx::Display::ROTATE_270) {
200         float tmp = base_size.width();
201         base_size.set_width(base_size.height());
202         base_size.set_height(tmp);
203       }
204       for (size_t i = 0; i < ui_scales.size(); ++i) {
205         gfx::SizeF new_size = base_size;
206         new_size.Scale(ui_scales[i]);
207         display_modes.push_back(ash::internal::DisplayMode(
208             gfx::ToFlooredSize(new_size), -1.0f, false, false));
209       }
210     } else {
211       for (size_t i = 0; i < display_info.display_modes().size(); ++i)
212         display_modes.push_back(display_info.display_modes()[i]);
213     }
214     std::sort(display_modes.begin(), display_modes.end(), CompareDisplayMode);
215
216     base::ListValue* js_resolutions = new base::ListValue();
217     gfx::Size current_size = display_info.bounds_in_native().size();
218     gfx::Insets current_overscan = display_info.GetOverscanInsetsInPixel();
219     for (size_t i = 0; i < display_modes.size(); ++i) {
220       base::DictionaryValue* resolution_info = new base::DictionaryValue();
221       gfx::Size resolution = display_modes[i].size;
222       if (!ui_scales.empty()) {
223         resolution_info->SetDouble("scale", ui_scales[i]);
224         if (ui_scales[i] == 1.0f)
225           resolution_info->SetBoolean("isBest", true);
226         resolution_info->SetBoolean(
227             "selected", display_info.configured_ui_scale() == ui_scales[i]);
228       } else {
229         // Picks the largest one as the "best", which is the last element
230         // because |display_modes| is sorted by its area.
231         if (i == display_modes.size() - 1)
232           resolution_info->SetBoolean("isBest", true);
233         resolution_info->SetBoolean("selected", (resolution == current_size));
234         resolution.Enlarge(
235             -current_overscan.width(), -current_overscan.height());
236       }
237       resolution_info->SetInteger("width", resolution.width());
238       resolution_info->SetInteger("height", resolution.height());
239       if (display_modes[i].refresh_rate > 0.0f) {
240         resolution_info->SetDouble("refreshRate",
241                                    display_modes[i].refresh_rate);
242       }
243       js_resolutions->Append(resolution_info);
244     }
245     js_display->Set("resolutions", js_resolutions);
246     js_displays.Append(js_display);
247   }
248
249   scoped_ptr<base::Value> layout_value(base::Value::CreateNullValue());
250   scoped_ptr<base::Value> offset_value(base::Value::CreateNullValue());
251   if (display_manager->GetNumDisplays() > 1) {
252     const ash::DisplayLayout layout =
253         display_manager->GetCurrentDisplayLayout();
254     layout_value.reset(new base::FundamentalValue(layout.position));
255     offset_value.reset(new base::FundamentalValue(layout.offset));
256   }
257
258   web_ui()->CallJavascriptFunction(
259       "options.DisplayOptions.setDisplayInfo",
260       mirroring, js_displays, *layout_value.get(), *offset_value.get());
261 }
262
263 void DisplayOptionsHandler::OnFadeOutForMirroringFinished(bool is_mirroring) {
264   ash::Shell::GetInstance()->display_manager()->SetMirrorMode(is_mirroring);
265   // Not necessary to start fade-in animation.  OutputConfigurator will do that.
266 }
267
268 void DisplayOptionsHandler::OnFadeOutForDisplayLayoutFinished(
269     int position, int offset) {
270   SetCurrentDisplayLayout(
271       ash::DisplayLayout::FromInts(position, offset));
272   ash::Shell::GetInstance()->output_configurator_animation()->
273       StartFadeInAnimation();
274 }
275
276 void DisplayOptionsHandler::HandleDisplayInfo(
277     const base::ListValue* unused_args) {
278   SendAllDisplayInfo();
279 }
280
281 void DisplayOptionsHandler::HandleMirroring(const base::ListValue* args) {
282   DCHECK(!args->empty());
283   bool is_mirroring = false;
284   args->GetBoolean(0, &is_mirroring);
285   ash::Shell::GetInstance()->output_configurator_animation()->
286       StartFadeOutAnimation(base::Bind(
287           &DisplayOptionsHandler::OnFadeOutForMirroringFinished,
288           base::Unretained(this),
289           is_mirroring));
290 }
291
292 void DisplayOptionsHandler::HandleSetPrimary(const base::ListValue* args) {
293   DCHECK(!args->empty());
294   int64 display_id = GetDisplayId(args);
295   if (display_id == gfx::Display::kInvalidDisplayID)
296     return;
297
298   ash::Shell::GetInstance()->display_controller()->
299       SetPrimaryDisplayId(display_id);
300 }
301
302 void DisplayOptionsHandler::HandleDisplayLayout(const base::ListValue* args) {
303   double layout = -1;
304   double offset = -1;
305   if (!args->GetDouble(0, &layout) || !args->GetDouble(1, &offset)) {
306     LOG(ERROR) << "Invalid parameter";
307     SendAllDisplayInfo();
308     return;
309   }
310   DCHECK_LE(ash::DisplayLayout::TOP, layout);
311   DCHECK_GE(ash::DisplayLayout::LEFT, layout);
312   ash::Shell::GetInstance()->output_configurator_animation()->
313       StartFadeOutAnimation(base::Bind(
314           &DisplayOptionsHandler::OnFadeOutForDisplayLayoutFinished,
315           base::Unretained(this),
316           static_cast<int>(layout),
317           static_cast<int>(offset)));
318 }
319
320 void DisplayOptionsHandler::HandleSetUIScale(const base::ListValue* args) {
321   DCHECK(!args->empty());
322
323   int64 display_id = GetDisplayId(args);
324   if (display_id == gfx::Display::kInvalidDisplayID)
325     return;
326
327   double ui_scale = 0.0f;
328   if (!args->GetDouble(1, &ui_scale) || ui_scale == 0.0f) {
329     LOG(ERROR) << "Can't find new ui_scale";
330     return;
331   }
332
333   GetDisplayManager()->SetDisplayUIScale(display_id, ui_scale);
334 }
335
336 void DisplayOptionsHandler::HandleSetResolution(const base::ListValue* args) {
337   DCHECK(!args->empty());
338   int64 display_id = GetDisplayId(args);
339   if (display_id == gfx::Display::kInvalidDisplayID)
340     return;
341
342   double width = 0.0f;
343   double height = 0.0f;
344   if (!args->GetDouble(1, &width) || width == 0.0f) {
345     LOG(ERROR) << "Can't find new width";
346     return;
347   }
348   if (!args->GetDouble(2, &height) || height == 0.0f) {
349     LOG(ERROR) << "Can't find new height";
350     return;
351   }
352
353   const ash::internal::DisplayInfo& display_info =
354       GetDisplayManager()->GetDisplayInfo(display_id);
355   gfx::Insets current_overscan = display_info.GetOverscanInsetsInPixel();
356   gfx::Size new_resolution = gfx::ToFlooredSize(gfx::SizeF(width, height));
357   new_resolution.Enlarge(current_overscan.width(), current_overscan.height());
358   gfx::Size old_resolution = display_info.bounds_in_native().size();
359   bool has_new_resolution = false;
360   bool has_old_resolution = false;
361   for (size_t i = 0; i < display_info.display_modes().size(); ++i) {
362     ash::internal::DisplayMode display_mode = display_info.display_modes()[i];
363     if (display_mode.size == new_resolution)
364       has_new_resolution = true;
365     if (display_mode.size == old_resolution)
366       has_old_resolution = true;
367   }
368   if (!has_new_resolution) {
369     LOG(ERROR) << "No new resolution " << new_resolution.ToString()
370                << " is found in the display info " << display_info.ToString();
371     return;
372   }
373   if (!has_old_resolution) {
374     LOG(ERROR) << "No old resolution " << old_resolution.ToString()
375                << " is found in the display info " << display_info.ToString();
376     return;
377   }
378
379   ash::Shell::GetInstance()->resolution_notification_controller()->
380       SetDisplayResolutionAndNotify(
381           display_id, old_resolution, new_resolution,
382           base::Bind(&StoreDisplayPrefs));
383 }
384
385 void DisplayOptionsHandler::HandleSetOrientation(const base::ListValue* args) {
386   DCHECK(!args->empty());
387
388   int64 display_id = GetDisplayId(args);
389   if (display_id == gfx::Display::kInvalidDisplayID)
390     return;
391
392   std::string rotation_value;
393   gfx::Display::Rotation new_rotation = gfx::Display::ROTATE_0;
394   if (!args->GetString(1, &rotation_value)) {
395     LOG(ERROR) << "Can't find new orientation";
396     return;
397   }
398   if (rotation_value == "90")
399     new_rotation = gfx::Display::ROTATE_90;
400   else if (rotation_value == "180")
401     new_rotation = gfx::Display::ROTATE_180;
402   else if (rotation_value == "270")
403     new_rotation = gfx::Display::ROTATE_270;
404   else if (rotation_value != "0")
405     LOG(ERROR) << "Invalid rotation: " << rotation_value << " Falls back to 0";
406
407   GetDisplayManager()->SetDisplayRotation(display_id, new_rotation);
408 }
409
410 }  // namespace options
411 }  // namespace chromeos