Make Use125DSFForUIScaling flag for internal display only.
[chromium-blink-merge.git] / chrome / browser / ui / webui / options / chromeos / display_options_handler.cc
blob7ed7c828de9d8493f6f43b29c8c6d0ee3b2aa885
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.
5 #include "chrome/browser/ui/webui/options/chromeos/display_options_handler.h"
7 #include <string>
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 "chrome/grit/generated_resources.h"
21 #include "content/public/browser/user_metrics.h"
22 #include "content/public/browser/web_ui.h"
23 #include "grit/ash_strings.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"
30 using ash::DisplayManager;
32 namespace chromeos {
33 namespace options {
34 namespace {
36 DisplayManager* GetDisplayManager() {
37 return ash::Shell::GetInstance()->display_manager();
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;
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;
54 return display_id;
57 base::string16 GetColorProfileName(ui::ColorCalibrationProfile profile) {
58 switch (profile) {
59 case ui::COLOR_PROFILE_STANDARD:
60 return l10n_util::GetStringUTF16(
61 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_COLOR_PROFILE_STANDARD);
62 case ui::COLOR_PROFILE_DYNAMIC:
63 return l10n_util::GetStringUTF16(
64 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_COLOR_PROFILE_DYNAMIC);
65 case ui::COLOR_PROFILE_MOVIE:
66 return l10n_util::GetStringUTF16(
67 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_COLOR_PROFILE_MOVIE);
68 case ui::COLOR_PROFILE_READING:
69 return l10n_util::GetStringUTF16(
70 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_COLOR_PROFILE_READING);
71 case ui::NUM_COLOR_PROFILES:
72 break;
75 NOTREACHED();
76 return base::string16();
79 int GetIntOrDouble(const base::DictionaryValue* dict,
80 const std::string& field) {
81 double double_result = 0;
82 if (dict->GetDouble(field, &double_result))
83 return static_cast<int>(double_result);
85 int result = 0;
86 dict->GetInteger(field, &result);
87 return result;
90 bool GetFloat(const base::DictionaryValue* dict,
91 const std::string& field,
92 float* result) {
93 double double_result = 0;
94 if (dict->GetDouble(field, &double_result)) {
95 *result = static_cast<float>(double_result);
96 return true;
98 return false;
101 bool ConvertValueToDisplayMode(const base::DictionaryValue* dict,
102 ash::DisplayMode* mode) {
103 mode->size.set_width(GetIntOrDouble(dict, "originalWidth"));
104 mode->size.set_height(GetIntOrDouble(dict, "originalHeight"));
105 if (mode->size.IsEmpty()) {
106 LOG(ERROR) << "missing width or height.";
107 return false;
109 if (!GetFloat(dict, "refreshRate", &mode->refresh_rate)) {
110 LOG(ERROR) << "missing refreshRate.";
111 return false;
113 if (!GetFloat(dict, "scale", &mode->ui_scale)) {
114 LOG(ERROR) << "missing ui-scale.";
115 return false;
117 if (!GetFloat(dict, "deviceScaleFactor", &mode->device_scale_factor)) {
118 LOG(ERROR) << "missing deviceScaleFactor.";
119 return false;
121 return true;
124 base::DictionaryValue* ConvertDisplayModeToValue(int64 display_id,
125 const ash::DisplayMode& mode) {
126 bool is_internal = GetDisplayManager()->IsInternalDisplayId(display_id);
127 base::DictionaryValue* result = new base::DictionaryValue();
128 gfx::Size size_dip = mode.GetSizeInDIP(is_internal);
129 result->SetInteger("width", size_dip.width());
130 result->SetInteger("height", size_dip.height());
131 result->SetInteger("originalWidth", mode.size.width());
132 result->SetInteger("originalHeight", mode.size.height());
133 result->SetDouble("deviceScaleFactor", mode.device_scale_factor);
134 result->SetDouble("scale", mode.ui_scale);
135 result->SetDouble("refreshRate", mode.refresh_rate);
136 result->SetBoolean(
137 "isBest", is_internal ? (mode.ui_scale == 1.0f) : mode.native);
138 result->SetBoolean("isNative", mode.native);
139 result->SetBoolean(
140 "selected", mode.IsEquivalent(
141 GetDisplayManager()->GetActiveModeForDisplayId(display_id)));
142 return result;
145 } // namespace
147 DisplayOptionsHandler::DisplayOptionsHandler() {
148 // ash::Shell doesn't exist in Athena.
149 // See: http://crbug.com/416961
150 ash::Shell::GetInstance()->display_controller()->AddObserver(this);
153 DisplayOptionsHandler::~DisplayOptionsHandler() {
154 // ash::Shell doesn't exist in Athena.
155 ash::Shell::GetInstance()->display_controller()->RemoveObserver(this);
158 void DisplayOptionsHandler::GetLocalizedValues(
159 base::DictionaryValue* localized_strings) {
160 DCHECK(localized_strings);
161 RegisterTitle(localized_strings, "displayOptionsPage",
162 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_TAB_TITLE);
164 localized_strings->SetString(
165 "selectedDisplayTitleOptions", l10n_util::GetStringUTF16(
166 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_OPTIONS));
167 localized_strings->SetString(
168 "selectedDisplayTitleResolution", l10n_util::GetStringUTF16(
169 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_RESOLUTION));
170 localized_strings->SetString(
171 "selectedDisplayTitleOrientation", l10n_util::GetStringUTF16(
172 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_ORIENTATION));
173 localized_strings->SetString(
174 "selectedDisplayTitleOverscan", l10n_util::GetStringUTF16(
175 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_OVERSCAN));
177 localized_strings->SetString("startMirroring", l10n_util::GetStringUTF16(
178 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_START_MIRRORING));
179 localized_strings->SetString("stopMirroring", l10n_util::GetStringUTF16(
180 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_STOP_MIRRORING));
181 localized_strings->SetString("mirroringDisplay", l10n_util::GetStringUTF16(
182 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_MIRRORING_DISPLAY_NAME));
183 localized_strings->SetString("setPrimary", l10n_util::GetStringUTF16(
184 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_SET_PRIMARY));
185 localized_strings->SetString("annotateBest", l10n_util::GetStringUTF16(
186 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_RESOLUTION_ANNOTATION_BEST));
187 localized_strings->SetString("annotateNative", l10n_util::GetStringUTF16(
188 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_RESOLUTION_ANNOTATION_NATIVE));
189 localized_strings->SetString("orientation0", l10n_util::GetStringUTF16(
190 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_STANDARD_ORIENTATION));
191 localized_strings->SetString("orientation90", l10n_util::GetStringUTF16(
192 IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90));
193 localized_strings->SetString("orientation180", l10n_util::GetStringUTF16(
194 IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_180));
195 localized_strings->SetString("orientation270", l10n_util::GetStringUTF16(
196 IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_270));
197 localized_strings->SetString(
198 "startCalibratingOverscan", l10n_util::GetStringUTF16(
199 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_START_CALIBRATING_OVERSCAN));
200 localized_strings->SetString(
201 "selectedDisplayColorProfile", l10n_util::GetStringUTF16(
202 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_COLOR_PROFILE));
205 void DisplayOptionsHandler::InitializePage() {
206 DCHECK(web_ui());
207 web_ui()->CallJavascriptFunction(
208 "options.BrowserOptions.enableDisplayButton",
209 base::FundamentalValue(true));
212 void DisplayOptionsHandler::RegisterMessages() {
213 web_ui()->RegisterMessageCallback(
214 "getDisplayInfo",
215 base::Bind(&DisplayOptionsHandler::HandleDisplayInfo,
216 base::Unretained(this)));
217 web_ui()->RegisterMessageCallback(
218 "setMirroring",
219 base::Bind(&DisplayOptionsHandler::HandleMirroring,
220 base::Unretained(this)));
221 web_ui()->RegisterMessageCallback(
222 "setPrimary",
223 base::Bind(&DisplayOptionsHandler::HandleSetPrimary,
224 base::Unretained(this)));
225 web_ui()->RegisterMessageCallback(
226 "setDisplayLayout",
227 base::Bind(&DisplayOptionsHandler::HandleDisplayLayout,
228 base::Unretained(this)));
229 web_ui()->RegisterMessageCallback(
230 "setDisplayMode",
231 base::Bind(&DisplayOptionsHandler::HandleSetDisplayMode,
232 base::Unretained(this)));
233 web_ui()->RegisterMessageCallback(
234 "setOrientation",
235 base::Bind(&DisplayOptionsHandler::HandleSetOrientation,
236 base::Unretained(this)));
237 web_ui()->RegisterMessageCallback(
238 "setColorProfile",
239 base::Bind(&DisplayOptionsHandler::HandleSetColorProfile,
240 base::Unretained(this)));
243 void DisplayOptionsHandler::OnDisplayConfigurationChanging() {
246 void DisplayOptionsHandler::OnDisplayConfigurationChanged() {
247 SendAllDisplayInfo();
250 void DisplayOptionsHandler::SendAllDisplayInfo() {
251 DisplayManager* display_manager = GetDisplayManager();
253 std::vector<gfx::Display> displays;
254 for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
255 displays.push_back(display_manager->GetDisplayAt(i));
257 SendDisplayInfo(displays);
260 void DisplayOptionsHandler::SendDisplayInfo(
261 const std::vector<gfx::Display>& displays) {
262 DisplayManager* display_manager = GetDisplayManager();
263 base::FundamentalValue mirroring(display_manager->IsMirrored());
265 int64 primary_id = ash::Shell::GetScreen()->GetPrimaryDisplay().id();
266 base::ListValue js_displays;
267 for (size_t i = 0; i < displays.size(); ++i) {
268 const gfx::Display& display = displays[i];
269 const ash::DisplayInfo& display_info =
270 display_manager->GetDisplayInfo(display.id());
271 const gfx::Rect& bounds = display.bounds();
272 base::DictionaryValue* js_display = new base::DictionaryValue();
273 js_display->SetString("id", base::Int64ToString(display.id()));
274 js_display->SetInteger("x", bounds.x());
275 js_display->SetInteger("y", bounds.y());
276 js_display->SetInteger("width", bounds.width());
277 js_display->SetInteger("height", bounds.height());
278 js_display->SetString("name",
279 display_manager->GetDisplayNameForId(display.id()));
280 js_display->SetBoolean("isPrimary", display.id() == primary_id);
281 js_display->SetBoolean("isInternal", display.IsInternal());
282 js_display->SetInteger("orientation",
283 static_cast<int>(display_info.rotation()));
285 base::ListValue* js_resolutions = new base::ListValue();
286 const std::vector<ash::DisplayMode>& display_modes =
287 display_info.display_modes();
288 for (size_t i = 0; i < display_modes.size(); ++i) {
289 js_resolutions->Append(
290 ConvertDisplayModeToValue(display.id(), display_modes[i]));
292 js_display->Set("resolutions", js_resolutions);
294 js_display->SetInteger("colorProfile", display_info.color_profile());
295 base::ListValue* available_color_profiles = new base::ListValue();
296 for (size_t i = 0;
297 i < display_info.available_color_profiles().size(); ++i) {
298 base::DictionaryValue* color_profile_dict = new base::DictionaryValue();
299 ui::ColorCalibrationProfile color_profile =
300 display_info.available_color_profiles()[i];
301 color_profile_dict->SetInteger("profileId", color_profile);
302 color_profile_dict->SetString("name", GetColorProfileName(color_profile));
303 available_color_profiles->Append(color_profile_dict);
305 js_display->Set("availableColorProfiles", available_color_profiles);
306 js_displays.Append(js_display);
309 scoped_ptr<base::Value> layout_value(base::Value::CreateNullValue());
310 scoped_ptr<base::Value> offset_value(base::Value::CreateNullValue());
311 if (display_manager->GetNumDisplays() > 1) {
312 const ash::DisplayLayout layout =
313 display_manager->GetCurrentDisplayLayout();
314 layout_value.reset(new base::FundamentalValue(layout.position));
315 offset_value.reset(new base::FundamentalValue(layout.offset));
318 web_ui()->CallJavascriptFunction(
319 "options.DisplayOptions.setDisplayInfo",
320 mirroring, js_displays, *layout_value.get(), *offset_value.get());
323 void DisplayOptionsHandler::OnFadeOutForMirroringFinished(bool is_mirroring) {
324 ash::Shell::GetInstance()->display_manager()->SetMirrorMode(is_mirroring);
325 // Not necessary to start fade-in animation. DisplayConfigurator will do that.
328 void DisplayOptionsHandler::OnFadeOutForDisplayLayoutFinished(
329 int position, int offset) {
330 SetCurrentDisplayLayout(
331 ash::DisplayLayout::FromInts(position, offset));
332 ash::Shell::GetInstance()->display_configurator_animation()->
333 StartFadeInAnimation();
336 void DisplayOptionsHandler::HandleDisplayInfo(
337 const base::ListValue* unused_args) {
338 SendAllDisplayInfo();
341 void DisplayOptionsHandler::HandleMirroring(const base::ListValue* args) {
342 DCHECK(!args->empty());
343 content::RecordAction(
344 base::UserMetricsAction("Options_DisplayToggleMirroring"));
345 bool is_mirroring = false;
346 args->GetBoolean(0, &is_mirroring);
347 ash::Shell::GetInstance()->display_configurator_animation()->
348 StartFadeOutAnimation(base::Bind(
349 &DisplayOptionsHandler::OnFadeOutForMirroringFinished,
350 base::Unretained(this),
351 is_mirroring));
354 void DisplayOptionsHandler::HandleSetPrimary(const base::ListValue* args) {
355 DCHECK(!args->empty());
356 int64 display_id = GetDisplayId(args);
357 if (display_id == gfx::Display::kInvalidDisplayID)
358 return;
360 content::RecordAction(base::UserMetricsAction("Options_DisplaySetPrimary"));
361 ash::Shell::GetInstance()->display_controller()->
362 SetPrimaryDisplayId(display_id);
365 void DisplayOptionsHandler::HandleDisplayLayout(const base::ListValue* args) {
366 double layout = -1;
367 double offset = -1;
368 if (!args->GetDouble(0, &layout) || !args->GetDouble(1, &offset)) {
369 LOG(ERROR) << "Invalid parameter";
370 SendAllDisplayInfo();
371 return;
373 DCHECK_LE(ash::DisplayLayout::TOP, layout);
374 DCHECK_GE(ash::DisplayLayout::LEFT, layout);
375 content::RecordAction(base::UserMetricsAction("Options_DisplayRearrange"));
376 ash::Shell::GetInstance()->display_configurator_animation()->
377 StartFadeOutAnimation(base::Bind(
378 &DisplayOptionsHandler::OnFadeOutForDisplayLayoutFinished,
379 base::Unretained(this),
380 static_cast<int>(layout),
381 static_cast<int>(offset)));
384 void DisplayOptionsHandler::HandleSetDisplayMode(const base::ListValue* args) {
385 DCHECK(!args->empty());
387 int64 display_id = GetDisplayId(args);
388 if (display_id == gfx::Display::kInvalidDisplayID)
389 return;
391 const base::DictionaryValue* mode_data = NULL;
392 if (!args->GetDictionary(1, &mode_data)) {
393 LOG(ERROR) << "Failed to get mode data";
394 return;
397 ash::DisplayMode mode;
398 if (!ConvertValueToDisplayMode(mode_data, &mode))
399 return;
401 content::RecordAction(
402 base::UserMetricsAction("Options_DisplaySetResolution"));
403 ash::DisplayManager* display_manager = GetDisplayManager();
404 ash::DisplayMode current_mode =
405 display_manager->GetActiveModeForDisplayId(display_id);
406 if (display_manager->SetDisplayMode(display_id, mode)) {
407 ash::Shell::GetInstance()->resolution_notification_controller()->
408 PrepareNotification(
409 display_id, current_mode, mode, base::Bind(&StoreDisplayPrefs));
413 void DisplayOptionsHandler::HandleSetOrientation(const base::ListValue* args) {
414 DCHECK(!args->empty());
416 int64 display_id = GetDisplayId(args);
417 if (display_id == gfx::Display::kInvalidDisplayID)
418 return;
420 std::string rotation_value;
421 gfx::Display::Rotation new_rotation = gfx::Display::ROTATE_0;
422 if (!args->GetString(1, &rotation_value)) {
423 LOG(ERROR) << "Can't find new orientation";
424 return;
426 if (rotation_value == "90")
427 new_rotation = gfx::Display::ROTATE_90;
428 else if (rotation_value == "180")
429 new_rotation = gfx::Display::ROTATE_180;
430 else if (rotation_value == "270")
431 new_rotation = gfx::Display::ROTATE_270;
432 else if (rotation_value != "0")
433 LOG(ERROR) << "Invalid rotation: " << rotation_value << " Falls back to 0";
435 content::RecordAction(
436 base::UserMetricsAction("Options_DisplaySetOrientation"));
437 GetDisplayManager()->SetDisplayRotation(display_id, new_rotation);
440 void DisplayOptionsHandler::HandleSetColorProfile(const base::ListValue* args) {
441 DCHECK(!args->empty());
442 int64 display_id = GetDisplayId(args);
443 if (display_id == gfx::Display::kInvalidDisplayID)
444 return;
446 std::string profile_value;
447 if (!args->GetString(1, &profile_value)) {
448 LOG(ERROR) << "Invalid profile_value";
449 return;
452 int profile_id;
453 if (!base::StringToInt(profile_value, &profile_id)) {
454 LOG(ERROR) << "Invalid profile: " << profile_value;
455 return;
458 if (profile_id < ui::COLOR_PROFILE_STANDARD ||
459 profile_id > ui::COLOR_PROFILE_READING) {
460 LOG(ERROR) << "Invalid profile_id: " << profile_id;
461 return;
464 GetDisplayManager()->SetColorCalibrationProfile(
465 display_id, static_cast<ui::ColorCalibrationProfile>(profile_id));
466 SendAllDisplayInfo();
469 } // namespace options
470 } // namespace chromeos