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