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